mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 07:38:10 +00:00
Add chown() syscall and a simple /bin/chown program.
This commit is contained in:
parent
711e2b2651
commit
1d2529b4a1
19 changed files with 130 additions and 5 deletions
|
@ -1346,6 +1346,17 @@ KResult Ext2FSInode::chmod(mode_t mode)
|
||||||
return KSuccess;
|
return KSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KResult Ext2FSInode::chown(uid_t uid, gid_t gid)
|
||||||
|
{
|
||||||
|
LOCKER(m_lock);
|
||||||
|
if (m_raw_inode.i_uid == uid && m_raw_inode.i_gid == gid)
|
||||||
|
return KSuccess;
|
||||||
|
m_raw_inode.i_uid = uid;
|
||||||
|
m_raw_inode.i_gid = gid;
|
||||||
|
set_metadata_dirty(true);
|
||||||
|
return KSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned Ext2FS::total_block_count() const
|
unsigned Ext2FS::total_block_count() const
|
||||||
{
|
{
|
||||||
LOCKER(m_lock);
|
LOCKER(m_lock);
|
||||||
|
|
|
@ -42,6 +42,7 @@ private:
|
||||||
virtual int decrement_link_count() override;
|
virtual int decrement_link_count() override;
|
||||||
virtual size_t directory_entry_count() const override;
|
virtual size_t directory_entry_count() const override;
|
||||||
virtual KResult chmod(mode_t) override;
|
virtual KResult chmod(mode_t) override;
|
||||||
|
virtual KResult chown(uid_t, gid_t) override;
|
||||||
|
|
||||||
void populate_lookup_cache() const;
|
void populate_lookup_cache() const;
|
||||||
|
|
||||||
|
|
|
@ -98,6 +98,7 @@ public:
|
||||||
virtual RetainPtr<Inode> parent() const = 0;
|
virtual RetainPtr<Inode> parent() const = 0;
|
||||||
virtual size_t directory_entry_count() const = 0;
|
virtual size_t directory_entry_count() const = 0;
|
||||||
virtual KResult chmod(mode_t) = 0;
|
virtual KResult chmod(mode_t) = 0;
|
||||||
|
virtual KResult chown(uid_t, gid_t) = 0;
|
||||||
|
|
||||||
LocalSocket* socket() { return m_socket.ptr(); }
|
LocalSocket* socket() { return m_socket.ptr(); }
|
||||||
const LocalSocket* socket() const { return m_socket.ptr(); }
|
const LocalSocket* socket() const { return m_socket.ptr(); }
|
||||||
|
|
|
@ -1124,3 +1124,8 @@ ProcFS::ProcFSDirectoryEntry* ProcFS::get_directory_entry(InodeIdentifier identi
|
||||||
return const_cast<ProcFSDirectoryEntry*>(&m_entries[proc_file_type]);
|
return const_cast<ProcFSDirectoryEntry*>(&m_entries[proc_file_type]);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KResult ProcFSInode::chown(uid_t, gid_t)
|
||||||
|
{
|
||||||
|
return KResult(-EPERM);
|
||||||
|
}
|
||||||
|
|
|
@ -88,6 +88,7 @@ private:
|
||||||
virtual RetainPtr<Inode> parent() const override;
|
virtual RetainPtr<Inode> parent() const override;
|
||||||
virtual size_t directory_entry_count() const override;
|
virtual size_t directory_entry_count() const override;
|
||||||
virtual KResult chmod(mode_t) override;
|
virtual KResult chmod(mode_t) override;
|
||||||
|
virtual KResult chown(uid_t, gid_t) override;
|
||||||
|
|
||||||
ProcFS& fs() { return static_cast<ProcFS&>(Inode::fs()); }
|
ProcFS& fs() { return static_cast<ProcFS&>(Inode::fs()); }
|
||||||
const ProcFS& fs() const { return static_cast<const ProcFS&>(Inode::fs()); }
|
const ProcFS& fs() const { return static_cast<const ProcFS&>(Inode::fs()); }
|
||||||
|
|
|
@ -72,6 +72,11 @@ Vector<Process*> Process::all_processes()
|
||||||
return processes;
|
return processes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Process::in_group(gid_t gid) const
|
||||||
|
{
|
||||||
|
return m_gids.contains(gid);
|
||||||
|
}
|
||||||
|
|
||||||
Region* Process::allocate_region(LinearAddress laddr, size_t size, String&& name, bool is_readable, bool is_writable, bool commit)
|
Region* Process::allocate_region(LinearAddress laddr, size_t size, String&& name, bool is_readable, bool is_writable, bool commit)
|
||||||
{
|
{
|
||||||
size = PAGE_ROUND_UP(size);
|
size = PAGE_ROUND_UP(size);
|
||||||
|
@ -2157,6 +2162,13 @@ int Process::sys$chmod(const char* pathname, mode_t mode)
|
||||||
return VFS::the().chmod(String(pathname), mode, cwd_inode());
|
return VFS::the().chmod(String(pathname), mode, cwd_inode());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Process::sys$chown(const char* pathname, uid_t uid, gid_t gid)
|
||||||
|
{
|
||||||
|
if (!validate_read_str(pathname))
|
||||||
|
return -EFAULT;
|
||||||
|
return VFS::the().chown(String(pathname), uid, gid, cwd_inode());
|
||||||
|
}
|
||||||
|
|
||||||
void Process::finalize()
|
void Process::finalize()
|
||||||
{
|
{
|
||||||
ASSERT(current == g_finalizer);
|
ASSERT(current == g_finalizer);
|
||||||
|
|
|
@ -122,6 +122,8 @@ public:
|
||||||
|
|
||||||
mode_t umask() const { return m_umask; }
|
mode_t umask() const { return m_umask; }
|
||||||
|
|
||||||
|
bool in_group(gid_t) const;
|
||||||
|
|
||||||
const FarPtr& far_ptr() const { return m_far_ptr; }
|
const FarPtr& far_ptr() const { return m_far_ptr; }
|
||||||
|
|
||||||
FileDescriptor* file_descriptor(int fd);
|
FileDescriptor* file_descriptor(int fd);
|
||||||
|
@ -216,6 +218,7 @@ public:
|
||||||
int sys$rmdir(const char* pathname);
|
int sys$rmdir(const char* pathname);
|
||||||
int sys$read_tsc(dword* lsw, dword* msw);
|
int sys$read_tsc(dword* lsw, dword* msw);
|
||||||
int sys$chmod(const char* pathname, mode_t);
|
int sys$chmod(const char* pathname, mode_t);
|
||||||
|
int sys$chown(const char* pathname, uid_t, gid_t);
|
||||||
int sys$socket(int domain, int type, int protocol);
|
int sys$socket(int domain, int type, int protocol);
|
||||||
int sys$bind(int sockfd, const sockaddr* addr, socklen_t);
|
int sys$bind(int sockfd, const sockaddr* addr, socklen_t);
|
||||||
int sys$listen(int sockfd, int backlog);
|
int sys$listen(int sockfd, int backlog);
|
||||||
|
|
|
@ -314,3 +314,8 @@ KResult SynthFSInode::chmod(mode_t)
|
||||||
{
|
{
|
||||||
return KResult(-EPERM);
|
return KResult(-EPERM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KResult SynthFSInode::chown(uid_t, gid_t)
|
||||||
|
{
|
||||||
|
return KResult(-EPERM);
|
||||||
|
}
|
||||||
|
|
|
@ -68,6 +68,7 @@ private:
|
||||||
virtual RetainPtr<Inode> parent() const override;
|
virtual RetainPtr<Inode> parent() const override;
|
||||||
virtual size_t directory_entry_count() const override;
|
virtual size_t directory_entry_count() const override;
|
||||||
virtual KResult chmod(mode_t) override;
|
virtual KResult chmod(mode_t) override;
|
||||||
|
virtual KResult chown(uid_t, gid_t) override;
|
||||||
|
|
||||||
SynthFS& fs();
|
SynthFS& fs();
|
||||||
const SynthFS& fs() const;
|
const SynthFS& fs() const;
|
||||||
|
|
|
@ -215,6 +215,8 @@ static dword handle(RegisterDump& regs, dword function, dword arg1, dword arg2,
|
||||||
return (dword)current->sys$get_shared_buffer((int)arg1);
|
return (dword)current->sys$get_shared_buffer((int)arg1);
|
||||||
case Syscall::SC_release_shared_buffer:
|
case Syscall::SC_release_shared_buffer:
|
||||||
return current->sys$release_shared_buffer((int)arg1);
|
return current->sys$release_shared_buffer((int)arg1);
|
||||||
|
case Syscall::SC_chown:
|
||||||
|
return current->sys$chown((const char*)arg1, (uid_t)arg2, (gid_t)arg3);
|
||||||
default:
|
default:
|
||||||
kprintf("<%u> int0x80: Unknown function %u requested {%x, %x, %x}\n", current->pid(), function, arg1, arg2, arg3);
|
kprintf("<%u> int0x80: Unknown function %u requested {%x, %x, %x}\n", current->pid(), function, arg1, arg2, arg3);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -82,6 +82,7 @@
|
||||||
__ENUMERATE_SYSCALL(get_shared_buffer) \
|
__ENUMERATE_SYSCALL(get_shared_buffer) \
|
||||||
__ENUMERATE_SYSCALL(release_shared_buffer) \
|
__ENUMERATE_SYSCALL(release_shared_buffer) \
|
||||||
__ENUMERATE_SYSCALL(link) \
|
__ENUMERATE_SYSCALL(link) \
|
||||||
|
__ENUMERATE_SYSCALL(chown) \
|
||||||
|
|
||||||
|
|
||||||
namespace Syscall {
|
namespace Syscall {
|
||||||
|
|
|
@ -300,6 +300,7 @@ KResult VFS::chmod(const String& path, mode_t mode, Inode& base)
|
||||||
if (inode->fs().is_readonly())
|
if (inode->fs().is_readonly())
|
||||||
return KResult(-EROFS);
|
return KResult(-EROFS);
|
||||||
|
|
||||||
|
// FIXME: Superuser should always be allowed to chmod.
|
||||||
if (current->euid() != inode->metadata().uid)
|
if (current->euid() != inode->metadata().uid)
|
||||||
return KResult(-EPERM);
|
return KResult(-EPERM);
|
||||||
|
|
||||||
|
@ -310,6 +311,37 @@ KResult VFS::chmod(const String& path, mode_t mode, Inode& base)
|
||||||
return inode->chmod(mode);
|
return inode->chmod(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KResult VFS::chown(const String& path, uid_t a_uid, gid_t a_gid, Inode& base)
|
||||||
|
{
|
||||||
|
auto inode_or_error = resolve_path_to_inode(path, base);
|
||||||
|
if (inode_or_error.is_error())
|
||||||
|
return inode_or_error.error();
|
||||||
|
auto inode = inode_or_error.value();
|
||||||
|
|
||||||
|
if (inode->fs().is_readonly())
|
||||||
|
return KResult(-EROFS);
|
||||||
|
|
||||||
|
if (current->euid() != inode->metadata().uid && !current->is_superuser())
|
||||||
|
return KResult(-EPERM);
|
||||||
|
|
||||||
|
uid_t new_uid = inode->metadata().uid;
|
||||||
|
gid_t new_gid = inode->metadata().gid;
|
||||||
|
|
||||||
|
if (a_uid != (uid_t)-1) {
|
||||||
|
if (current->euid() != a_uid && !current->is_superuser())
|
||||||
|
return KResult(-EPERM);
|
||||||
|
new_uid = a_uid;
|
||||||
|
}
|
||||||
|
if (a_gid != (gid_t)-1) {
|
||||||
|
if (!current->in_group(a_gid) && !current->is_superuser())
|
||||||
|
return KResult(-EPERM);
|
||||||
|
new_gid = a_gid;
|
||||||
|
}
|
||||||
|
|
||||||
|
dbgprintf("VFS::chown(): inode %u:%u <- uid:%d, gid:%d\n", inode->fsid(), inode->index(), new_uid, new_gid);
|
||||||
|
return inode->chown(new_uid, new_gid);
|
||||||
|
}
|
||||||
|
|
||||||
KResultOr<RetainPtr<Inode>> VFS::resolve_path_to_inode(const String& path, Inode& base, RetainPtr<Inode>* parent_inode)
|
KResultOr<RetainPtr<Inode>> VFS::resolve_path_to_inode(const String& path, Inode& base, RetainPtr<Inode>* parent_inode)
|
||||||
{
|
{
|
||||||
// FIXME: This won't work nicely across mount boundaries.
|
// FIXME: This won't work nicely across mount boundaries.
|
||||||
|
|
|
@ -70,6 +70,7 @@ public:
|
||||||
bool unlink(const String& path, Inode& base, int& error);
|
bool unlink(const String& path, Inode& base, int& error);
|
||||||
bool rmdir(const String& path, Inode& base, int& error);
|
bool rmdir(const String& path, Inode& base, int& error);
|
||||||
KResult chmod(const String& path, mode_t, Inode& base);
|
KResult chmod(const String& path, mode_t, Inode& base);
|
||||||
|
KResult chown(const String& path, uid_t, gid_t, Inode& base);
|
||||||
KResult access(const String& path, int mode, Inode& base);
|
KResult access(const String& path, int mode, Inode& base);
|
||||||
bool stat(const String& path, int& error, int options, Inode& base, struct stat&);
|
bool stat(const String& path, int& error, int options, Inode& base, struct stat&);
|
||||||
KResult utime(const String& path, Inode& base, time_t atime, time_t mtime);
|
KResult utime(const String& path, Inode& base, time_t atime, time_t mtime);
|
||||||
|
|
|
@ -66,6 +66,7 @@ cp -v ../Userland/sysctl mnt/bin/sysctl
|
||||||
cp -v ../Userland/pape mnt/bin/pape
|
cp -v ../Userland/pape mnt/bin/pape
|
||||||
cp -v ../Userland/dmesg mnt/bin/dmesg
|
cp -v ../Userland/dmesg mnt/bin/dmesg
|
||||||
cp -v ../Userland/chmod mnt/bin/chmod
|
cp -v ../Userland/chmod mnt/bin/chmod
|
||||||
|
cp -v ../Userland/chown mnt/bin/chown
|
||||||
cp -v ../Userland/top mnt/bin/top
|
cp -v ../Userland/top mnt/bin/top
|
||||||
cp -v ../Userland/ln mnt/bin/ln
|
cp -v ../Userland/ln mnt/bin/ln
|
||||||
cp -v ../Userland/df mnt/bin/df
|
cp -v ../Userland/df mnt/bin/df
|
||||||
|
|
|
@ -14,12 +14,10 @@
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
int chown(const char* pathname, uid_t owner, gid_t group)
|
int chown(const char* pathname, uid_t uid, gid_t gid)
|
||||||
{
|
{
|
||||||
(void)pathname;
|
int rc = syscall(SC_chown, pathname, uid, gid);
|
||||||
(void)owner;
|
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||||
(void)group;
|
|
||||||
assert(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pid_t fork()
|
pid_t fork()
|
||||||
|
|
|
@ -74,6 +74,7 @@ int mknod(const char* pathname, mode_t, dev_t);
|
||||||
long fpathconf(int fd, int name);
|
long fpathconf(int fd, int name);
|
||||||
long pathconf(const char *path, int name);
|
long pathconf(const char *path, int name);
|
||||||
char* getlogin();
|
char* getlogin();
|
||||||
|
int chown(const char* pathname, uid_t, gid_t);
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
_PC_NAME_MAX,
|
_PC_NAME_MAX,
|
||||||
|
|
1
Userland/.gitignore
vendored
1
Userland/.gitignore
vendored
|
@ -35,3 +35,4 @@ ln
|
||||||
df
|
df
|
||||||
su
|
su
|
||||||
env
|
env
|
||||||
|
chown
|
||||||
|
|
|
@ -26,6 +26,7 @@ OBJS = \
|
||||||
rmdir.o \
|
rmdir.o \
|
||||||
dmesg.o \
|
dmesg.o \
|
||||||
chmod.o \
|
chmod.o \
|
||||||
|
chown.o \
|
||||||
top.o \
|
top.o \
|
||||||
df.o \
|
df.o \
|
||||||
ln.o \
|
ln.o \
|
||||||
|
@ -62,6 +63,7 @@ APPS = \
|
||||||
rmdir \
|
rmdir \
|
||||||
dmesg \
|
dmesg \
|
||||||
chmod \
|
chmod \
|
||||||
|
chown \
|
||||||
top \
|
top \
|
||||||
ln \
|
ln \
|
||||||
df \
|
df \
|
||||||
|
@ -173,6 +175,9 @@ rmdir: rmdir.o
|
||||||
chmod: chmod.o
|
chmod: chmod.o
|
||||||
$(LD) -o $@ $(LDFLAGS) $< -lc
|
$(LD) -o $@ $(LDFLAGS) $< -lc
|
||||||
|
|
||||||
|
chown: chown.o
|
||||||
|
$(LD) -o $@ $(LDFLAGS) $< -lc
|
||||||
|
|
||||||
top: top.o
|
top: top.o
|
||||||
$(LD) -o $@ $(LDFLAGS) $< -lc
|
$(LD) -o $@ $(LDFLAGS) $< -lc
|
||||||
|
|
||||||
|
|
43
Userland/chown.cpp
Normal file
43
Userland/chown.cpp
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <AK/AKString.h>
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
if (argc < 2) {
|
||||||
|
printf("usage: chown <uid[:gid]> <path>\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uid_t new_uid = -1;
|
||||||
|
gid_t new_gid = -1;
|
||||||
|
|
||||||
|
auto parts = String(argv[1]).split(':');
|
||||||
|
if (parts.is_empty()) {
|
||||||
|
fprintf(stderr, "Empty uid/gid spec\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
bool ok;
|
||||||
|
new_uid = parts[0].to_uint(ok);
|
||||||
|
if (!ok) {
|
||||||
|
fprintf(stderr, "Invalid uid: '%s'\n", parts[0].characters());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (parts.size() == 2) {
|
||||||
|
new_gid = parts[1].to_uint(ok);
|
||||||
|
if (!ok) {
|
||||||
|
fprintf(stderr, "Invalid gid: '%s'\n", parts[1].characters());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int rc = chown(argv[2], new_uid, new_gid);
|
||||||
|
if (rc < 0) {
|
||||||
|
perror("chown");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue