forked from Hyperion/HyperionOS
/home/user owned by user, user starts in cwd /home/user
This commit is contained in:
@@ -64,12 +64,18 @@ local newGid = resolveGid(groupStr)
|
||||
local function chgrpPath(path)
|
||||
local stat = syscall.stat(path)
|
||||
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
|
||||
end
|
||||
local ok, err = pcall(syscall.chown, path, stat.owner, newGid)
|
||||
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
|
||||
end
|
||||
return true
|
||||
|
||||
@@ -220,7 +220,13 @@ local function chmodPath(path)
|
||||
|
||||
local ok, cerr = pcall(syscall.chmod, path, newPerms)
|
||||
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
|
||||
end
|
||||
return true
|
||||
|
||||
@@ -95,14 +95,20 @@ end
|
||||
local function chownPath(path)
|
||||
local stat = syscall.stat(path)
|
||||
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
|
||||
end
|
||||
local uid = newUid ~= nil and newUid or stat.owner
|
||||
local gid = newGid ~= nil and newGid or stat.group
|
||||
local ok, err = pcall(syscall.chown, path, uid, gid)
|
||||
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
|
||||
end
|
||||
return true
|
||||
|
||||
@@ -17,7 +17,13 @@ local commandHistory = {}
|
||||
local terminate = false
|
||||
syscall.setEnviron("SHELL","rtbash")
|
||||
syscall.setEnviron("PATH","/bin/")
|
||||
syscall.chdir("/")
|
||||
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("/")
|
||||
end
|
||||
local oldWD = ""
|
||||
|
||||
for i = 1, 16 do
|
||||
|
||||
@@ -96,6 +96,9 @@ local function spawnShell(username, uid, shell, homedir)
|
||||
end
|
||||
|
||||
local chdirOk, chdirErr = pcall(syscall.chdir, homedir)
|
||||
if not chdirOk then
|
||||
pcall(syscall.chdir, "/")
|
||||
end
|
||||
|
||||
local ok, err = pcall(syscall.execspawn, shell, username .. ":shell")
|
||||
if not ok then
|
||||
|
||||
@@ -14,6 +14,9 @@ for i,v in pairs(kernel.processes) do
|
||||
end, i)
|
||||
end
|
||||
|
||||
if not fs.exists("/bin/startup") then
|
||||
fs.mkdir("/bin/startup")
|
||||
end
|
||||
local files = fs.list("/bin/startup")
|
||||
if not files then error("Failed to list /bin/startup") end
|
||||
for i,v in ipairs(files) do
|
||||
|
||||
@@ -164,6 +164,9 @@ local function resolveMount(normalPath)
|
||||
return vfs.disks[mountId], diskPath
|
||||
end
|
||||
|
||||
-- Expose parser for use by other modules (e.g. permissions seeder)
|
||||
vfs._parseMetafile = parseMetafile
|
||||
|
||||
local function readMetaEntry(disk, parentDiskPath, filename)
|
||||
if filename == ".meta" then error("Cannot open metafile") end
|
||||
local mp
|
||||
@@ -177,6 +180,15 @@ local function readMetaEntry(disk, parentDiskPath, filename)
|
||||
if not ok or not f then return nil end
|
||||
local raw = f.read(65535)
|
||||
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)
|
||||
return parsed[filename]
|
||||
end
|
||||
@@ -418,6 +430,8 @@ function vfs.open(path, mode)
|
||||
if not disk then error("NODISK") end
|
||||
|
||||
local meta = getFileMeta(path)
|
||||
local isNew = (mode == "w" or mode == "a") and not disk:fileExists(diskPath)
|
||||
|
||||
checkperms(meta, mode == "r" and "r" or "w")
|
||||
|
||||
local handle
|
||||
@@ -426,6 +440,22 @@ function vfs.open(path, mode)
|
||||
if type(handle) ~= "table" then error("ENFILE") 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))
|
||||
if mode == "r" and bit_is_set(meta.perms, 6) then
|
||||
fobj.suid_owner = meta.owner
|
||||
@@ -592,15 +622,33 @@ function vfs.listdir(path)
|
||||
end
|
||||
|
||||
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 meta = getFileMeta(path)
|
||||
checkperms(meta, "w")
|
||||
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
|
||||
|
||||
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)
|
||||
checkperms(meta, "w")
|
||||
|
||||
if kernel.unixSockets and kernel.unixSockets[path] then
|
||||
kernel.unixSockets[path] = nil
|
||||
|
||||
@@ -50,10 +50,10 @@ local function readonly(tbl)
|
||||
__metatable = false
|
||||
})
|
||||
end
|
||||
local origLoad = load
|
||||
--local origLoad = load
|
||||
|
||||
kernel._U = readonly(kernel._G)
|
||||
kernel.allowGlobalOverwrites = true
|
||||
kernel._U._G = kernel._U
|
||||
kernel._U.load = function(a,b,c,d) return origLoad(a,b,c,d or kernel._U) end
|
||||
--kernel._U.load = function(a,b,c,d) return origLoad(a,b,c,d or kernel._U) end
|
||||
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
|
||||
kernel.vfs.mkdir(homedir)
|
||||
-- Homedir must be owned by the new user, not root
|
||||
pcall(kernel.vfs.chown, homedir, uid, uid)
|
||||
end
|
||||
|
||||
kernel.log("AUTH: new user '" .. username .. "' uid=" .. tostring(uid))
|
||||
|
||||
@@ -51,12 +51,106 @@ end
|
||||
|
||||
local REG = 0x00
|
||||
|
||||
if rootDisk:fileExists(".meta") then
|
||||
kernel.log("Permissions already seeded, skipping.", "INFO")
|
||||
else
|
||||
-- All known /bin entries with their permissions
|
||||
local BIN_ENTRIES = {
|
||||
{"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")
|
||||
|
||||
-- /
|
||||
-- / (only on fresh install — these dirs are stable)
|
||||
writeMeta("/", {
|
||||
{"bin", REG, 0, 0, RWX_RX_RX},
|
||||
{"boot", REG, 0, 0, RWX_RX_RX},
|
||||
@@ -71,38 +165,10 @@ else
|
||||
{"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", {
|
||||
{"test.lua", REG, 0, 0, RWX_RX_RX},
|
||||
})
|
||||
|
||||
-- /etc
|
||||
writeMeta("/etc", {
|
||||
{"passwd", REG, 0, 0, RW_R_R},
|
||||
{"shadow", REG, 0, 0, RW____},
|
||||
@@ -113,12 +179,10 @@ else
|
||||
{"secret", REG, 0, 0, RW____},
|
||||
})
|
||||
|
||||
-- /sbin
|
||||
writeMeta("/sbin", {
|
||||
{"init.lua", REG, 0, 0, RWX_RX_RX},
|
||||
})
|
||||
|
||||
-- /boot
|
||||
writeMeta("/boot", {
|
||||
{"kernel.lua", REG, 0, 0, RW_R_R },
|
||||
{"boot.cfg", REG, 0, 0, RW_R_R },
|
||||
@@ -129,7 +193,6 @@ else
|
||||
{"oc", REG, 0, 0, RWX_RX_RX},
|
||||
})
|
||||
|
||||
-- /lib
|
||||
writeMeta("/lib", {
|
||||
{"sys", REG, 0, 0, RWX_RX_RX},
|
||||
{"modules", REG, 0, 0, RWX_RX_RX},
|
||||
@@ -141,6 +204,11 @@ else
|
||||
})
|
||||
|
||||
kernel.log("Filesystem permissions seeded.", "INFO")
|
||||
else
|
||||
kernel.log("Permissions already seeded, merging /bin updates...", "INFO")
|
||||
end
|
||||
|
||||
-- Always merge /bin — adds missing entries and upgrades format to v2
|
||||
mergeMeta("/bin", BIN_ENTRIES)
|
||||
|
||||
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