@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/kernel-worker.js
CHANGED
|
@@ -2796,8 +2796,8 @@ var OpfsFs = class {
|
|
|
2796
2796
|
const [entry] = await this.meta.get([target]);
|
|
2797
2797
|
if (entry?.fifo || entry?.socket) throw fsError("ENXIO", path);
|
|
2798
2798
|
const kept = fresh3 ? cached : this.files.get(target);
|
|
2799
|
-
const
|
|
2800
|
-
return [
|
|
2799
|
+
const usable3 = kept && performance.now() - (this.found.get(kept) ?? -CHECK_MS) < CHECK_MS;
|
|
2800
|
+
return [usable3 ? kept : void 0, target, true];
|
|
2801
2801
|
}
|
|
2802
2802
|
async writeAt(handle, target, path, offset, bytes) {
|
|
2803
2803
|
await this.counting(target);
|
|
@@ -5580,14 +5580,21 @@ async function ownerOnly(g, op, path, follow2) {
|
|
|
5580
5580
|
return walked;
|
|
5581
5581
|
}
|
|
5582
5582
|
async function chmodMode(g, path, mode) {
|
|
5583
|
-
const
|
|
5584
|
-
|
|
5583
|
+
const walked = await need(g, "chmod", path, 0, { follow: true });
|
|
5584
|
+
const perm = walked.perm;
|
|
5585
|
+
const st = await g.fs.stat(walked.path).catch(() => void 0);
|
|
5586
|
+
if (!st?.fat && perm && g.cred.euid !== 0 && perm.uid !== g.cred.euid) {
|
|
5587
|
+
if (await present(g.fs, walked.path, false)) deny(g, "chmod", path, "EPERM");
|
|
5588
|
+
}
|
|
5589
|
+
if (!g.dac.enforcing || !perm || g.cred.euid === 0 || st?.fat || inGroup(g.cred, perm.gid)) {
|
|
5590
|
+
return mode;
|
|
5591
|
+
}
|
|
5585
5592
|
return mode & ~S_ISGID3;
|
|
5586
5593
|
}
|
|
5587
5594
|
function heldChmodMode(g, path, st, mode) {
|
|
5588
5595
|
const perm = permOf(st);
|
|
5589
|
-
if (g.cred.euid !== 0 && perm.uid !== g.cred.euid) deny(g, "fchmod", path, "EPERM");
|
|
5590
|
-
if (!g.dac.enforcing || g.cred.euid === 0 || inGroup(g.cred, perm.gid)) return mode;
|
|
5596
|
+
if (!st.fat && g.cred.euid !== 0 && perm.uid !== g.cred.euid) deny(g, "fchmod", path, "EPERM");
|
|
5597
|
+
if (!g.dac.enforcing || g.cred.euid === 0 || st.fat || inGroup(g.cred, perm.gid)) return mode;
|
|
5591
5598
|
return mode & ~S_ISGID3;
|
|
5592
5599
|
}
|
|
5593
5600
|
function heldRetimable(g, path, st, now) {
|
|
@@ -8767,7 +8774,7 @@ function satisfies(version, range2) {
|
|
|
8767
8774
|
}
|
|
8768
8775
|
|
|
8769
8776
|
// src/version.ts
|
|
8770
|
-
var KERNEL_VERSION = true ? "1.
|
|
8777
|
+
var KERNEL_VERSION = true ? "1.177.0" : "0.0.0-dev";
|
|
8771
8778
|
var OS_RELEASE = "6.0.0-slicc";
|
|
8772
8779
|
function procVersion() {
|
|
8773
8780
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -13912,10 +13919,15 @@ var DriverConnection = class _DriverConnection {
|
|
|
13912
13919
|
// src/mount/mount-fs.ts
|
|
13913
13920
|
var S_ISGID4 = 1024;
|
|
13914
13921
|
var ID = /^\d{1,10}$/;
|
|
13922
|
+
var MASK = /^0*[0-7]{1,4}$/;
|
|
13915
13923
|
var MAX_ID2 = 4294967294;
|
|
13916
13924
|
function idOption(value2) {
|
|
13917
13925
|
return value2 === void 0 ? 0 : Number(value2);
|
|
13918
13926
|
}
|
|
13927
|
+
function maskOption(value2) {
|
|
13928
|
+
if (value2 === void 0) return void 0;
|
|
13929
|
+
return Number.parseInt(value2, 8) & 511;
|
|
13930
|
+
}
|
|
13919
13931
|
function checkIds(options) {
|
|
13920
13932
|
for (const key of ["uid", "gid"]) {
|
|
13921
13933
|
const value2 = options[key];
|
|
@@ -13923,6 +13935,27 @@ function checkIds(options) {
|
|
|
13923
13935
|
if (!ID.test(value2) || Number(value2) > MAX_ID2) throw errnoError("EINVAL", `${key}=${value2}`);
|
|
13924
13936
|
}
|
|
13925
13937
|
}
|
|
13938
|
+
function checkMasks(options) {
|
|
13939
|
+
for (const key of ["umask", "fmask", "dmask"]) {
|
|
13940
|
+
const value2 = options[key];
|
|
13941
|
+
if (value2 === void 0) continue;
|
|
13942
|
+
if (!MASK.test(value2) || Number.parseInt(value2, 8) > 511) {
|
|
13943
|
+
throw errnoError("EINVAL", `${key}=${value2}`);
|
|
13944
|
+
}
|
|
13945
|
+
}
|
|
13946
|
+
}
|
|
13947
|
+
function modeOf(attr2, mount) {
|
|
13948
|
+
const type = attr2.kind === "directory" ? 16384 : attr2.kind === "symlink" ? 40960 : attr2.kind === "fifo" ? 4096 : 32768;
|
|
13949
|
+
const fallback = type | (attr2.kind === "directory" ? 493 : attr2.kind === "symlink" ? 511 : 420);
|
|
13950
|
+
if (mount.caps.owners) return attr2.mode ?? fallback;
|
|
13951
|
+
const umask = maskOption(mount.options.umask);
|
|
13952
|
+
const fmask = maskOption(mount.options.fmask) ?? umask;
|
|
13953
|
+
const dmask = maskOption(mount.options.dmask) ?? umask;
|
|
13954
|
+
const mask = attr2.kind === "directory" ? dmask : fmask;
|
|
13955
|
+
if (mask === void 0) return attr2.mode ?? fallback;
|
|
13956
|
+
const base = attr2.kind === "directory" || attr2.kind === "symlink" ? 511 : 438;
|
|
13957
|
+
return type | base & ~mask;
|
|
13958
|
+
}
|
|
13926
13959
|
var MAX_LINKS7 = 40;
|
|
13927
13960
|
var STALE_RETRIES = 3;
|
|
13928
13961
|
var SETTLE_ROUNDS = 4;
|
|
@@ -14189,14 +14222,13 @@ function inodeless(mount, attr2) {
|
|
|
14189
14222
|
}
|
|
14190
14223
|
function statOf2(attr2, path, mount) {
|
|
14191
14224
|
const mtime = new Date(attr2.mtime);
|
|
14192
|
-
const fallback = attr2.kind === "directory" ? 16877 : attr2.kind === "symlink" ? 41471 : attr2.kind === "fifo" ? 4516 : 33188;
|
|
14193
14225
|
return {
|
|
14194
14226
|
isFile: attr2.kind === "file",
|
|
14195
14227
|
isDirectory: attr2.kind === "directory",
|
|
14196
14228
|
isSymbolicLink: attr2.kind === "symlink",
|
|
14197
14229
|
...attr2.kind === "fifo" ? { isFifo: true } : {},
|
|
14198
14230
|
size: attr2.size,
|
|
14199
|
-
mode: attr2
|
|
14231
|
+
mode: modeOf(attr2, mount),
|
|
14200
14232
|
mtime,
|
|
14201
14233
|
atime: attr2.atime === void 0 ? mtime : new Date(attr2.atime),
|
|
14202
14234
|
ctime: mtime,
|
|
@@ -14210,7 +14242,8 @@ function statOf2(attr2, path, mount) {
|
|
|
14210
14242
|
...attr2.etag !== void 0 ? { version: attr2.etag } : {},
|
|
14211
14243
|
...mount.owners ? {
|
|
14212
14244
|
uid: (mount.caps.owners ? attr2.uid : void 0) ?? idOption(mount.options.uid),
|
|
14213
|
-
gid: (mount.caps.owners ? attr2.gid : void 0) ?? idOption(mount.options.gid)
|
|
14245
|
+
gid: (mount.caps.owners ? attr2.gid : void 0) ?? idOption(mount.options.gid),
|
|
14246
|
+
...!mount.caps.owners && !mount.caps.chmod && (mount.options.umask !== void 0 || mount.options.fmask !== void 0 || mount.options.dmask !== void 0) ? { fat: true } : {}
|
|
14214
14247
|
} : {}
|
|
14215
14248
|
};
|
|
14216
14249
|
}
|
|
@@ -14317,6 +14350,7 @@ var MountTable = class {
|
|
|
14317
14350
|
if (!st.isDirectory) throw errnoError("ENOTDIR", target);
|
|
14318
14351
|
const options = { ...spec.options };
|
|
14319
14352
|
if (this.deps.owners) checkIds(options);
|
|
14353
|
+
checkMasks(options);
|
|
14320
14354
|
const maxFile = options.maxfile !== void 0 ? parseSize(options.maxfile) : void 0;
|
|
14321
14355
|
const opened2 = await this.deps.open(spec.type, { ...spec, target, options });
|
|
14322
14356
|
let mounted;
|
|
@@ -18767,8 +18801,8 @@ var SCRUB_IDLE_MS = 50;
|
|
|
18767
18801
|
var SCRUB_NONBLOCK_MAX = 64 * 1024;
|
|
18768
18802
|
var encoder5 = new TextEncoder();
|
|
18769
18803
|
function scrubberOf(secrets, sameLength = false) {
|
|
18770
|
-
const
|
|
18771
|
-
return
|
|
18804
|
+
const usable3 = secrets.filter((s) => encoder5.encode(s.value).length >= MIN_VALUE);
|
|
18805
|
+
return usable3.length > 0 ? compile(usable3, { idleMs: SCRUB_IDLE_MS, sameLength }) : void 0;
|
|
18772
18806
|
}
|
|
18773
18807
|
async function writeAll2(file, bytes) {
|
|
18774
18808
|
const write = file.write;
|
|
@@ -19407,6 +19441,56 @@ var SealedBroker = class {
|
|
|
19407
19441
|
}
|
|
19408
19442
|
};
|
|
19409
19443
|
|
|
19444
|
+
// src/sudo-timestamp.ts
|
|
19445
|
+
var TIMESTAMPS_MAX = 64;
|
|
19446
|
+
var MINUTE_MS2 = 6e4;
|
|
19447
|
+
function timestampKey(owner, type) {
|
|
19448
|
+
if (type === "global") return "global";
|
|
19449
|
+
const { terminal, parent } = owner;
|
|
19450
|
+
if (type === "tty" && terminal) {
|
|
19451
|
+
return JSON.stringify(["tty", terminal.tty, terminal.sid, terminal.started]);
|
|
19452
|
+
}
|
|
19453
|
+
return parent ? JSON.stringify(["ppid", parent.pid, parent.started]) : void 0;
|
|
19454
|
+
}
|
|
19455
|
+
var Timestamps = class {
|
|
19456
|
+
users = /* @__PURE__ */ new Map();
|
|
19457
|
+
now;
|
|
19458
|
+
constructor(now) {
|
|
19459
|
+
this.now = now;
|
|
19460
|
+
}
|
|
19461
|
+
current(owner, policy) {
|
|
19462
|
+
if (policy.minutes === 0) return false;
|
|
19463
|
+
const key = timestampKey(owner, policy.type);
|
|
19464
|
+
const at = key === void 0 ? void 0 : this.users.get(owner.uid)?.get(key);
|
|
19465
|
+
if (at === void 0) return false;
|
|
19466
|
+
const now = this.now();
|
|
19467
|
+
return at <= now && (policy.minutes < 0 || now - at < policy.minutes * MINUTE_MS2);
|
|
19468
|
+
}
|
|
19469
|
+
stamp(owner, policy) {
|
|
19470
|
+
const key = policy.minutes === 0 ? void 0 : timestampKey(owner, policy.type);
|
|
19471
|
+
if (key === void 0) return false;
|
|
19472
|
+
const now = this.now();
|
|
19473
|
+
const records = this.users.get(owner.uid) ?? /* @__PURE__ */ new Map();
|
|
19474
|
+
this.users.set(owner.uid, records);
|
|
19475
|
+
records.delete(key);
|
|
19476
|
+
records.set(key, now);
|
|
19477
|
+
for (const [old, at] of records) {
|
|
19478
|
+
const stale = policy.minutes > 0 && (at > now || now - at >= policy.minutes * MINUTE_MS2);
|
|
19479
|
+
if (stale || records.size > TIMESTAMPS_MAX) records.delete(old);
|
|
19480
|
+
}
|
|
19481
|
+
return true;
|
|
19482
|
+
}
|
|
19483
|
+
invalidate(owner, type) {
|
|
19484
|
+
const key = timestampKey(owner, type);
|
|
19485
|
+
const records = this.users.get(owner.uid);
|
|
19486
|
+
if (key !== void 0) records?.delete(key);
|
|
19487
|
+
if (records?.size === 0) this.users.delete(owner.uid);
|
|
19488
|
+
}
|
|
19489
|
+
remove(uid) {
|
|
19490
|
+
this.users.delete(uid);
|
|
19491
|
+
}
|
|
19492
|
+
};
|
|
19493
|
+
|
|
19410
19494
|
// src/sudoers.ts
|
|
19411
19495
|
var SUDOERS = "/etc/sudoers";
|
|
19412
19496
|
var SUDOERS_D = "/etc/sudoers.d";
|
|
@@ -19426,6 +19510,8 @@ var SHOWN_MAX = 60;
|
|
|
19426
19510
|
var KERNEL_SYNTAX = "[NOPASSWD] <user|%group|ALL> [(<target>)] [Cwd <dir>] [Stdin none] Cmnd <command\u2026|*>";
|
|
19427
19511
|
var SUDOERS_SYNTAX = "<user|%group|ALL> ALL=[(<target>[,<target>\u2026])] [NOPASSWD:] <command\u2026|ALL>";
|
|
19428
19512
|
var EXPECTED = `expected '${KERNEL_SYNTAX}' or '${SUDOERS_SYNTAX}'`;
|
|
19513
|
+
var TIMESTAMP_TIMEOUT = 5;
|
|
19514
|
+
var TIMESTAMP_TYPE = "tty";
|
|
19429
19515
|
function hasControl(text) {
|
|
19430
19516
|
return CONTROL.test(text);
|
|
19431
19517
|
}
|
|
@@ -19708,9 +19794,6 @@ function directiveError(text) {
|
|
|
19708
19794
|
return /^#-?\d+\s+\S+\s*=/.test(text) ? "a #uid isn't supported: name the user, %group or ALL" : null;
|
|
19709
19795
|
}
|
|
19710
19796
|
const first = /^\S+/.exec(text)?.[0] ?? "";
|
|
19711
|
-
if (/^Defaults([:@>!]|$)/.test(first)) {
|
|
19712
|
-
return "Defaults aren't supported: the kernel's sudo has no settings, so this changes nothing";
|
|
19713
|
-
}
|
|
19714
19797
|
if (/^[A-Z][A-Za-z]*_Alias$/.test(first)) {
|
|
19715
19798
|
return "aliases aren't supported: name the users, targets and commands in each line";
|
|
19716
19799
|
}
|
|
@@ -19736,9 +19819,90 @@ function kernelLine(m, line, file) {
|
|
|
19736
19819
|
)
|
|
19737
19820
|
};
|
|
19738
19821
|
}
|
|
19822
|
+
var DEFAULTS = /^Defaults(?=[:@>!\s]|$)/;
|
|
19823
|
+
var DEFAULTS_ONLY = `Defaults aren't supported, except timestamp_timeout and timestamp_type for everyone, a user or a %group: this line changes nothing`;
|
|
19824
|
+
var PARAM = /^(!*)([A-Za-z_]+)(?:\s*([-+]?=)\s*(.*))?$/s;
|
|
19825
|
+
var MINUTES = /^[-+]?(?:\d+(?:\.\d*)?|\.\d+)$/;
|
|
19826
|
+
var TYPES = ["tty", "ppid", "global"];
|
|
19827
|
+
function defaultsValue(raw2) {
|
|
19828
|
+
const quoted = /^"(.*)"$/s.exec(raw2);
|
|
19829
|
+
return quoted ? quoted[1] : raw2;
|
|
19830
|
+
}
|
|
19831
|
+
function timeoutParam({ text, negated, op, value: value2 }) {
|
|
19832
|
+
if (negated && op === void 0) return { timestampTimeout: 0 };
|
|
19833
|
+
if (negated || op !== "=" || !MINUTES.test(value2) || !Number.isFinite(Number(value2))) {
|
|
19834
|
+
return `timestamp_timeout takes minutes, such as =5 or =2.5 (0 always asks, below 0 never expires), not ${shown(text)}`;
|
|
19835
|
+
}
|
|
19836
|
+
return { timestampTimeout: Number(value2) };
|
|
19837
|
+
}
|
|
19838
|
+
function typeParam({ text, negated, op, value: value2 }) {
|
|
19839
|
+
if (!negated && op === "=" && TYPES.includes(value2)) {
|
|
19840
|
+
return { timestampType: value2 };
|
|
19841
|
+
}
|
|
19842
|
+
if (value2 === "kernel") return "timestamp_type=kernel isn't supported: use tty, ppid or global";
|
|
19843
|
+
return `timestamp_type takes =tty, =ppid or =global, not ${shown(text)}`;
|
|
19844
|
+
}
|
|
19845
|
+
function defaultsParam(param) {
|
|
19846
|
+
const m = PARAM.exec(param);
|
|
19847
|
+
if (!m) return DEFAULTS_ONLY;
|
|
19848
|
+
const [, bangs = "", name2, op, raw2 = ""] = m;
|
|
19849
|
+
const read = { text: param, negated: bangs !== "", op, value: defaultsValue(raw2.trim()) };
|
|
19850
|
+
const settings = name2 === "timestamp_timeout" ? timeoutParam(read) : name2 === "timestamp_type" ? typeParam(read) : DEFAULTS_ONLY;
|
|
19851
|
+
if (typeof settings === "string") return settings;
|
|
19852
|
+
const value2 = settings.timestampTimeout ?? settings.timestampType;
|
|
19853
|
+
return { settings, text: `${name2}=${value2}` };
|
|
19854
|
+
}
|
|
19855
|
+
function defaultsWho(binding) {
|
|
19856
|
+
if (binding === "") return null;
|
|
19857
|
+
if (!binding.startsWith(":")) return DEFAULTS_ONLY;
|
|
19858
|
+
const who = binding.slice(1).split(",");
|
|
19859
|
+
for (const name2 of who) {
|
|
19860
|
+
if (!validWho(name2))
|
|
19861
|
+
return `expected users, %groups or ALL after Defaults:, not ${shown(name2)}`;
|
|
19862
|
+
}
|
|
19863
|
+
return who;
|
|
19864
|
+
}
|
|
19865
|
+
function defaultsLine(text) {
|
|
19866
|
+
const m = /^Defaults(\S*)(?:\s+(.*))?$/s.exec(text);
|
|
19867
|
+
const who = defaultsWho(m?.[1] ?? "");
|
|
19868
|
+
if (typeof who === "string") return { error: who };
|
|
19869
|
+
const list = (m?.[2] ?? "").trim();
|
|
19870
|
+
if (list === "")
|
|
19871
|
+
return {
|
|
19872
|
+
error: "expected timestamp_timeout=<minutes> or timestamp_type=<type> after Defaults"
|
|
19873
|
+
};
|
|
19874
|
+
const settings = {};
|
|
19875
|
+
const params = [];
|
|
19876
|
+
for (const param of list.split(",")) {
|
|
19877
|
+
const read = defaultsParam(param.trim());
|
|
19878
|
+
if (typeof read === "string") return { error: read };
|
|
19879
|
+
Object.assign(settings, read.settings);
|
|
19880
|
+
params.push(read.text);
|
|
19881
|
+
}
|
|
19882
|
+
return { defaults: { who, settings, params } };
|
|
19883
|
+
}
|
|
19884
|
+
function resolveDefaults(entries, applies) {
|
|
19885
|
+
const everyone = entries.filter((e) => e.who === null);
|
|
19886
|
+
const mine = entries.filter((e) => e.who?.some(applies));
|
|
19887
|
+
const matching = [...everyone, ...mine];
|
|
19888
|
+
const settings = Object.assign({}, ...matching.map((e) => e.settings));
|
|
19889
|
+
return {
|
|
19890
|
+
timestampTimeout: settings.timestampTimeout ?? TIMESTAMP_TIMEOUT,
|
|
19891
|
+
timestampType: settings.timestampType ?? TIMESTAMP_TYPE,
|
|
19892
|
+
matching
|
|
19893
|
+
};
|
|
19894
|
+
}
|
|
19895
|
+
function defaultsText(entries) {
|
|
19896
|
+
const all = resolveDefaults(entries, () => false);
|
|
19897
|
+
return [
|
|
19898
|
+
`Defaults timestamp_timeout=${all.timestampTimeout}, timestamp_type=${all.timestampType}`,
|
|
19899
|
+
...entries.filter((e) => e.who !== null).map((e) => `Defaults:${e.who.join(",")} ${e.params.join(", ")}`)
|
|
19900
|
+
];
|
|
19901
|
+
}
|
|
19739
19902
|
function parseLine(line, file) {
|
|
19740
19903
|
const text = line.trim();
|
|
19741
19904
|
if (text === "") return null;
|
|
19905
|
+
if (DEFAULTS.test(text)) return defaultsLine(text);
|
|
19742
19906
|
const directive = directiveError(text);
|
|
19743
19907
|
if (directive !== void 0) return directive === null ? null : { error: directive };
|
|
19744
19908
|
const kernel = KERNEL_FORM.exec(text);
|
|
@@ -19750,14 +19914,16 @@ function parseLine(line, file) {
|
|
|
19750
19914
|
}
|
|
19751
19915
|
function parsePolicy(text, file) {
|
|
19752
19916
|
const rules = [];
|
|
19917
|
+
const defaults2 = [];
|
|
19753
19918
|
const errors = [];
|
|
19754
19919
|
for (const [n, line] of text.split("\n").entries()) {
|
|
19755
19920
|
const parsed2 = parseLine(line, file);
|
|
19756
19921
|
if (parsed2 === null) continue;
|
|
19757
19922
|
if ("error" in parsed2) errors.push({ line: n + 1, message: parsed2.error });
|
|
19923
|
+
else if ("defaults" in parsed2) defaults2.push(parsed2.defaults);
|
|
19758
19924
|
else rules.push(...parsed2.rules);
|
|
19759
19925
|
}
|
|
19760
|
-
return { rules, errors };
|
|
19926
|
+
return { rules, defaults: defaults2, errors };
|
|
19761
19927
|
}
|
|
19762
19928
|
|
|
19763
19929
|
// src/sudo.ts
|
|
@@ -19765,7 +19931,14 @@ var SECURE_PATH = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
|
|
19765
19931
|
var DEFAULT_SUDOERS = "%sudo Cmnd *\n";
|
|
19766
19932
|
var SUDO_TIMEOUT_MS = 3e5;
|
|
19767
19933
|
var TERM = /^[A-Za-z0-9._+-]+$/;
|
|
19768
|
-
var USAGE =
|
|
19934
|
+
var USAGE = [
|
|
19935
|
+
"usage: sudo -K | -k",
|
|
19936
|
+
" sudo -v [-kn] [-u user]",
|
|
19937
|
+
" sudo -l [-kn]",
|
|
19938
|
+
" sudo [-kn] [-u user] [--] command [args...]"
|
|
19939
|
+
].join("\n");
|
|
19940
|
+
var DONE = { done: true };
|
|
19941
|
+
var NOT_STAMPED = "sudo: approved, but the approver didn't say a person decided, so no timestamp was recorded";
|
|
19769
19942
|
var DENIED2 = "sudo: approval denied";
|
|
19770
19943
|
var DENIAL_MAX = 500;
|
|
19771
19944
|
var ABORTED = /* @__PURE__ */ Symbol("aborted");
|
|
@@ -19839,6 +20012,17 @@ async function answerOf(approve, req, signal) {
|
|
|
19839
20012
|
return cut === void 0 ? "deny" : await cut;
|
|
19840
20013
|
}
|
|
19841
20014
|
}
|
|
20015
|
+
function approvalOf(answer2) {
|
|
20016
|
+
if (answer2 === "once" || answer2 === "always") return { answer: answer2, person: false };
|
|
20017
|
+
if (typeof answer2 !== "object" || answer2 === null) return void 0;
|
|
20018
|
+
try {
|
|
20019
|
+
const { answer: kind, timestamp } = answer2;
|
|
20020
|
+
if (kind !== "once" && kind !== "always" || timestamp !== true) return void 0;
|
|
20021
|
+
return { answer: kind, person: true };
|
|
20022
|
+
} catch {
|
|
20023
|
+
return void 0;
|
|
20024
|
+
}
|
|
20025
|
+
}
|
|
19842
20026
|
function recordedCommand(argv) {
|
|
19843
20027
|
const [path = "", ...args] = argv;
|
|
19844
20028
|
return commandText({ path, args: args.map((a) => [a]) });
|
|
@@ -19848,6 +20032,9 @@ function flags(parsed2, arg, next3) {
|
|
|
19848
20032
|
const flag = arg[j];
|
|
19849
20033
|
if (flag === "n") parsed2.nonInteractive = true;
|
|
19850
20034
|
else if (flag === "l") parsed2.list = true;
|
|
20035
|
+
else if (flag === "v") parsed2.validate = true;
|
|
20036
|
+
else if (flag === "k") parsed2.reset = true;
|
|
20037
|
+
else if (flag === "K") parsed2.removeAll = true;
|
|
19851
20038
|
else if (flag !== "u") return `sudo: invalid option -- '${flag}'
|
|
19852
20039
|
${USAGE}`;
|
|
19853
20040
|
else {
|
|
@@ -19861,7 +20048,15 @@ ${USAGE}`;
|
|
|
19861
20048
|
return 0;
|
|
19862
20049
|
}
|
|
19863
20050
|
function parseArgs(args) {
|
|
19864
|
-
const parsed2 = {
|
|
20051
|
+
const parsed2 = {
|
|
20052
|
+
list: false,
|
|
20053
|
+
nonInteractive: false,
|
|
20054
|
+
validate: false,
|
|
20055
|
+
reset: false,
|
|
20056
|
+
removeAll: false,
|
|
20057
|
+
user: "root",
|
|
20058
|
+
command: []
|
|
20059
|
+
};
|
|
19865
20060
|
let i = 0;
|
|
19866
20061
|
for (; i < args.length; i++) {
|
|
19867
20062
|
const arg = args[i];
|
|
@@ -19875,8 +20070,17 @@ function parseArgs(args) {
|
|
|
19875
20070
|
i += used2;
|
|
19876
20071
|
}
|
|
19877
20072
|
parsed2.command = args.slice(i);
|
|
19878
|
-
|
|
19879
|
-
|
|
20073
|
+
return usable(parsed2) ? parsed2 : USAGE;
|
|
20074
|
+
}
|
|
20075
|
+
function usable(parsed2) {
|
|
20076
|
+
const command = parsed2.command.length > 0;
|
|
20077
|
+
const modes = [parsed2.list, parsed2.validate, parsed2.removeAll].filter(Boolean).length;
|
|
20078
|
+
if (modes > 1 || parsed2.removeAll && parsed2.reset) return false;
|
|
20079
|
+
if (modes === 1) return !command;
|
|
20080
|
+
return command || parsed2.reset;
|
|
20081
|
+
}
|
|
20082
|
+
function policyOf(settings) {
|
|
20083
|
+
return { type: settings.timestampType, minutes: settings.timestampTimeout };
|
|
19880
20084
|
}
|
|
19881
20085
|
function described(rule) {
|
|
19882
20086
|
const cmnd = rule.cmnd === "*" ? "ALL" : commandText(rule.cmnd);
|
|
@@ -19888,9 +20092,11 @@ var Sudo = class {
|
|
|
19888
20092
|
o;
|
|
19889
20093
|
warned = /* @__PURE__ */ new Set();
|
|
19890
20094
|
pending = /* @__PURE__ */ new Set();
|
|
20095
|
+
timestamps;
|
|
19891
20096
|
next = 0;
|
|
19892
20097
|
constructor(options) {
|
|
19893
20098
|
this.o = options;
|
|
20099
|
+
this.timestamps = new Timestamps(options.now ?? (() => performance.now()));
|
|
19894
20100
|
}
|
|
19895
20101
|
warn(message3) {
|
|
19896
20102
|
if (this.warned.has(message3)) return;
|
|
@@ -19977,8 +20183,8 @@ var Sudo = class {
|
|
|
19977
20183
|
const code = err.code;
|
|
19978
20184
|
return skipped(`it can't be read (${typeof code === "string" ? code : "error"})`);
|
|
19979
20185
|
}
|
|
19980
|
-
const { rules, errors } = parsePolicy(text, path);
|
|
19981
|
-
return { path, rules, problems: errors, ok: true };
|
|
20186
|
+
const { rules, defaults: defaults2, errors } = parsePolicy(text, path);
|
|
20187
|
+
return { path, rules, defaults: defaults2, problems: errors, ok: true };
|
|
19982
20188
|
}
|
|
19983
20189
|
async policy() {
|
|
19984
20190
|
const files = [await this.policyFile(SUDOERS)];
|
|
@@ -20007,7 +20213,10 @@ var Sudo = class {
|
|
|
20007
20213
|
}
|
|
20008
20214
|
}
|
|
20009
20215
|
if (!detailed && skipped > 0) await caller.report?.(skippedNotice(skipped));
|
|
20010
|
-
return
|
|
20216
|
+
return {
|
|
20217
|
+
rules: files.flatMap((f) => f.rules),
|
|
20218
|
+
defaults: files.flatMap((f) => f.defaults ?? [])
|
|
20219
|
+
};
|
|
20011
20220
|
}
|
|
20012
20221
|
async check(cred, call) {
|
|
20013
20222
|
const lines2 = [];
|
|
@@ -20020,17 +20229,26 @@ var Sudo = class {
|
|
|
20020
20229
|
if (read && problems.length === 0) lines2.push([1, `${path}: parsed OK`]);
|
|
20021
20230
|
if (problems.length > 0) ok4 = false;
|
|
20022
20231
|
};
|
|
20232
|
+
const values = (defaults2) => {
|
|
20233
|
+
for (const line of defaultsText(defaults2)) lines2.push([1, line]);
|
|
20234
|
+
};
|
|
20023
20235
|
if (call.files !== void 0) {
|
|
20236
|
+
const defaults2 = [];
|
|
20024
20237
|
for (const { name: name2, text } of call.files) {
|
|
20025
|
-
|
|
20238
|
+
const parsed2 = parsePolicy(text);
|
|
20239
|
+
defaults2.push(...parsed2.defaults);
|
|
20240
|
+
report({ path: name2, rules: [], problems: parsed2.errors, ok: true });
|
|
20026
20241
|
}
|
|
20242
|
+
if (defaults2.length > 0) values(defaults2);
|
|
20027
20243
|
return { lines: lines2, ok: ok4 };
|
|
20028
20244
|
}
|
|
20029
20245
|
if (this.o.mode === "enforce" && cred.euid !== 0) {
|
|
20030
20246
|
const hint = "check the policy as root (sudo visudo -c), or a file with visudo -c -f <file>";
|
|
20031
20247
|
return { lines: [[2, `visudo: ${SUDOERS}: Permission denied: ${hint}`]], ok: false };
|
|
20032
20248
|
}
|
|
20033
|
-
|
|
20249
|
+
const files = await this.policy();
|
|
20250
|
+
for (const file of files) report(file);
|
|
20251
|
+
values(files.flatMap((f) => f.defaults ?? []));
|
|
20034
20252
|
return { lines: lines2, ok: ok4 };
|
|
20035
20253
|
}
|
|
20036
20254
|
async groupIds() {
|
|
@@ -20039,9 +20257,9 @@ var Sudo = class {
|
|
|
20039
20257
|
async applies(caller, cred) {
|
|
20040
20258
|
const gids = await this.groupIds();
|
|
20041
20259
|
const mine = /* @__PURE__ */ new Set([cred.rgid, cred.egid, ...cred.groups]);
|
|
20042
|
-
return (
|
|
20043
|
-
if (
|
|
20044
|
-
const gid =
|
|
20260
|
+
return (who) => {
|
|
20261
|
+
if (who === "ALL" || who === caller.name) return true;
|
|
20262
|
+
const gid = who.startsWith("%") ? gids.get(who.slice(1)) : void 0;
|
|
20045
20263
|
return gid !== void 0 && mine.has(gid);
|
|
20046
20264
|
};
|
|
20047
20265
|
}
|
|
@@ -20086,18 +20304,40 @@ var Sudo = class {
|
|
|
20086
20304
|
const mode = this.o.mode;
|
|
20087
20305
|
if (parsed2.list) return { list: `sudo: users are '${mode}': commands run as the caller
|
|
20088
20306
|
` };
|
|
20089
|
-
return { run: parsed2.command };
|
|
20307
|
+
return parsed2.command.length > 0 ? { run: parsed2.command } : DONE;
|
|
20090
20308
|
}
|
|
20091
20309
|
const { cred } = caller;
|
|
20092
20310
|
const policy = await this.policyRules(caller);
|
|
20093
20311
|
const self = await this.o.users.lookup(cred.ruid);
|
|
20094
20312
|
if (!self) return failed2("EPERM", `sudo: uid ${cred.ruid} is not in the passwd database`);
|
|
20313
|
+
const owner = {
|
|
20314
|
+
uid: cred.ruid,
|
|
20315
|
+
terminal: caller.terminal,
|
|
20316
|
+
parent: caller.parent
|
|
20317
|
+
};
|
|
20318
|
+
const applies = await this.applies(self, cred);
|
|
20319
|
+
const settings = resolveDefaults(policy.defaults, applies);
|
|
20320
|
+
if (parsed2.removeAll) {
|
|
20321
|
+
this.timestamps.remove(owner.uid);
|
|
20322
|
+
return DONE;
|
|
20323
|
+
}
|
|
20324
|
+
if (parsed2.reset && !parsed2.validate && !parsed2.list && parsed2.command.length === 0) {
|
|
20325
|
+
this.timestamps.invalidate(owner, settings.timestampType);
|
|
20326
|
+
return DONE;
|
|
20327
|
+
}
|
|
20095
20328
|
const target = await this.lookup(parsed2.user);
|
|
20096
20329
|
if (!target) return failed2("ENOENT", `sudo: unknown user ${parsed2.user}`);
|
|
20097
20330
|
const root = cred.euid === 0;
|
|
20098
|
-
const rules = root ? [] : policy;
|
|
20099
|
-
const
|
|
20100
|
-
if (parsed2.list) return this.listed(self, root,
|
|
20331
|
+
const rules = root ? [] : policy.rules;
|
|
20332
|
+
const mine = rules.filter((rule) => applies(rule.who));
|
|
20333
|
+
if (parsed2.list) return this.listed(self, root, mine, settings.matching);
|
|
20334
|
+
const session = { caller, self, target, owner, policy: policyOf(settings), parsed: parsed2, signal };
|
|
20335
|
+
if (parsed2.validate) return this.validate(session, root, mine, call.cwd);
|
|
20336
|
+
return this.command(session, root, mine, call);
|
|
20337
|
+
}
|
|
20338
|
+
async command(s, root, mine, call) {
|
|
20339
|
+
const { caller, self, target, parsed: parsed2 } = s;
|
|
20340
|
+
const { cred } = caller;
|
|
20101
20341
|
const [word = "", ...args] = parsed2.command;
|
|
20102
20342
|
const cwd = await this.canonical(call.cwd);
|
|
20103
20343
|
if (cwd === void 0 || !await this.reachable(cred, cwd)) {
|
|
@@ -20111,8 +20351,8 @@ var Sudo = class {
|
|
|
20111
20351
|
const untrusted2 = await this.untrusted(path, cwd, word);
|
|
20112
20352
|
if (untrusted2) return untrusted2;
|
|
20113
20353
|
const argv = [path, ...args];
|
|
20114
|
-
const matching =
|
|
20115
|
-
(rule) =>
|
|
20354
|
+
const matching = mine.filter(
|
|
20355
|
+
(rule) => (rule.target === "ALL" || rule.target === target.name) && (rule.cwd === void 0 || rule.cwd === cwd) && stdinMatches(rule, caller.stdin) && commandMatches(rule.cmnd, argv)
|
|
20116
20356
|
);
|
|
20117
20357
|
const grant = () => this.grant(self, target, cred, parsed2.command, path, cwd, call.term);
|
|
20118
20358
|
if (root || matching.some((rule) => rule.nopasswd)) return grant();
|
|
@@ -20123,23 +20363,67 @@ var Sudo = class {
|
|
|
20123
20363
|
`sudo: ${self.name} is not allowed to run ${quoted} as ${target.name}`
|
|
20124
20364
|
);
|
|
20125
20365
|
}
|
|
20366
|
+
if (!parsed2.reset && this.timestamps.current(s.owner, s.policy)) {
|
|
20367
|
+
this.timestamps.stamp(s.owner, s.policy);
|
|
20368
|
+
this.logged(s, cwd, argv);
|
|
20369
|
+
return grant();
|
|
20370
|
+
}
|
|
20126
20371
|
if (parsed2.nonInteractive) return failed2("EPERM", "sudo: a password is required");
|
|
20127
|
-
|
|
20128
|
-
|
|
20129
|
-
|
|
20130
|
-
const answer2 = await this.ask(caller, self, target, parsed2.command, path, cwd, signal);
|
|
20131
|
-
if (typeof answer2 !== "string") return answer2;
|
|
20372
|
+
return this.pendingFor(cred.ruid, async () => {
|
|
20373
|
+
const answer2 = await this.ask(s, { argv: parsed2.command, path, cwd });
|
|
20374
|
+
if ("error" in answer2) return answer2;
|
|
20132
20375
|
if (await this.canonical(call.cwd) !== cwd || !await this.reachable(cred, cwd)) {
|
|
20133
20376
|
return failed2("EACCES", `sudo: ${call.cwd} changed while the request waited`);
|
|
20134
20377
|
}
|
|
20135
20378
|
const changed = await this.untrusted(path, cwd, word);
|
|
20136
20379
|
if (changed) return changed;
|
|
20137
|
-
|
|
20138
|
-
|
|
20380
|
+
const result = answer2.answer === "once" ? grant() : await this.always(self, target, cwd, argv, recordable(cwd, parsed2.command), grant);
|
|
20381
|
+
if (!("error" in result)) this.stamped(s, answer2);
|
|
20382
|
+
return result;
|
|
20383
|
+
});
|
|
20384
|
+
}
|
|
20385
|
+
async validate(s, root, mine, dir) {
|
|
20386
|
+
const { self, parsed: parsed2 } = s;
|
|
20387
|
+
if (root) return DONE;
|
|
20388
|
+
if (mine.length === 0) {
|
|
20389
|
+
return failed2("EPERM", `Sorry, user ${self.name} may not run sudo on ${this.o.hostname}.`);
|
|
20390
|
+
}
|
|
20391
|
+
if (mine.every((rule) => rule.nopasswd)) return DONE;
|
|
20392
|
+
if (!parsed2.reset && this.timestamps.current(s.owner, s.policy)) {
|
|
20393
|
+
this.timestamps.stamp(s.owner, s.policy);
|
|
20394
|
+
return DONE;
|
|
20395
|
+
}
|
|
20396
|
+
if (parsed2.nonInteractive) return failed2("EPERM", "sudo: a password is required");
|
|
20397
|
+
const cwd = await this.canonical(dir) ?? normalizePath(dir);
|
|
20398
|
+
return this.pendingFor(s.caller.cred.ruid, async () => {
|
|
20399
|
+
const answer2 = await this.ask(s, { argv: [], path: "", cwd, validate: true });
|
|
20400
|
+
if ("error" in answer2) return answer2;
|
|
20401
|
+
if (!answer2.person) await s.caller.report?.(NOT_STAMPED);
|
|
20402
|
+
this.stamped(s, answer2);
|
|
20403
|
+
return DONE;
|
|
20404
|
+
});
|
|
20405
|
+
}
|
|
20406
|
+
async pendingFor(uid, work) {
|
|
20407
|
+
if (this.pending.has(uid)) return failed2("EBUSY", "sudo: another request is pending");
|
|
20408
|
+
this.pending.add(uid);
|
|
20409
|
+
try {
|
|
20410
|
+
return await work();
|
|
20139
20411
|
} finally {
|
|
20140
|
-
this.pending.delete(
|
|
20412
|
+
this.pending.delete(uid);
|
|
20141
20413
|
}
|
|
20142
20414
|
}
|
|
20415
|
+
stamped(s, answer2) {
|
|
20416
|
+
if (answer2.person && !s.parsed.reset) this.timestamps.stamp(s.owner, s.policy);
|
|
20417
|
+
}
|
|
20418
|
+
logged(s, cwd, argv) {
|
|
20419
|
+
const { caller, self, target, owner, policy } = s;
|
|
20420
|
+
const type = policy.type === "tty" && !owner.terminal ? "ppid" : policy.type;
|
|
20421
|
+
const tty = owner.terminal?.tty ?? caller.tty ?? "unknown";
|
|
20422
|
+
const command = argv.map(quoteWord).join(" ");
|
|
20423
|
+
(this.o.warn ?? console.warn)(
|
|
20424
|
+
`sudo: ${self.name} : TTY=${tty} ; PWD=${quoteWord(cwd)} ; USER=${target.name} ; TIMESTAMP=${type} ; COMMAND=${command}`
|
|
20425
|
+
);
|
|
20426
|
+
}
|
|
20143
20427
|
async always(self, target, cwd, argv, shown2, grant) {
|
|
20144
20428
|
if (!shown2 || !recordable(cwd, argv)) return { ...grant(), notice: RAN_ONCE };
|
|
20145
20429
|
if (!await this.remember(self, target, cwd, argv)) {
|
|
@@ -20147,7 +20431,7 @@ var Sudo = class {
|
|
|
20147
20431
|
}
|
|
20148
20432
|
return grant();
|
|
20149
20433
|
}
|
|
20150
|
-
listed(self, root, rules) {
|
|
20434
|
+
listed(self, root, rules, defaults2) {
|
|
20151
20435
|
const host = this.o.hostname;
|
|
20152
20436
|
if (root) {
|
|
20153
20437
|
return {
|
|
@@ -20160,11 +20444,20 @@ var Sudo = class {
|
|
|
20160
20444
|
return failed2("EPERM", `User ${self.name} is not allowed to run sudo on ${host}.`);
|
|
20161
20445
|
}
|
|
20162
20446
|
const lines2 = rules.map(described).join("\n");
|
|
20163
|
-
|
|
20447
|
+
const params = defaults2.flatMap((d) => d.params).join(", ");
|
|
20448
|
+
const matching = params === "" ? "" : `Matching Defaults entries for ${self.name} on ${host}:
|
|
20449
|
+
${params}
|
|
20450
|
+
|
|
20451
|
+
`;
|
|
20452
|
+
return {
|
|
20453
|
+
list: `${matching}User ${self.name} may run the following commands on ${host}:
|
|
20164
20454
|
${lines2}
|
|
20165
|
-
`
|
|
20455
|
+
`
|
|
20456
|
+
};
|
|
20166
20457
|
}
|
|
20167
|
-
async ask(
|
|
20458
|
+
async ask(s, asked) {
|
|
20459
|
+
const { caller, self, target, signal: requester } = s;
|
|
20460
|
+
const { argv, path, cwd } = asked;
|
|
20168
20461
|
const { approve } = this.o;
|
|
20169
20462
|
if (!approve || requester.aborted) return failed2("EACCES", DENIED2);
|
|
20170
20463
|
const createdAt = Date.now();
|
|
@@ -20183,9 +20476,11 @@ ${lines2}
|
|
|
20183
20476
|
...caller.tty ? { tty: caller.tty } : {},
|
|
20184
20477
|
createdAt,
|
|
20185
20478
|
expiresAt: createdAt + timeout,
|
|
20186
|
-
always: recordable(cwd, [path, ...argv]),
|
|
20479
|
+
always: asked.validate ? false : recordable(cwd, [path, ...argv]),
|
|
20187
20480
|
stdin: caller.stdin,
|
|
20188
|
-
rootOnly: await this.rootOnly(cwd, argv.slice(1))
|
|
20481
|
+
rootOnly: asked.validate ? {} : await this.rootOnly(cwd, argv.slice(1)),
|
|
20482
|
+
...asked.validate ? { validate: true } : {},
|
|
20483
|
+
timestamp: true
|
|
20189
20484
|
};
|
|
20190
20485
|
const control = new AbortController();
|
|
20191
20486
|
const timer = setTimeout(() => control.abort("expired"), timeout);
|
|
@@ -20195,9 +20490,8 @@ ${lines2}
|
|
|
20195
20490
|
try {
|
|
20196
20491
|
const answer2 = await answerOf(approve, req, control.signal);
|
|
20197
20492
|
if (answer2 === ABORTED) return ended();
|
|
20198
|
-
|
|
20199
|
-
|
|
20200
|
-
}
|
|
20493
|
+
const approved = approvalOf(answer2);
|
|
20494
|
+
if (approved) return control.signal.aborted ? ended() : approved;
|
|
20201
20495
|
return failed2("EACCES", denialText(answer2));
|
|
20202
20496
|
} finally {
|
|
20203
20497
|
clearTimeout(timer);
|
|
@@ -23914,7 +24208,7 @@ function replaced(text, values) {
|
|
|
23914
24208
|
for (const [ph, value2] of Object.entries(values)) out = out.split(ph).join(binary(value2));
|
|
23915
24209
|
return out;
|
|
23916
24210
|
}
|
|
23917
|
-
function
|
|
24211
|
+
function usable2(values) {
|
|
23918
24212
|
const out = {};
|
|
23919
24213
|
for (const [ph, value2] of Object.entries(values ?? {}))
|
|
23920
24214
|
if (encoder8.encode(value2).length >= MIN_VALUE) out[ph] = value2;
|
|
@@ -23929,7 +24223,7 @@ async function substituteHead(head, ask) {
|
|
|
23929
24223
|
if (!request3 || !found || found.length !== 1) return void 0;
|
|
23930
24224
|
const at = found[0];
|
|
23931
24225
|
if (at.placeholders.length > SESSION_PLACEHOLDERS) return void 0;
|
|
23932
|
-
const values =
|
|
24226
|
+
const values = usable2(
|
|
23933
24227
|
await ask(`header:${at.name}`, at.placeholders, {
|
|
23934
24228
|
method: request3[1],
|
|
23935
24229
|
path: request3[2]
|
|
@@ -24239,7 +24533,7 @@ async function cleartext(message3, asks) {
|
|
|
24239
24533
|
const placeholders = placeholdersIn(password);
|
|
24240
24534
|
if (placeholders.length === 0 || placeholders.length > SESSION_PLACEHOLDERS)
|
|
24241
24535
|
return { bytes: message3, done: true };
|
|
24242
|
-
const values =
|
|
24536
|
+
const values = usable2(await asks.cleartext(placeholders));
|
|
24243
24537
|
if (Object.keys(values).length === 0) return { bytes: message3, done: true };
|
|
24244
24538
|
return { bytes: frame3(112, `${replaced(password, values)}\0`), values, done: true };
|
|
24245
24539
|
}
|
|
@@ -24304,7 +24598,7 @@ var PgClient = class {
|
|
|
24304
24598
|
const x = got.exchange;
|
|
24305
24599
|
const binding = this.header === END_POINT ? this.server.binding : void 0;
|
|
24306
24600
|
const serverFinal = `c=${channelOf(this.header, binding)},r=${got.nonce}`;
|
|
24307
|
-
const values =
|
|
24601
|
+
const values = usable2(
|
|
24308
24602
|
await this.asks.scram({
|
|
24309
24603
|
clientFirstBare: x.clientFirstBare,
|
|
24310
24604
|
serverFirst: x.serverFirst,
|
|
@@ -24353,7 +24647,7 @@ function decoded(b642) {
|
|
|
24353
24647
|
async function swapped2(text, position, ask) {
|
|
24354
24648
|
const placeholders = placeholdersIn(text);
|
|
24355
24649
|
if (placeholders.length === 0 || placeholders.length > SESSION_PLACEHOLDERS) return void 0;
|
|
24356
|
-
const values =
|
|
24650
|
+
const values = usable2(await ask(position, placeholders));
|
|
24357
24651
|
if (Object.keys(values).length === 0) return void 0;
|
|
24358
24652
|
return { text: replaced(text, values), values };
|
|
24359
24653
|
}
|
|
@@ -24451,7 +24745,7 @@ function headEnd2(bytes) {
|
|
|
24451
24745
|
}
|
|
24452
24746
|
return -1;
|
|
24453
24747
|
}
|
|
24454
|
-
function
|
|
24748
|
+
function modeOf2(start2) {
|
|
24455
24749
|
const sniffs = [
|
|
24456
24750
|
["http1", sniffHttp1(start2)],
|
|
24457
24751
|
["smtp", sniffSmtp(start2)],
|
|
@@ -24560,7 +24854,7 @@ var SessionWriter = class {
|
|
|
24560
24854
|
joined5.set(bytes, this.buffer.length);
|
|
24561
24855
|
this.buffer.fill(0);
|
|
24562
24856
|
this.buffer = joined5;
|
|
24563
|
-
if (this.mode === "sniff") this.mode =
|
|
24857
|
+
if (this.mode === "sniff") this.mode = modeOf2(latin12(joined5.subarray(0, 8))) ?? "sniff";
|
|
24564
24858
|
if (this.mode === "pg" && !this.sawPg) {
|
|
24565
24859
|
this.sawPg = true;
|
|
24566
24860
|
if (!this.s.verified) void this.proof("pg");
|
|
@@ -33000,6 +33294,7 @@ var SUDO_SOURCE = [
|
|
|
33000
33294
|
" await say(1, answer.list);",
|
|
33001
33295
|
" return 0;",
|
|
33002
33296
|
" }",
|
|
33297
|
+
" if (answer.done === true) return 0;",
|
|
33003
33298
|
" if (answer.run !== undefined) {",
|
|
33004
33299
|
" try {",
|
|
33005
33300
|
" pid = (await ctx.spawn({ argv: answer.run, pgid: 0 })).pid;",
|
|
@@ -33639,6 +33934,7 @@ var Launcher = class {
|
|
|
33639
33934
|
);
|
|
33640
33935
|
}
|
|
33641
33936
|
this.users = new UserDb(this.fs, this.owners);
|
|
33937
|
+
const { sudoClock } = options;
|
|
33642
33938
|
this.sudoer = new Sudo({
|
|
33643
33939
|
fs: this.fs,
|
|
33644
33940
|
users: this.users,
|
|
@@ -33648,7 +33944,8 @@ var Launcher = class {
|
|
|
33648
33944
|
pnpmHome: this.pnpmHome,
|
|
33649
33945
|
backing: (path, cwd) => this.backing(path, cwd),
|
|
33650
33946
|
approve: options.approve,
|
|
33651
|
-
timeoutMs: options.sudoTimeoutMs
|
|
33947
|
+
timeoutMs: options.sudoTimeoutMs,
|
|
33948
|
+
now: sudoClock ? () => sudoClock.now() : void 0
|
|
33652
33949
|
});
|
|
33653
33950
|
this.cron = this.cronService(options.cron);
|
|
33654
33951
|
void this.unlinked.sweep("/");
|
|
@@ -35054,11 +35351,26 @@ var Launcher = class {
|
|
|
35054
35351
|
pid: this.jobs.shown(pid),
|
|
35055
35352
|
tags: this.tagsOf(pid),
|
|
35056
35353
|
tty: this.described.get(pid)?.tty,
|
|
35354
|
+
...this.timestampOwner(pid),
|
|
35057
35355
|
stdin,
|
|
35058
35356
|
report
|
|
35059
35357
|
};
|
|
35060
35358
|
return this.sudoer.request(caller, call, signal);
|
|
35061
35359
|
}
|
|
35360
|
+
timestampOwner(pid) {
|
|
35361
|
+
const sid = this.jobs.sidOf(pid);
|
|
35362
|
+
const tty = this.jobs.controllingTerminal(pid)?.name;
|
|
35363
|
+
const leader = sid === void 0 ? void 0 : this.startedOf(sid);
|
|
35364
|
+
const host = this.jobs.shownParent(pid) ?? this.jobs.shown(pid);
|
|
35365
|
+
const started = this.startedOf(host);
|
|
35366
|
+
return {
|
|
35367
|
+
...tty && sid !== void 0 && leader !== void 0 ? { terminal: { tty, sid, started: leader } } : {},
|
|
35368
|
+
...started === void 0 ? {} : { parent: { pid: host, started } }
|
|
35369
|
+
};
|
|
35370
|
+
}
|
|
35371
|
+
startedOf(shown2) {
|
|
35372
|
+
return this.running(shown2) ? this.described.get(shown2)?.started : void 0;
|
|
35373
|
+
}
|
|
35062
35374
|
visudo(pid, call) {
|
|
35063
35375
|
return this.sudoer.check(this.credOf(pid), call);
|
|
35064
35376
|
}
|