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_ */