diff --git a/Base/etc/passwd b/Base/etc/passwd index 8e7e246d64..987589b5e8 100644 --- a/Base/etc/passwd +++ b/Base/etc/passwd @@ -1,2 +1,3 @@ root:x:0:0:root:/:/bin/sh anon:x:100:100:Anonymous,,,:/home/anon:/bin/sh +nona:x:200:200:Nona,,,:/home/nona:/bin/sh diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index 75771d1a2b..eb4dbab2c4 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -411,6 +411,11 @@ int Process::do_exec(String path, Vector arguments, Vector envir m_initial_arguments = move(arguments); m_initial_environment = move(environment); + if (descriptor->metadata().is_setuid()) + m_euid = descriptor->metadata().uid; + if (descriptor->metadata().is_setgid()) + m_egid = descriptor->metadata().gid; + #ifdef TASK_DEBUG kprintf("Process %u (%s) exec'd %s @ %p\n", pid(), name().characters(), path.characters(), m_tss.eip); #endif @@ -1352,14 +1357,22 @@ int Process::sys$killpg(int pgrp, int signum) ASSERT_NOT_REACHED(); } -int Process::sys$setuid(uid_t) +int Process::sys$setuid(uid_t uid) { - ASSERT_NOT_REACHED(); + if (uid != m_uid && !is_superuser()) + return -EPERM; + m_uid = uid; + m_euid = uid; + return 0; } -int Process::sys$setgid(gid_t) +int Process::sys$setgid(gid_t gid) { - ASSERT_NOT_REACHED(); + if (gid != m_gid && !is_superuser()) + return -EPERM; + m_gid = gid; + m_egid = gid; + return 0; } unsigned Process::sys$alarm(unsigned seconds) @@ -1900,7 +1913,7 @@ int Process::sys$getgroups(int count, gid_t* gids) int Process::sys$setgroups(size_t count, const gid_t* gids) { - if (!is_root()) + if (!is_superuser()) return -EPERM; if (count >= MAX_PROCESS_GIDS) return -EINVAL; diff --git a/Kernel/Process.h b/Kernel/Process.h index 2ecd3faf8f..71b69253f3 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -283,7 +283,7 @@ public: Process* fork(RegisterDump&); int exec(String path, Vector arguments, Vector environment); - bool is_root() const { return m_euid == 0; } + bool is_superuser() const { return m_euid == 0; } bool wakeup_requested() { return m_wakeup_requested; } void request_wakeup() { m_wakeup_requested = true; } diff --git a/Kernel/sync.sh b/Kernel/sync.sh index 6127135904..1328ad7ba3 100755 --- a/Kernel/sync.sh +++ b/Kernel/sync.sh @@ -32,7 +32,10 @@ ln -s /proc/self/fd/0 mnt/dev/stdin ln -s /proc/self/fd/1 mnt/dev/stdout ln -s /proc/self/fd/2 mnt/dev/stderr cp -vR ../Base/* mnt/ +mkdir mnt/home/anon +mkdir mnt/home/nona chown -vR 100:100 mnt/home/anon +chown -vR 200:200 mnt/home/nona cp -v ../Userland/sh mnt/bin/sh cp -v ../Userland/id mnt/bin/id cp -v ../Userland/ps mnt/bin/ps @@ -65,6 +68,8 @@ cp -v ../Userland/chmod mnt/bin/chmod cp -v ../Userland/top mnt/bin/top cp -v ../Userland/ln mnt/bin/ln cp -v ../Userland/df mnt/bin/df +cp -v ../Userland/su mnt/bin/su +chmod 4755 mnt/bin/su cp -v ../Applications/Terminal/Terminal mnt/bin/Terminal cp -v ../Applications/FontEditor/FontEditor mnt/bin/FontEditor cp -v ../Applications/Launcher/Launcher mnt/bin/Launcher diff --git a/LibC/unistd.h b/LibC/unistd.h index 5ec0d04ca7..35c1c7a755 100644 --- a/LibC/unistd.h +++ b/LibC/unistd.h @@ -31,6 +31,8 @@ gid_t getgid(); pid_t getpid(); int getgroups(int size, gid_t list[]); int setgroups(size_t, const gid_t*); +int setuid(uid_t); +int setgid(gid_t); pid_t tcgetpgrp(int fd); int tcsetpgrp(int fd, pid_t pgid); int open(const char* path, int options, ...); diff --git a/Userland/.gitignore b/Userland/.gitignore index 45015daa24..53b51e01f4 100644 --- a/Userland/.gitignore +++ b/Userland/.gitignore @@ -33,3 +33,4 @@ chmod pape ln df +su diff --git a/Userland/Makefile b/Userland/Makefile index 7232c194e4..76a1f97720 100644 --- a/Userland/Makefile +++ b/Userland/Makefile @@ -29,6 +29,7 @@ OBJS = \ top.o \ df.o \ ln.o \ + su.o \ rm.o APPS = \ @@ -63,6 +64,7 @@ APPS = \ top \ ln \ df \ + su \ rm ARCH_FLAGS = @@ -179,6 +181,9 @@ ln: ln.o df: df.o $(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a +su: su.o + $(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a + .cpp.o: @echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $< diff --git a/Userland/ls.cpp b/Userland/ls.cpp index 1d92a56068..7ff875967b 100644 --- a/Userland/ls.cpp +++ b/Userland/ls.cpp @@ -148,10 +148,10 @@ int do_dir(const char* path) printf("%c%c%c%c%c%c%c%c", st.st_mode & S_IRUSR ? 'r' : '-', st.st_mode & S_IWUSR ? 'w' : '-', - st.st_mode & S_IXUSR ? 'x' : '-', + st.st_mode & S_ISUID ? 's' : (st.st_mode & S_IXUSR ? 'x' : '-'), st.st_mode & S_IRGRP ? 'r' : '-', st.st_mode & S_IWGRP ? 'w' : '-', - st.st_mode & S_IXGRP ? 'x' : '-', + st.st_mode & S_ISGID ? 's' : (st.st_mode & S_IXGRP ? 'x' : '-'), st.st_mode & S_IROTH ? 'r' : '-', st.st_mode & S_IWOTH ? 'w' : '-' ); diff --git a/Userland/su.cpp b/Userland/su.cpp new file mode 100644 index 0000000000..51ee60729b --- /dev/null +++ b/Userland/su.cpp @@ -0,0 +1,44 @@ +#include +#include +#include +#include +#include + +extern "C" int main(int, char**); + +int main(int argc, char** argv) +{ + uid_t uid; + gid_t gid; + if (argc == 1) { + uid = 0; + gid = 0; + } else { + auto* pwd = getpwnam(argv[1]); + if (!pwd) { + fprintf(stderr, "No such user: %s\n", argv[1]); + return 1; + } + uid = pwd->pw_uid; + gid = pwd->pw_gid; + } + + int rc = setgid(uid); + if (rc < 0) { + perror("setgid"); + return 1; + } + + rc = setuid(gid); + if (rc < 0) { + perror("setuid"); + return 1; + } + + rc = execl("/bin/sh", "sh", nullptr); + if (rc < 0) { + perror("execl"); + return 1; + } + return 0; +}