From a77c3dffd05a904eb67251c731d9168005908ebe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josef=20S=C3=B6ntgen?= Date: Mon, 20 Aug 2012 18:24:11 +0200 Subject: [PATCH] Noux: add user information support (struct passwd) There are certain programs which need the information that is stored in 'struct passwd'. This commit introduces configurable user information support to NOUX. One can set the user information via in NOUX config: ! ! ! ! ! ! [...] ! When is not specified default values are used. Currently these are 'root', 0, 0, '/bin/bash', '/'. Note: this is just a single user implementation because each Noux instance has only one user or rather one identity and there will be no complete multi-user support in Noux. If you need different users, just start new Noux instances for each of them. --- ports/include/noux_session/noux_session.h | 2 + ports/include/noux_session/sysio.h | 16 +++++ ports/src/lib/libc_noux/plugin.cc | 80 +++++++++++++++++++++++ ports/src/noux/child.h | 6 ++ ports/src/noux/main.cc | 43 ++++++++++++ ports/src/noux/net/net.cc | 1 + ports/src/noux/user_info.h | 78 ++++++++++++++++++++++ 7 files changed, 226 insertions(+) create mode 100644 ports/src/noux/user_info.h diff --git a/ports/include/noux_session/noux_session.h b/ports/include/noux_session/noux_session.h index 2272702b27..33d5397800 100644 --- a/ports/include/noux_session/noux_session.h +++ b/ports/include/noux_session/noux_session.h @@ -72,6 +72,7 @@ namespace Noux { SYSCALL_SHUTDOWN, SYSCALL_CONNECT, SYSCALL_GETADDRINFO, + SYSCALL_USERINFO, SYSCALL_INVALID = -1 }; @@ -116,6 +117,7 @@ namespace Noux { NOUX_DECL_SYSCALL_NAME(SHUTDOWN) NOUX_DECL_SYSCALL_NAME(CONNECT) NOUX_DECL_SYSCALL_NAME(GETADDRINFO) + NOUX_DECL_SYSCALL_NAME(USERINFO) case SYSCALL_INVALID: return 0; } return 0; diff --git a/ports/include/noux_session/sysio.h b/ports/include/noux_session/sysio.h index 0c145b0078..dbeedd0484 100644 --- a/ports/include/noux_session/sysio.h +++ b/ports/include/noux_session/sysio.h @@ -271,6 +271,18 @@ namespace Noux { char ai_canonname[255]; }; + /** + * user info defintions + */ + enum { USERINFO_GET_ALL = 0, USERINFO_GET_UID, USERINFO_GET_GID }; + enum { MAX_USERNAME_LEN = 32 }; + typedef char User[MAX_USERNAME_LEN]; + enum { MAX_SHELL_LEN = 16 }; + typedef char Shell[MAX_SHELL_LEN]; + enum { MAX_HOME_LEN = 128 }; + typedef char Home[MAX_HOME_LEN]; + typedef unsigned int Uid; + enum General_error { ERR_FD_INVALID, NUM_GENERAL_ERRORS }; enum Stat_error { STAT_ERR_NO_ENTRY = NUM_GENERAL_ERRORS }; enum Fchdir_error { FCHDIR_ERR_NOT_DIR = NUM_GENERAL_ERRORS }; @@ -400,6 +412,10 @@ namespace Noux { Addrinfo hints; Addrinfo res[MAX_ADDRINFO_RESULTS]; }, { int addr_num; }); + + SYSIO_DECL(userinfo, { int request; Uid uid; }, + { User name; Uid uid; Uid gid; Shell shell; + Home home; }); }; }; }; diff --git a/ports/src/lib/libc_noux/plugin.cc b/ports/src/lib/libc_noux/plugin.cc index 73beb12fb8..eb480e1e4d 100644 --- a/ports/src/lib/libc_noux/plugin.cc +++ b/ports/src/lib/libc_noux/plugin.cc @@ -37,6 +37,7 @@ #include #include #include +#include /* libc-internal includes */ #include @@ -93,6 +94,85 @@ enum { FS_BLOCK_SIZE = 1024 }; ** Overrides of libc default implementations ** ***********************************************/ +/** + * User information related functions + */ +extern "C" struct passwd *getpwuid(uid_t uid) +{ + static char name[Noux::Sysio::MAX_USERNAME_LEN]; + static char shell[Noux::Sysio::MAX_SHELL_LEN]; + static char home[Noux::Sysio::MAX_HOME_LEN]; + + static struct passwd pw = { + /* .pw_name = */ name, + /* .pw_passwd = */ "", + /* .pw_uid = */ 0, + /* .pw_gid = */ 0, + /* .pw_change = */ 0, + /* .pw_class = */ "", + /* .pw_gecos = */ "", + /* .pw_dir = */ home, + /* .pw_shell = */ shell, + /* .pw_expire = */ 0, + /* .pw_fields = */ 0 + }; + + sysio()->userinfo_in.uid = uid; + sysio()->userinfo_in.request = Noux::Sysio::USERINFO_GET_ALL; + + if (!noux()->syscall(Noux::Session::SYSCALL_USERINFO)) { + return (struct passwd *)0; + } + + /* SYSCALL_USERINFO assures that strings are always '\0' terminated */ + Genode::memcpy(name, sysio()->userinfo_out.name, sizeof (sysio()->userinfo_out.name)); + Genode::memcpy(home, sysio()->userinfo_out.home, sizeof (sysio()->userinfo_out.home)); + Genode::memcpy(shell, sysio()->userinfo_out.shell, sizeof (sysio()->userinfo_out.shell)); + + pw.pw_uid = sysio()->userinfo_out.uid; + pw.pw_gid = sysio()->userinfo_out.gid; + + return &pw; +} + + +extern "C" uid_t getgid() +{ + sysio()->userinfo_in.request = Noux::Sysio::USERINFO_GET_GID; + + if (!noux()->syscall(Noux::Session::SYSCALL_USERINFO)) + return 0; + + uid_t gid = sysio()->userinfo_out.gid; + return gid; +} + + +extern "C" uid_t getegid() +{ + return getgid(); +} + + +extern "C" uid_t getuid() +{ + sysio()->userinfo_in.request = Noux::Sysio::USERINFO_GET_UID; + + if (!noux()->syscall(Noux::Session::SYSCALL_USERINFO)) + return 0; + + uid_t uid = sysio()->userinfo_out.uid; + PDBG("getuid(): %d", uid); + return uid; +} + + +extern "C" uid_t geteuid() +{ + return getuid(); +} + + extern "C" int __getcwd(char *dst, Genode::size_t dst_size) { noux()->syscall(Noux::Session::SYSCALL_GETCWD); diff --git a/ports/src/noux/child.h b/ports/src/noux/child.h index 4e2f248c6a..f04a8bdb93 100644 --- a/ports/src/noux/child.h +++ b/ports/src/noux/child.h @@ -66,6 +66,12 @@ namespace Noux { class Timeout_scheduler; Timeout_scheduler *timeout_scheduler(); + /** + * Return singleton instance of user information + */ + class User_info; + User_info *user_info(); + class Child; diff --git a/ports/src/noux/main.cc b/ports/src/noux/main.cc index 74ab791308..43c8fd314c 100644 --- a/ports/src/noux/main.cc +++ b/ports/src/noux/main.cc @@ -25,6 +25,7 @@ #include #include #include +#include static bool trace_syscalls = false; @@ -562,6 +563,33 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc) return _root_dir->mkdir(_sysio, Absolute_path(_sysio->mkdir_in.path, _env.pwd()).base()); + case SYSCALL_USERINFO: + { + if (_sysio->userinfo_in.request == Sysio::USERINFO_GET_UID + || _sysio->userinfo_in.request == Sysio::USERINFO_GET_GID) { + _sysio->userinfo_out.uid = Noux::user_info()->uid; + _sysio->userinfo_out.gid = Noux::user_info()->gid; + + return true; + } + + /* + * Since NOUX supports exactly one user, return false if we + * got a unknown uid. + */ + if (_sysio->userinfo_in.uid != Noux::user_info()->uid) + return false; + + Genode::memcpy(_sysio->userinfo_out.name, Noux::user_info()->name, sizeof(Noux::user_info()->name)); + Genode::memcpy(_sysio->userinfo_out.shell, Noux::user_info()->shell, sizeof(Noux::user_info()->shell)); + Genode::memcpy(_sysio->userinfo_out.home, Noux::user_info()->home, sizeof(Noux::user_info()->home)); + + _sysio->userinfo_out.uid = user_info()->uid; + _sysio->userinfo_out.gid = user_info()->gid; + + return true; + } + case SYSCALL_SOCKET: case SYSCALL_GETSOCKOPT: case SYSCALL_SETSOCKOPT: @@ -697,12 +725,21 @@ Noux::Pid_allocator *Noux::pid_allocator() return &inst; } + Noux::Timeout_scheduler *Noux::timeout_scheduler() { static Noux::Timeout_scheduler inst; return &inst; } + +Noux::User_info* Noux::user_info() +{ + static Noux::User_info inst; + return &inst; +} + + void *operator new (Genode::size_t size) { return Genode::env()->heap()->alloc(size); } @@ -735,6 +772,12 @@ int main(int argc, char **argv) static Dir_file_system root_dir(config()->xml_node().sub_node("fstab")); + /* set user information */ + try { + user_info()->set_info(config()->xml_node().sub_node("user")); + } + catch (...) { } + /* initialize network */ init_network(); diff --git a/ports/src/noux/net/net.cc b/ports/src/noux/net/net.cc index ee930dc90d..a0fc7179d5 100644 --- a/ports/src/noux/net/net.cc +++ b/ports/src/noux/net/net.cc @@ -163,6 +163,7 @@ bool Noux::Child::_syscall_net(Noux::Session::Syscall sc) case SYSCALL_RENAME: case SYSCALL_MKDIR: case SYSCALL_FTRUNCATE: + case SYSCALL_USERINFO: break; case SYSCALL_SOCKET: { diff --git a/ports/src/noux/user_info.h b/ports/src/noux/user_info.h new file mode 100644 index 0000000000..5b7da400ee --- /dev/null +++ b/ports/src/noux/user_info.h @@ -0,0 +1,78 @@ +/* + * \brief User information + * \author Josef Soentgen + * \date 2012-07-23 + */ + +/* + * Copyright (C) 2011-2012 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _NOUX__USER_INFO_H_ +#define _NOUX__USER_INFO_H_ + +/* Genode includes */ +#include +#include + +/* Noux includes */ +#include + +namespace Noux { + + struct User_info { + public: + + char name[Sysio::MAX_USERNAME_LEN]; + char shell[Sysio::MAX_SHELL_LEN]; + char home[Sysio::MAX_HOME_LEN]; + + unsigned int uid; + unsigned int gid; + + private: + + void _dup_str(char *dest, const char *src) + { + Genode::size_t len = Genode::strlen(src); + Genode::memcpy(dest, src, len); + dest[len] = '\0'; + } + + public: + + User_info() : uid(0), gid(0) + { + _dup_str(name, "root"); + _dup_str(home, "/"); + _dup_str(shell, "/bin/bash"); + } + + void set_info(Genode::Xml_node user_info_node) + { + try { + user_info_node.attribute("name").value(name, sizeof(name)); + user_info_node.attribute("uid").value(&uid); + user_info_node.attribute("gid").value(&gid); + + for (unsigned i = 0; i < user_info_node.num_sub_nodes(); i++) { + Xml_node sub_node = user_info_node.sub_node(i); + + if (sub_node.has_type("shell")) { + sub_node.attribute("name").value(shell, sizeof(shell)); + } + + if (sub_node.has_type("home")) { + sub_node.attribute("name").value(home, sizeof(home)); + } + } + } + catch (...) { } + } + }; +} + +#endif /* _NOUX__USER_INFO_H_ */