Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a6d2f6dca7 | |||
| b015d5880a |
@@ -64,12 +64,18 @@ local newGid = resolveGid(groupStr)
|
|||||||
local function chgrpPath(path)
|
local function chgrpPath(path)
|
||||||
local stat = syscall.stat(path)
|
local stat = syscall.stat(path)
|
||||||
if not stat then
|
if not stat then
|
||||||
print(name .. ": cannot stat '" .. path .. "': No such file or directory")
|
print(name .. ": cannot stat '" .. path .. "': no such file or directory")
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
local ok, err = pcall(syscall.chown, path, stat.owner, newGid)
|
local ok, err = pcall(syscall.chown, path, stat.owner, newGid)
|
||||||
if not ok then
|
if not ok then
|
||||||
print(name .. ": cannot change group of '" .. path .. "': " .. tostring(err))
|
local msg = tostring(err)
|
||||||
|
if msg:find("EPERM") or msg:find("EACCES") then
|
||||||
|
msg = "operation not permitted (must be root)"
|
||||||
|
elseif msg:find("ENOENT") then
|
||||||
|
msg = "no such file or directory"
|
||||||
|
end
|
||||||
|
print(name .. ": cannot change group of '" .. path .. "': " .. msg)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -220,7 +220,13 @@ local function chmodPath(path)
|
|||||||
|
|
||||||
local ok, cerr = pcall(syscall.chmod, path, newPerms)
|
local ok, cerr = pcall(syscall.chmod, path, newPerms)
|
||||||
if not ok then
|
if not ok then
|
||||||
print(name .. ": cannot change permissions of '" .. path .. "': " .. tostring(cerr))
|
local msg = tostring(cerr)
|
||||||
|
if msg:find("EACCES") or msg:find("EPERM") then
|
||||||
|
msg = "permission denied"
|
||||||
|
elseif msg:find("ENOENT") then
|
||||||
|
msg = "no such file or directory"
|
||||||
|
end
|
||||||
|
print(name .. ": cannot change permissions of '" .. path .. "': " .. msg)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -95,14 +95,20 @@ end
|
|||||||
local function chownPath(path)
|
local function chownPath(path)
|
||||||
local stat = syscall.stat(path)
|
local stat = syscall.stat(path)
|
||||||
if not stat then
|
if not stat then
|
||||||
print(name .. ": cannot stat '" .. path .. "': No such file or directory")
|
print(name .. ": cannot stat '" .. path .. "': no such file or directory")
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
local uid = newUid ~= nil and newUid or stat.owner
|
local uid = newUid ~= nil and newUid or stat.owner
|
||||||
local gid = newGid ~= nil and newGid or stat.group
|
local gid = newGid ~= nil and newGid or stat.group
|
||||||
local ok, err = pcall(syscall.chown, path, uid, gid)
|
local ok, err = pcall(syscall.chown, path, uid, gid)
|
||||||
if not ok then
|
if not ok then
|
||||||
print(name .. ": cannot change owner of '" .. path .. "': " .. tostring(err))
|
local msg = tostring(err)
|
||||||
|
if msg:find("EPERM") or msg:find("EACCES") then
|
||||||
|
msg = "operation not permitted (must be root)"
|
||||||
|
elseif msg:find("ENOENT") then
|
||||||
|
msg = "no such file or directory"
|
||||||
|
end
|
||||||
|
print(name .. ": cannot change owner of '" .. path .. "': " .. msg)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -17,7 +17,13 @@ local commandHistory = {}
|
|||||||
local terminate = false
|
local terminate = false
|
||||||
syscall.setEnviron("SHELL","rtbash")
|
syscall.setEnviron("SHELL","rtbash")
|
||||||
syscall.setEnviron("PATH","/bin/")
|
syscall.setEnviron("PATH","/bin/")
|
||||||
|
local _home = syscall.getEnviron("HOME")
|
||||||
|
if _home and _home ~= "" then
|
||||||
|
local ok = pcall(syscall.chdir, _home)
|
||||||
|
if not ok then syscall.chdir("/") end
|
||||||
|
else
|
||||||
syscall.chdir("/")
|
syscall.chdir("/")
|
||||||
|
end
|
||||||
local oldWD = ""
|
local oldWD = ""
|
||||||
|
|
||||||
for i = 1, 16 do
|
for i = 1, 16 do
|
||||||
|
|||||||
@@ -96,6 +96,9 @@ local function spawnShell(username, uid, shell, homedir)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local chdirOk, chdirErr = pcall(syscall.chdir, homedir)
|
local chdirOk, chdirErr = pcall(syscall.chdir, homedir)
|
||||||
|
if not chdirOk then
|
||||||
|
pcall(syscall.chdir, "/")
|
||||||
|
end
|
||||||
|
|
||||||
local ok, err = pcall(syscall.execspawn, shell, username .. ":shell")
|
local ok, err = pcall(syscall.execspawn, shell, username .. ":shell")
|
||||||
if not ok then
|
if not ok then
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ for j = i + 1, #cmdArgs do restArgs[#restArgs + 1] = cmdArgs[j] end
|
|||||||
local currentUid = syscall.getuid()
|
local currentUid = syscall.getuid()
|
||||||
local currentUser = syscall.getUsername(currentUid) or tostring(currentUid)
|
local currentUser = syscall.getUsername(currentUid) or tostring(currentUid)
|
||||||
|
|
||||||
local targetUid = syscall.getuid(targetUser)
|
local targetUid = syscall.getuidbyname(targetUser)
|
||||||
if not targetUid then
|
if not targetUid then
|
||||||
print("sudo: user '" .. targetUser .. "' does not exist")
|
print("sudo: user '" .. targetUser .. "' does not exist")
|
||||||
syscall.exit(1)
|
syscall.exit(1)
|
||||||
@@ -39,7 +39,7 @@ if not targetUid then
|
|||||||
end
|
end
|
||||||
|
|
||||||
if currentUid ~= 0 then
|
if currentUid ~= 0 then
|
||||||
printInline("[sudo] password for " .. currentUser .. ": ")
|
printInline("[sudo] password for root: ")
|
||||||
local pw = ""
|
local pw = ""
|
||||||
while true do
|
while true do
|
||||||
local ch = syscall.read(0)
|
local ch = syscall.read(0)
|
||||||
@@ -55,7 +55,7 @@ if currentUid ~= 0 then
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local ok, err = syscall.elevate(currentUser, pw)
|
local ok, err = syscall.elevate("root", pw)
|
||||||
if not ok then
|
if not ok then
|
||||||
sleep(1)
|
sleep(1)
|
||||||
print("sudo: Authentication failure")
|
print("sudo: Authentication failure")
|
||||||
@@ -63,7 +63,7 @@ if currentUid ~= 0 then
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if targetUid ~= 0 then
|
if targetUid ~= currentUid then
|
||||||
syscall.setuid(targetUid)
|
syscall.setuid(targetUid)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ for i,v in pairs(kernel.processes) do
|
|||||||
end, i)
|
end, i)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if not fs.exists("/bin/startup") then
|
||||||
|
fs.mkdir("/bin/startup")
|
||||||
|
end
|
||||||
local files = fs.list("/bin/startup")
|
local files = fs.list("/bin/startup")
|
||||||
if not files then error("Failed to list /bin/startup") end
|
if not files then error("Failed to list /bin/startup") end
|
||||||
for i,v in ipairs(files) do
|
for i,v in ipairs(files) do
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ function peripheral.isPresent(name)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function peripheral.getType(peripheral)
|
function peripheral.getType(peripheral)
|
||||||
if type(peripheral) == "string" then -- Peripheral name passed
|
if type(peripheral) == "string" then
|
||||||
if native.isPresent(peripheral) then
|
if native.isPresent(peripheral) then
|
||||||
return native.getType(peripheral)
|
return native.getType(peripheral)
|
||||||
end
|
end
|
||||||
@@ -58,7 +58,7 @@ function peripheral.getType(peripheral)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function peripheral.hasType(peripheral, peripheral_type)
|
function peripheral.hasType(peripheral, peripheral_type)
|
||||||
if type(peripheral) == "string" then -- Peripheral name passed
|
if type(peripheral) == "string" then
|
||||||
if native.isPresent(peripheral) then
|
if native.isPresent(peripheral) then
|
||||||
return native.hasType(peripheral, peripheral_type)
|
return native.hasType(peripheral, peripheral_type)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -5,14 +5,14 @@ kernel.vfs = vfs
|
|||||||
vfs.mounts = {["$"] = "/"}
|
vfs.mounts = {["$"] = "/"}
|
||||||
vfs.disks = kernel.disks
|
vfs.disks = kernel.disks
|
||||||
|
|
||||||
-- Metafile format (version 1)
|
-- Metafile format (version 2)
|
||||||
-- File header: 1 byte = version (0x01)
|
-- File header: 1 byte = version (0x02)
|
||||||
-- Per-entry:
|
-- Per-entry:
|
||||||
-- 1 byte = name length
|
-- 1 byte = name length
|
||||||
-- N bytes = name
|
-- N bytes = name
|
||||||
-- 1 byte = entry type (0x00 = regular, 0x01 = symlink)
|
-- 1 byte = entry type (0x00 = regular, 0x01 = symlink)
|
||||||
-- 1 byte = owner uid
|
-- 2 bytes = owner uid (little-endian uint16)
|
||||||
-- 1 byte = group gid
|
-- 2 bytes = group gid (little-endian uint16)
|
||||||
-- 2 bytes = perms (little-endian uint16)
|
-- 2 bytes = perms (little-endian uint16)
|
||||||
-- bit 0 = world-write bit 1 = world-read
|
-- bit 0 = world-write bit 1 = world-read
|
||||||
-- bit 2 = group-write bit 3 = group-read
|
-- bit 2 = group-write bit 3 = group-read
|
||||||
@@ -24,12 +24,16 @@ vfs.disks = kernel.disks
|
|||||||
-- 1 byte = cmeta length
|
-- 1 byte = cmeta length
|
||||||
-- N bytes = cmeta (for symlinks: the link target path)
|
-- N bytes = cmeta (for symlinks: the link target path)
|
||||||
--
|
--
|
||||||
|
-- Version 1:
|
||||||
|
-- 1 byte name len, N bytes name, 1 byte etype, 1 byte owner,
|
||||||
|
-- 1 byte group, 2 bytes perms (little-endian), 1 byte cmeta len, N bytes cmeta
|
||||||
|
--
|
||||||
-- Version 0:
|
-- Version 0:
|
||||||
-- No file header. Per-entry:
|
-- No file header. Per-entry:
|
||||||
-- 1 byte name len, N bytes name, 1 byte owner, 1 byte group,
|
-- 1 byte name len, N bytes name, 1 byte owner, 1 byte group,
|
||||||
-- 1 byte perms (low 7 bits only), 1 byte cmeta len, N bytes cmeta
|
-- 1 byte perms (low 7 bits only), 1 byte cmeta len, N bytes cmeta
|
||||||
|
|
||||||
local META_VERSION = 0x01
|
local META_VERSION = 0x02
|
||||||
|
|
||||||
local function bit_is_set(num, bit)
|
local function bit_is_set(num, bit)
|
||||||
return math.floor(num / (2 ^ bit)) % 2 == 1
|
return math.floor(num / (2 ^ bit)) % 2 == 1
|
||||||
@@ -41,8 +45,9 @@ local function parseMetafile(raw)
|
|||||||
local p = 1
|
local p = 1
|
||||||
|
|
||||||
local version = 0
|
local version = 0
|
||||||
if raw:byte(1) == META_VERSION then
|
local firstByte = raw:byte(1)
|
||||||
version = META_VERSION
|
if firstByte == 0x02 or firstByte == 0x01 then
|
||||||
|
version = firstByte
|
||||||
p = 2
|
p = 2
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -54,13 +59,22 @@ local function parseMetafile(raw)
|
|||||||
|
|
||||||
local etype, owner, group, perms, cmeta
|
local etype, owner, group, perms, cmeta
|
||||||
|
|
||||||
if version == META_VERSION then
|
if version == 0x02 then
|
||||||
|
-- v2: etype(1) + owner(2) + group(2) + perms(2) = 7 bytes
|
||||||
|
if p + 6 > #raw then break end
|
||||||
|
etype = raw:byte(p); p = p + 1
|
||||||
|
owner = raw:byte(p) + raw:byte(p+1) * 256; p = p + 2
|
||||||
|
group = raw:byte(p) + raw:byte(p+1) * 256; p = p + 2
|
||||||
|
perms = raw:byte(p) + raw:byte(p+1) * 256; p = p + 2
|
||||||
|
elseif version == 0x01 then
|
||||||
|
-- v1: etype(1) + owner(1) + group(1) + perms(2) = 5 bytes
|
||||||
if p + 4 > #raw then break end
|
if p + 4 > #raw then break end
|
||||||
etype = raw:byte(p); p = p + 1
|
etype = raw:byte(p); p = p + 1
|
||||||
owner = raw:byte(p); p = p + 1
|
owner = raw:byte(p); p = p + 1
|
||||||
group = raw:byte(p); p = p + 1
|
group = raw:byte(p); p = p + 1
|
||||||
perms = raw:byte(p) + raw:byte(p+1) * 256; p = p + 2
|
perms = raw:byte(p) + raw:byte(p+1) * 256; p = p + 2
|
||||||
else
|
else
|
||||||
|
-- v0: owner(1) + group(1) + perms(1) = 3 bytes
|
||||||
if p + 2 > #raw then break end
|
if p + 2 > #raw then break end
|
||||||
etype = 0x00
|
etype = 0x00
|
||||||
owner = raw:byte(p); p = p + 1
|
owner = raw:byte(p); p = p + 1
|
||||||
@@ -87,10 +101,14 @@ local function makeMetafile(meta)
|
|||||||
for name, m in pairs(meta) do
|
for name, m in pairs(meta) do
|
||||||
local plo = m.perms % 256
|
local plo = m.perms % 256
|
||||||
local phi = math.floor(m.perms / 256) % 256
|
local phi = math.floor(m.perms / 256) % 256
|
||||||
|
local olo = (m.owner or 0) % 256
|
||||||
|
local ohi = math.floor((m.owner or 0) / 256) % 256
|
||||||
|
local glo = (m.group or 0) % 256
|
||||||
|
local ghi = math.floor((m.group or 0) / 256) % 256
|
||||||
out = out
|
out = out
|
||||||
.. string.char(#name) .. name
|
.. string.char(#name) .. name
|
||||||
.. string.char(m.etype or 0x00)
|
.. string.char(m.etype or 0x00)
|
||||||
.. string.char(m.owner, m.group, plo, phi)
|
.. string.char(olo, ohi, glo, ghi, plo, phi)
|
||||||
.. string.char(#m.cmeta) .. m.cmeta
|
.. string.char(#m.cmeta) .. m.cmeta
|
||||||
end
|
end
|
||||||
return out
|
return out
|
||||||
@@ -146,6 +164,9 @@ local function resolveMount(normalPath)
|
|||||||
return vfs.disks[mountId], diskPath
|
return vfs.disks[mountId], diskPath
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Expose parser for use by other modules (e.g. permissions seeder)
|
||||||
|
vfs._parseMetafile = parseMetafile
|
||||||
|
|
||||||
local function readMetaEntry(disk, parentDiskPath, filename)
|
local function readMetaEntry(disk, parentDiskPath, filename)
|
||||||
if filename == ".meta" then error("Cannot open metafile") end
|
if filename == ".meta" then error("Cannot open metafile") end
|
||||||
local mp
|
local mp
|
||||||
@@ -159,6 +180,15 @@ local function readMetaEntry(disk, parentDiskPath, filename)
|
|||||||
if not ok or not f then return nil end
|
if not ok or not f then return nil end
|
||||||
local raw = f.read(65535)
|
local raw = f.read(65535)
|
||||||
if f.close then f.close() end
|
if f.close then f.close() end
|
||||||
|
|
||||||
|
-- Auto-upgrade: if this .meta file is not v2, rewrite it as v2 now
|
||||||
|
if raw and #raw > 0 and raw:byte(1) ~= META_VERSION then
|
||||||
|
local upgraded = makeMetafile(parseMetafile(raw))
|
||||||
|
local wok, wf = pcall(function() return disk:open(mp, "w") end)
|
||||||
|
if wok and wf then wf.write(upgraded); if wf.close then wf.close() end end
|
||||||
|
raw = upgraded
|
||||||
|
end
|
||||||
|
|
||||||
local parsed = parseMetafile(raw)
|
local parsed = parseMetafile(raw)
|
||||||
return parsed[filename]
|
return parsed[filename]
|
||||||
end
|
end
|
||||||
@@ -400,6 +430,8 @@ function vfs.open(path, mode)
|
|||||||
if not disk then error("NODISK") end
|
if not disk then error("NODISK") end
|
||||||
|
|
||||||
local meta = getFileMeta(path)
|
local meta = getFileMeta(path)
|
||||||
|
local isNew = (mode == "w" or mode == "a") and not disk:fileExists(diskPath)
|
||||||
|
|
||||||
checkperms(meta, mode == "r" and "r" or "w")
|
checkperms(meta, mode == "r" and "r" or "w")
|
||||||
|
|
||||||
local handle
|
local handle
|
||||||
@@ -408,6 +440,22 @@ function vfs.open(path, mode)
|
|||||||
if type(handle) ~= "table" then error("ENFILE") end
|
if type(handle) ~= "table" then error("ENFILE") end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- If this is a newly created file, stamp it with the creating user's ownership
|
||||||
|
if isNew then
|
||||||
|
local euid = (task and (task.euid or task.uid)) or kernel.uid
|
||||||
|
local egid = (task and task.gid) or 0
|
||||||
|
local norm = normalizePath(path)
|
||||||
|
local parent = norm:match("^(.*)/[^/]+$") or "/"
|
||||||
|
if parent == "" then parent = "/" end
|
||||||
|
local name = norm:match("[^/]+$")
|
||||||
|
if name then
|
||||||
|
local entry = { etype=0x00, owner=euid, group=egid,
|
||||||
|
perms=vfs.PERM.RW_R_R, cmeta="" }
|
||||||
|
pcall(writeMetaEntry, parent, name, entry, false)
|
||||||
|
meta = entry
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local fobj = newFileObj(handle, mode, path, meta, disk:type(diskPath))
|
local fobj = newFileObj(handle, mode, path, meta, disk:type(diskPath))
|
||||||
if mode == "r" and bit_is_set(meta.perms, 6) then
|
if mode == "r" and bit_is_set(meta.perms, 6) then
|
||||||
fobj.suid_owner = meta.owner
|
fobj.suid_owner = meta.owner
|
||||||
@@ -574,15 +622,33 @@ function vfs.listdir(path)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function vfs.mkdir(path)
|
function vfs.mkdir(path)
|
||||||
|
local norm = normalizePath(path)
|
||||||
|
local parent = norm:match("^(.*)/[^/]+$") or "/"
|
||||||
|
if parent == "" then parent = "/" end
|
||||||
|
local parentMeta = getFileMeta(parent)
|
||||||
|
checkperms(parentMeta, "w")
|
||||||
local disk, diskPath = resolvePath(path)
|
local disk, diskPath = resolvePath(path)
|
||||||
local meta = getFileMeta(path)
|
|
||||||
checkperms(meta, "w")
|
|
||||||
disk:makeDirectory(diskPath)
|
disk:makeDirectory(diskPath)
|
||||||
|
-- Stamp the new directory with the creating user's ownership
|
||||||
|
local task = kernel.currentTask
|
||||||
|
local euid = (task and (task.euid or task.uid)) or kernel.uid
|
||||||
|
local egid = (task and task.gid) or 0
|
||||||
|
local name = norm:match("[^/]+$")
|
||||||
|
if name then
|
||||||
|
local entry = { etype=0x00, owner=euid, group=egid,
|
||||||
|
perms=vfs.PERM.RWX_RX, cmeta="" }
|
||||||
|
pcall(writeMetaEntry, parent, name, entry, false)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function vfs.remove(path)
|
function vfs.remove(path)
|
||||||
|
local norm = resolveSymlinks(path, true)
|
||||||
|
local parent = norm:match("^(.*)/[^/]+$") or "/"
|
||||||
|
if parent == "" then parent = "/" end
|
||||||
|
local parentMeta = getFileMeta(parent)
|
||||||
|
checkperms(parentMeta, "w")
|
||||||
|
|
||||||
local meta = getFileMeta(path, true)
|
local meta = getFileMeta(path, true)
|
||||||
checkperms(meta, "w")
|
|
||||||
|
|
||||||
if kernel.unixSockets and kernel.unixSockets[path] then
|
if kernel.unixSockets and kernel.unixSockets[path] then
|
||||||
kernel.unixSockets[path] = nil
|
kernel.unixSockets[path] = nil
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ local args = {...}
|
|||||||
local kernel = args[1]
|
local kernel = args[1]
|
||||||
kernel._G = _G
|
kernel._G = _G
|
||||||
|
|
||||||
|
|
||||||
local function readonly(tbl)
|
local function readonly(tbl)
|
||||||
return setmetatable({}, {
|
return setmetatable({}, {
|
||||||
__index = function(_, key)
|
__index = function(_, key)
|
||||||
@@ -49,8 +50,10 @@ local function readonly(tbl)
|
|||||||
__metatable = false
|
__metatable = false
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
--local origLoad = load
|
||||||
|
|
||||||
kernel._U = readonly(kernel._G)
|
kernel._U = readonly(kernel._G)
|
||||||
kernel.allowGlobalOverwrites = true
|
kernel.allowGlobalOverwrites = true
|
||||||
kernel._U._G = kernel._U
|
kernel._U._G = kernel._U
|
||||||
|
--kernel._U.load = function(a,b,c,d) return origLoad(a,b,c,d or kernel._U) end
|
||||||
kernel.allowGlobalOverwrites = false
|
kernel.allowGlobalOverwrites = false
|
||||||
|
|||||||
@@ -394,6 +394,8 @@ function auth.newUser(username, password, gid, homedir, shell)
|
|||||||
|
|
||||||
if kernel.vfs.mkdir and not kernel.vfs.exists(homedir) then
|
if kernel.vfs.mkdir and not kernel.vfs.exists(homedir) then
|
||||||
kernel.vfs.mkdir(homedir)
|
kernel.vfs.mkdir(homedir)
|
||||||
|
-- Homedir must be owned by the new user, not root
|
||||||
|
pcall(kernel.vfs.chown, homedir, uid, uid)
|
||||||
end
|
end
|
||||||
|
|
||||||
kernel.log("AUTH: new user '" .. username .. "' uid=" .. tostring(uid))
|
kernel.log("AUTH: new user '" .. username .. "' uid=" .. tostring(uid))
|
||||||
@@ -591,13 +593,13 @@ function auth.elevate(targetUsername, password)
|
|||||||
|
|
||||||
local task = kernel.currentTask
|
local task = kernel.currentTask
|
||||||
local prevUid = task.uid
|
local prevUid = task.uid
|
||||||
task.uid = uid
|
task.uid = 0
|
||||||
task.euid = uid
|
task.euid = 0
|
||||||
task.gid = tonumber(entry[2]) or uid
|
task.gid = 0
|
||||||
task.egid = tonumber(entry[2]) or uid
|
task.egid = 0
|
||||||
kernel.uid = uid
|
kernel.uid = 0
|
||||||
|
|
||||||
kernel.log("AUTH: elevate uid=" .. tostring(prevUid) .. " -> " .. tostring(uid) .. " (" .. targetUsername .. ")")
|
kernel.log("AUTH: elevate uid=" .. tostring(prevUid) .. " -> 0 (via " .. targetUsername .. ")")
|
||||||
return true, uid
|
return true, uid
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -13,15 +13,19 @@ local RW____ = P.OWNER_R + P.OWNER_W
|
|||||||
local RWXRWXRWX = PERM.RWXRWXRWX
|
local RWXRWXRWX = PERM.RWXRWXRWX
|
||||||
local SUID_755 = PERM.SUID_755
|
local SUID_755 = PERM.SUID_755
|
||||||
|
|
||||||
local META_VERSION = 0x01
|
local META_VERSION = 0x02
|
||||||
local rootDisk = kernel.disks["$"]
|
local rootDisk = kernel.disks["$"]
|
||||||
|
|
||||||
local function makeEntry(name, etype, owner, group, perms, cmeta)
|
local function makeEntry(name, etype, owner, group, perms, cmeta)
|
||||||
cmeta = cmeta or ""
|
cmeta = cmeta or ""
|
||||||
local plo = perms % 256
|
local plo = perms % 256
|
||||||
local phi = math.floor(perms / 256) % 256
|
local phi = math.floor(perms / 256) % 256
|
||||||
|
local olo = (owner or 0) % 256
|
||||||
|
local ohi = math.floor((owner or 0) / 256) % 256
|
||||||
|
local glo = (group or 0) % 256
|
||||||
|
local ghi = math.floor((group or 0) / 256) % 256
|
||||||
return string.char(#name) .. name
|
return string.char(#name) .. name
|
||||||
.. string.char(etype, owner, group, plo, phi)
|
.. string.char(etype, olo, ohi, glo, ghi, plo, phi)
|
||||||
.. string.char(#cmeta) .. cmeta
|
.. string.char(#cmeta) .. cmeta
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -47,12 +51,106 @@ end
|
|||||||
|
|
||||||
local REG = 0x00
|
local REG = 0x00
|
||||||
|
|
||||||
if rootDisk:fileExists(".meta") then
|
-- All known /bin entries with their permissions
|
||||||
kernel.log("Permissions already seeded, skipping.", "INFO")
|
local BIN_ENTRIES = {
|
||||||
else
|
{"cat", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"chattr", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"chgrp", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"chmod", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"chown", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"chroot", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"clear", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"echo", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"hfetch", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"help", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"hysh", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"hyshex", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"id", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"install", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"ln", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"login", REG, 0, 0, SUID_755 },
|
||||||
|
{"loimgcreate", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"looptest", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"losetup", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"ls", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"lsusers", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"lua", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"luaold", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"micro", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"mkdir", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"mount", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"passwd", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"ps", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"pwd", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"readlink", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"sed", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"socktest", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"spm", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"su", REG, 0, 0, SUID_755 },
|
||||||
|
{"sudo", REG, 0, 0, SUID_755 },
|
||||||
|
{"sysdump", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"umount", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"useradd", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"userdel", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"usermod", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"whoami", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"yes", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"startup", REG, 0, 0, RWX_RX_RX},
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Merge entries: always ensure all known entries exist with correct permissions.
|
||||||
|
-- This handles both fresh installs and upgrades (adds missing entries, upgrades
|
||||||
|
-- the on-disk format to v2 by rewriting).
|
||||||
|
local function mergeMeta(dir, entries)
|
||||||
|
local diskDir = dir
|
||||||
|
if diskDir:sub(1,1) == "/" then diskDir = diskDir:sub(2) end
|
||||||
|
local metaPath = (diskDir == "" and ".meta" or diskDir .. "/.meta")
|
||||||
|
|
||||||
|
-- Read existing meta (may be v1 or v2)
|
||||||
|
local existing = {}
|
||||||
|
local rok, rf = pcall(function() return rootDisk:open(metaPath, "r") end)
|
||||||
|
if rok and rf then
|
||||||
|
local raw = rf.read(65535)
|
||||||
|
if rf.close then rf.close() end
|
||||||
|
-- Parse using the VFS parser (handles v0/v1/v2)
|
||||||
|
existing = kernel.vfs and kernel.vfs._parseMetafile and kernel.vfs._parseMetafile(raw) or {}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Add any missing entries (don't overwrite existing customised perms)
|
||||||
|
for _, e in ipairs(entries) do
|
||||||
|
if not existing[e[1]] then
|
||||||
|
existing[e[1]] = {
|
||||||
|
etype = e[2] or 0x00,
|
||||||
|
owner = e[3] or 0,
|
||||||
|
group = e[4] or 0,
|
||||||
|
perms = e[5] or RWX_RX_RX,
|
||||||
|
cmeta = e[6] or "",
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Write back as v2
|
||||||
|
local data = string.char(META_VERSION)
|
||||||
|
for name, m in pairs(existing) do
|
||||||
|
data = data .. makeEntry(name, m.etype or 0x00, m.owner or 0, m.group or 0, m.perms or RWX_RX_RX, m.cmeta or "")
|
||||||
|
end
|
||||||
|
|
||||||
|
local ok, err = pcall(function()
|
||||||
|
local f = rootDisk:open(metaPath, "w")
|
||||||
|
f.write(data)
|
||||||
|
f.close()
|
||||||
|
end)
|
||||||
|
if not ok then
|
||||||
|
kernel.log("permissions: failed to write " .. metaPath .. ": " .. tostring(err), "WARN", 8)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local freshInstall = not rootDisk:fileExists(".meta")
|
||||||
|
|
||||||
|
if freshInstall then
|
||||||
kernel.log("Seeding filesystem permissions...", "INFO")
|
kernel.log("Seeding filesystem permissions...", "INFO")
|
||||||
|
|
||||||
-- /
|
-- / (only on fresh install — these dirs are stable)
|
||||||
writeMeta("/", {
|
writeMeta("/", {
|
||||||
{"bin", REG, 0, 0, RWX_RX_RX},
|
{"bin", REG, 0, 0, RWX_RX_RX},
|
||||||
{"boot", REG, 0, 0, RWX_RX_RX},
|
{"boot", REG, 0, 0, RWX_RX_RX},
|
||||||
@@ -67,38 +165,10 @@ else
|
|||||||
{"var", REG, 0, 0, RWX_RX_RX},
|
{"var", REG, 0, 0, RWX_RX_RX},
|
||||||
})
|
})
|
||||||
|
|
||||||
-- /bin
|
|
||||||
writeMeta("/bin", {
|
|
||||||
{"cat", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"clear", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"echo", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"hfetch", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"hysh", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"hyshex", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"install", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"login", REG, 0, 0, SUID_755 },
|
|
||||||
{"ls", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"lua", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"luaold", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"mkdir", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"ps", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"pwd", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"spm", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"su", REG, 0, 0, SUID_755 },
|
|
||||||
{"sudo", REG, 0, 0, SUID_755 },
|
|
||||||
{"sysdump", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"whoami", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"yes", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"startup", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"ln", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"readlink", REG, 0, 0, RWX_RX_RX},
|
|
||||||
})
|
|
||||||
|
|
||||||
writeMeta("/bin/startup", {
|
writeMeta("/bin/startup", {
|
||||||
{"test.lua", REG, 0, 0, RWX_RX_RX},
|
{"test.lua", REG, 0, 0, RWX_RX_RX},
|
||||||
})
|
})
|
||||||
|
|
||||||
-- /etc
|
|
||||||
writeMeta("/etc", {
|
writeMeta("/etc", {
|
||||||
{"passwd", REG, 0, 0, RW_R_R},
|
{"passwd", REG, 0, 0, RW_R_R},
|
||||||
{"shadow", REG, 0, 0, RW____},
|
{"shadow", REG, 0, 0, RW____},
|
||||||
@@ -109,12 +179,10 @@ else
|
|||||||
{"secret", REG, 0, 0, RW____},
|
{"secret", REG, 0, 0, RW____},
|
||||||
})
|
})
|
||||||
|
|
||||||
-- /sbin
|
|
||||||
writeMeta("/sbin", {
|
writeMeta("/sbin", {
|
||||||
{"init.lua", REG, 0, 0, RWX_RX_RX},
|
{"init.lua", REG, 0, 0, RWX_RX_RX},
|
||||||
})
|
})
|
||||||
|
|
||||||
-- /boot
|
|
||||||
writeMeta("/boot", {
|
writeMeta("/boot", {
|
||||||
{"kernel.lua", REG, 0, 0, RW_R_R },
|
{"kernel.lua", REG, 0, 0, RW_R_R },
|
||||||
{"boot.cfg", REG, 0, 0, RW_R_R },
|
{"boot.cfg", REG, 0, 0, RW_R_R },
|
||||||
@@ -125,7 +193,6 @@ else
|
|||||||
{"oc", REG, 0, 0, RWX_RX_RX},
|
{"oc", REG, 0, 0, RWX_RX_RX},
|
||||||
})
|
})
|
||||||
|
|
||||||
-- /lib
|
|
||||||
writeMeta("/lib", {
|
writeMeta("/lib", {
|
||||||
{"sys", REG, 0, 0, RWX_RX_RX},
|
{"sys", REG, 0, 0, RWX_RX_RX},
|
||||||
{"modules", REG, 0, 0, RWX_RX_RX},
|
{"modules", REG, 0, 0, RWX_RX_RX},
|
||||||
@@ -137,6 +204,11 @@ else
|
|||||||
})
|
})
|
||||||
|
|
||||||
kernel.log("Filesystem permissions seeded.", "INFO")
|
kernel.log("Filesystem permissions seeded.", "INFO")
|
||||||
|
else
|
||||||
|
kernel.log("Permissions already seeded, merging /bin updates...", "INFO")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Always merge /bin — adds missing entries and upgrades format to v2
|
||||||
|
mergeMeta("/bin", BIN_ENTRIES)
|
||||||
|
|
||||||
kernel.log("Permission module loaded.", "INFO")
|
kernel.log("Permission module loaded.", "INFO")
|
||||||
|
|||||||
5
Src/Hyperion-kernel/lib/modules/Hyperion/99_final.kmod
Normal file
5
Src/Hyperion-kernel/lib/modules/Hyperion/99_final.kmod
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
local args = {...}
|
||||||
|
local kernel = args[1]
|
||||||
|
|
||||||
|
local origLoad = load
|
||||||
|
--kernel._U.load = function(a,b,c,d) return origLoad(a,b,c,d or kernel._U) end
|
||||||
Reference in New Issue
Block a user