mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-01 00:45:29 +00:00
Libc: single-user getpwent implementation
Implement the passwd database subroutines with single-user database. This database is populated with a <passwd/> sub-node of the libc configuration node. All fields of the "passwd" struct may be specified with reasonable defaults provided for a "root" user. This allows a libc-based component to spoof user information for the sake of porting existing Unix software. A test is provided at run/libc_getpwent. Fix #2919
This commit is contained in:
parent
9f6838ae42
commit
874ba409ca
@ -16,7 +16,8 @@ SRC_CC = atexit.cc dummies.cc rlimit.cc sysctl.cc \
|
||||
plugin.cc plugin_registry.cc select.cc exit.cc environ.cc nanosleep.cc \
|
||||
pread_pwrite.cc readv_writev.cc poll.cc \
|
||||
libc_pdbg.cc vfs_plugin.cc rtc.cc dynamic_linker.cc signal.cc \
|
||||
socket_operations.cc task.cc socket_fs_plugin.cc syscall.cc
|
||||
socket_operations.cc task.cc socket_fs_plugin.cc syscall.cc \
|
||||
getpwent.cc
|
||||
|
||||
CC_OPT_sysctl += -Wno-write-strings
|
||||
|
||||
|
@ -278,7 +278,9 @@ getprogname W
|
||||
getprotobyname T
|
||||
getprotobyname_r T
|
||||
getpwent W
|
||||
getpwent_r W
|
||||
getpwnam W
|
||||
getpwnam_r W
|
||||
getpwuid W
|
||||
getpwuid_r W
|
||||
getrlimit W
|
||||
|
135
repos/libports/run/libc_getpwent.run
Normal file
135
repos/libports/run/libc_getpwent.run
Normal file
@ -0,0 +1,135 @@
|
||||
build "core init app/sequence server/vfs test/libc_getpwent"
|
||||
|
||||
create_boot_directory
|
||||
|
||||
install_config {
|
||||
<config>
|
||||
<parent-provides>
|
||||
<service name="CPU"/>
|
||||
<service name="LOG"/>
|
||||
<service name="PD"/>
|
||||
<service name="RM"/>
|
||||
<service name="ROM"/>
|
||||
</parent-provides>
|
||||
<default-route>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</default-route>
|
||||
<default caps="128"/>
|
||||
|
||||
<start name="fs">
|
||||
<binary name="vfs"/>
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<provides> <service name="File_system"/> </provides>
|
||||
<config>
|
||||
<vfs> <log label="log"/> </vfs>
|
||||
<default-policy root="/" writeable="yes"/>
|
||||
</config>
|
||||
</start>
|
||||
|
||||
<start name="test">
|
||||
<binary name="sequence"/>
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<config>
|
||||
|
||||
<start name="root">
|
||||
<binary name="test-libc_getpwent"/>
|
||||
<config>
|
||||
<vfs> <fs/> </vfs>
|
||||
<libc stdout="/log" stderr="/log"/>
|
||||
<arg value="test-libc_getpwent"/>
|
||||
<env key="HOME" value="/home-from-getenv"/>
|
||||
</config>
|
||||
</start>
|
||||
|
||||
<start name="alice">
|
||||
<binary name="test-libc_getpwent"/>
|
||||
<config>
|
||||
<vfs> <fs/> </vfs>
|
||||
<libc stdout="/log" stderr="/log">
|
||||
<passwd name="alice" uid="1" home="/home/alice"/>
|
||||
</libc>
|
||||
</config>
|
||||
</start>
|
||||
|
||||
<start name="bob">
|
||||
<binary name="test-libc_getpwent"/>
|
||||
<config>
|
||||
<vfs> <fs/> </vfs>
|
||||
<libc stdout="/log" stderr="/log">
|
||||
<passwd name="bob" uid="2" home="/root"/>
|
||||
</libc>
|
||||
</config>
|
||||
</start>
|
||||
|
||||
</config>
|
||||
</start>
|
||||
</config>
|
||||
}
|
||||
|
||||
build_boot_image {
|
||||
core init vfs sequence test-libc_getpwent
|
||||
ld.lib.so libc.lib.so vfs.lib.so libm.lib.so posix.lib.so
|
||||
}
|
||||
|
||||
append qemu_args " -nographic "
|
||||
|
||||
run_genode_until "child .* exited with exit value 0.*\n" 20
|
||||
|
||||
grep_output {\[init -\> fs -\> log\] }
|
||||
|
||||
compare_output_to {
|
||||
[init -> fs -> log] [getpwent] user:root uid:0 home:/
|
||||
[init -> fs -> log] [getpwent] NULL
|
||||
[init -> fs -> log] [getpwent] NULL
|
||||
[init -> fs -> log] [getpwent_r] user:root uid:0 home:/
|
||||
[init -> fs -> log] [getpwent_r] NULL
|
||||
[init -> fs -> log] [getpwent_r] NULL
|
||||
[init -> fs -> log] [getpwnam root] user:root uid:0 home:/
|
||||
[init -> fs -> log] [getpwnam alice] NULL
|
||||
[init -> fs -> log] [getpwnam bob] NULL
|
||||
[init -> fs -> log] [getpwnam_r root] user:root uid:0 home:/
|
||||
[init -> fs -> log] [getpwnam_r alice] NULL
|
||||
[init -> fs -> log] [getpwnam_r bob] NULL
|
||||
[init -> fs -> log] [getpwuid 0] user:root uid:0 home:/
|
||||
[init -> fs -> log] [getpwuid 1] NULL
|
||||
[init -> fs -> log] [getpwuid 2] NULL
|
||||
[init -> fs -> log] [getpwuid_r 0] user:root uid:0 home:/
|
||||
[init -> fs -> log] [getpwuid_r 1] NULL
|
||||
[init -> fs -> log] [getpwuid_r 2] NULL
|
||||
[init -> fs -> log] [getpwent] user:alice uid:1 home:/home/alice
|
||||
[init -> fs -> log] [getpwent] NULL
|
||||
[init -> fs -> log] [getpwent] NULL
|
||||
[init -> fs -> log] [getpwent_r] user:alice uid:1 home:/home/alice
|
||||
[init -> fs -> log] [getpwent_r] NULL
|
||||
[init -> fs -> log] [getpwent_r] NULL
|
||||
[init -> fs -> log] [getpwnam root] NULL
|
||||
[init -> fs -> log] [getpwnam alice] user:alice uid:1 home:/home/alice
|
||||
[init -> fs -> log] [getpwnam bob] NULL
|
||||
[init -> fs -> log] [getpwnam_r root] NULL
|
||||
[init -> fs -> log] [getpwnam_r alice] user:alice uid:1 home:/home/alice
|
||||
[init -> fs -> log] [getpwnam_r bob] NULL
|
||||
[init -> fs -> log] [getpwuid 0] NULL
|
||||
[init -> fs -> log] [getpwuid 1] user:alice uid:1 home:/home/alice
|
||||
[init -> fs -> log] [getpwuid 2] NULL
|
||||
[init -> fs -> log] [getpwuid_r 0] NULL
|
||||
[init -> fs -> log] [getpwuid_r 1] user:alice uid:1 home:/home/alice
|
||||
[init -> fs -> log] [getpwuid_r 2] NULL
|
||||
[init -> fs -> log] [getpwent] user:bob uid:2 home:/root
|
||||
[init -> fs -> log] [getpwent] NULL
|
||||
[init -> fs -> log] [getpwent] NULL
|
||||
[init -> fs -> log] [getpwent_r] user:bob uid:2 home:/root
|
||||
[init -> fs -> log] [getpwent_r] NULL
|
||||
[init -> fs -> log] [getpwent_r] NULL
|
||||
[init -> fs -> log] [getpwnam root] NULL
|
||||
[init -> fs -> log] [getpwnam alice] NULL
|
||||
[init -> fs -> log] [getpwnam bob] user:bob uid:2 home:/root
|
||||
[init -> fs -> log] [getpwnam_r root] NULL
|
||||
[init -> fs -> log] [getpwnam_r alice] NULL
|
||||
[init -> fs -> log] [getpwnam_r bob] user:bob uid:2 home:/root
|
||||
[init -> fs -> log] [getpwuid 0] NULL
|
||||
[init -> fs -> log] [getpwuid 1] NULL
|
||||
[init -> fs -> log] [getpwuid 2] user:bob uid:2 home:/root
|
||||
[init -> fs -> log] [getpwuid_r 0] NULL
|
||||
[init -> fs -> log] [getpwuid_r 1] NULL
|
||||
[init -> fs -> log] [getpwuid_r 2] user:bob uid:2 home:/root
|
||||
}
|
@ -57,7 +57,6 @@ DUMMY(int , -1, chroot, (const char *))
|
||||
DUMMY(char *, 0, crypt, (const char *, const char *))
|
||||
DUMMY(DB * , 0, dbopen, (const char *, int, int, DBTYPE, const void *))
|
||||
DUMMY(u_int32_t, 0, __default_hash, (const void *, size_t));
|
||||
DUMMY(void , , endpwent, (void))
|
||||
DUMMY(int , 0, fchmod, (int, mode_t))
|
||||
DUMMY(int , -1, fchown, (int, uid_t, gid_t))
|
||||
DUMMY(int , -1, flock, (int, int))
|
||||
@ -81,10 +80,6 @@ DUMMY(int , -1, getsid, (pid_t))
|
||||
DUMMY(pid_t , -1, getppid, (void))
|
||||
DUMMY(pid_t , -1, getpgrp, (void))
|
||||
DUMMY(int , -1, getpriority, (int, int))
|
||||
DUMMY(struct passwd *, 0, getpwent, (void))
|
||||
DUMMY(struct passwd *, 0, getpwnam, (const char *))
|
||||
DUMMY(struct passwd *, 0, getpwuid, (uid_t))
|
||||
DUMMY(int , 0, getpwuid_r, (uid_t, struct passwd *, char *, size_t, struct passwd **))
|
||||
DUMMY(int , -1, getrusage, (int, rusage *))
|
||||
DUMMY(uid_t , 0, getuid, (void))
|
||||
DUMMY(int , -1, kill, (pid_t, int))
|
||||
@ -110,10 +105,8 @@ DUMMY(int , -1, setgid, (gid_t))
|
||||
DUMMY(int , -1, setuid, (uid_t))
|
||||
DUMMY(int , -1, setgroups, (int, const gid_t *))
|
||||
DUMMY(int , -1, setitimer, (int, const itimerval *, itimerval *))
|
||||
DUMMY(int , -1, setpassent, (int))
|
||||
DUMMY(int , -1, setpgid, (pid_t, pid_t))
|
||||
DUMMY(int , -1, setpriority, (int, int, int))
|
||||
DUMMY(void , , setpwent, (void))
|
||||
DUMMY(int , -1, setregid, (gid_t, gid_t))
|
||||
DUMMY(int , -1, setreuid, (uid_t, uid_t))
|
||||
DUMMY(int , -1, setrlimit, (int, const rlimit *))
|
||||
|
184
repos/libports/src/lib/libc/getpwent.cc
Normal file
184
repos/libports/src/lib/libc/getpwent.cc
Normal file
@ -0,0 +1,184 @@
|
||||
/*
|
||||
* \brief Password database operations
|
||||
* \author Emery Hemingway
|
||||
* \date 2018-07-15
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2018 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/log.h>
|
||||
#include <util/string.h>
|
||||
|
||||
/* Libc includes */
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* local includes */
|
||||
#include "libc_errno.h"
|
||||
#include "task.h"
|
||||
|
||||
typedef Genode::String<128> Passwd_string;
|
||||
|
||||
struct Passwd_fields {
|
||||
Passwd_string name { "root" };
|
||||
Passwd_string passwd { };
|
||||
unsigned long uid = 0;
|
||||
unsigned long gid = 0;
|
||||
unsigned long change = 0;
|
||||
Passwd_string clas { };
|
||||
Passwd_string gecos { };
|
||||
Passwd_string home { "/" };
|
||||
Passwd_string shell { };
|
||||
unsigned long expire = 0;
|
||||
unsigned long fields = 0;
|
||||
|
||||
Passwd_fields() { }
|
||||
};
|
||||
|
||||
|
||||
static void _fill_passwd(struct passwd &db, Passwd_fields &fields)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
/* reset buffers */
|
||||
Genode::memset(&db, 0x00, sizeof(struct passwd));
|
||||
fields = Passwd_fields();
|
||||
|
||||
try {
|
||||
Xml_node const passwd = Libc::libc_config().sub_node("passwd");
|
||||
|
||||
fields.name = passwd.attribute_value("name", fields.name);
|
||||
fields.uid = passwd.attribute_value("uid", 0UL);
|
||||
fields.gid = passwd.attribute_value("gid", 0UL);
|
||||
fields.change = passwd.attribute_value("change", 0UL);
|
||||
fields.passwd = passwd.attribute_value("passwd", fields.passwd);
|
||||
fields.clas = passwd.attribute_value("class", fields.clas);
|
||||
fields.gecos = passwd.attribute_value("gecos", fields.gecos);
|
||||
fields.home = passwd.attribute_value("home", fields.home);
|
||||
fields.shell = passwd.attribute_value("shell", fields.shell);
|
||||
fields.expire = passwd.attribute_value("expire", 0UL);
|
||||
fields.fields = passwd.attribute_value("fields", 0UL);
|
||||
}
|
||||
|
||||
catch (...) { }
|
||||
|
||||
db.pw_name = (char *)fields.name.string();
|
||||
db.pw_uid = fields.uid;
|
||||
db.pw_gid = fields.gid;
|
||||
db.pw_change = fields.change;
|
||||
db.pw_passwd = (char *)fields.passwd.string();
|
||||
db.pw_class = (char *)fields.clas.string();
|
||||
db.pw_gecos = (char *)fields.gecos.string();
|
||||
db.pw_dir = (char *)fields.home.string();
|
||||
db.pw_shell = (char *)fields.shell.string();
|
||||
db.pw_expire = fields.expire;
|
||||
db.pw_fields = fields.fields;
|
||||
}
|
||||
|
||||
|
||||
static int _fill_r(struct passwd *in,
|
||||
char *buffer, size_t bufsize,
|
||||
struct passwd **out)
|
||||
{
|
||||
if (!in || !buffer) return Libc::Errno(EINVAL);
|
||||
if (bufsize < sizeof(Passwd_fields)) return Libc::Errno(ERANGE);
|
||||
|
||||
Passwd_fields *fields = (Passwd_fields *)buffer;
|
||||
_fill_passwd(*in, *fields);
|
||||
*out = in;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct passwd *_fill_static()
|
||||
{
|
||||
struct Passwd_storage {
|
||||
struct passwd pwd;
|
||||
Passwd_fields fields;
|
||||
};
|
||||
|
||||
static Passwd_storage *db = nullptr;
|
||||
if (!db)
|
||||
db = (Passwd_storage *)malloc(sizeof(struct Passwd_storage));
|
||||
|
||||
_fill_passwd(db->pwd, db->fields);
|
||||
return &db->pwd;
|
||||
}
|
||||
|
||||
|
||||
static int _passwd_index = 0;
|
||||
|
||||
|
||||
extern "C" {
|
||||
|
||||
struct passwd *getpwent(void)
|
||||
{
|
||||
return (_passwd_index++ == 0)
|
||||
? _fill_static()
|
||||
: NULL;
|
||||
}
|
||||
|
||||
|
||||
int getpwent_r(struct passwd *in,
|
||||
char *buffer, size_t bufsize,
|
||||
struct passwd **out)
|
||||
{
|
||||
*out = NULL;
|
||||
return _passwd_index++ == 0
|
||||
? _fill_r(in, buffer, bufsize, out)
|
||||
: 0;
|
||||
}
|
||||
|
||||
|
||||
struct passwd *getpwnam(const char *login)
|
||||
{
|
||||
struct passwd *result = _fill_static();
|
||||
return (Genode::strcmp(login, result->pw_name) == 0)
|
||||
? result : NULL;
|
||||
}
|
||||
|
||||
|
||||
int getpwnam_r(const char *login, struct passwd *in,
|
||||
char *buffer, size_t bufsize,
|
||||
struct passwd **out)
|
||||
{
|
||||
int rc = _fill_r(in, buffer, bufsize, out);
|
||||
if (rc == 0 && *out && Genode::strcmp(login, in->pw_name) != 0)
|
||||
*out = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
struct passwd *getpwuid(uid_t uid)
|
||||
{
|
||||
struct passwd *result = _fill_static();
|
||||
return (uid == result->pw_uid)
|
||||
? result : NULL;
|
||||
}
|
||||
|
||||
|
||||
int getpwuid_r(uid_t uid, struct passwd *in,
|
||||
char *buffer, size_t bufsize,
|
||||
struct passwd **out)
|
||||
{
|
||||
int rc = _fill_r(in, buffer, bufsize, out);
|
||||
if (rc == 0 && *out && uid != in->pw_uid)
|
||||
*out = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int setpassent(int) { _passwd_index = 0; return 0; }
|
||||
|
||||
void setpwent(void) { _passwd_index = 0; }
|
||||
|
||||
void endpwent(void) { }
|
||||
|
||||
} /* extern "C" */
|
76
repos/libports/src/test/libc_getpwent/main.c
Normal file
76
repos/libports/src/test/libc_getpwent/main.c
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* \brief Libc passwd database test
|
||||
* \author Emery Hemingway
|
||||
* \date 2018-07-16
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2018 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
void print_db(char const *label, struct passwd *db)
|
||||
{
|
||||
if (db == NULL)
|
||||
printf("[%s] NULL\n", label);
|
||||
else
|
||||
printf("[%s] user:%s uid:%d home:%s \n",
|
||||
label, db->pw_name, db->pw_uid, db->pw_dir);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
static char buf[4096];
|
||||
|
||||
struct passwd db;
|
||||
struct passwd *ptr;
|
||||
|
||||
print_db("getpwent", getpwent());
|
||||
print_db("getpwent", getpwent());
|
||||
print_db("getpwent", getpwent());
|
||||
|
||||
setpwent();
|
||||
getpwent_r(&db, buf, sizeof(buf), &ptr);
|
||||
print_db("getpwent_r", ptr);
|
||||
getpwent_r(&db, buf, sizeof(buf), &ptr);
|
||||
print_db("getpwent_r", ptr);
|
||||
getpwent_r(&db, buf, sizeof(buf), &ptr);
|
||||
print_db("getpwent_r", ptr);
|
||||
|
||||
print_db("getpwnam root", getpwnam("root"));
|
||||
print_db("getpwnam alice", getpwnam("alice"));
|
||||
print_db("getpwnam bob", getpwnam("bob"));
|
||||
|
||||
setpassent(0);
|
||||
getpwnam_r("root", &db, buf, sizeof(buf), &ptr);
|
||||
print_db("getpwnam_r root", ptr);
|
||||
getpwnam_r("alice", &db, buf, sizeof(buf), &ptr);
|
||||
print_db("getpwnam_r alice", ptr);
|
||||
getpwnam_r("bob", &db, buf, sizeof(buf), &ptr);
|
||||
print_db("getpwnam_r bob", ptr);
|
||||
|
||||
print_db("getpwuid 0", getpwuid(0));
|
||||
print_db("getpwuid 1", getpwuid(1));
|
||||
print_db("getpwuid 2", getpwuid(2));
|
||||
|
||||
setpassent(1);
|
||||
getpwuid_r(0, &db, buf, sizeof(buf), &ptr);
|
||||
print_db("getpwuid_r 0", ptr);
|
||||
getpwuid_r(1, &db, buf, sizeof(buf), &ptr);
|
||||
print_db("getpwuid_r 1", ptr);
|
||||
getpwuid_r(2, &db, buf, sizeof(buf), &ptr);
|
||||
print_db("getpwuid_r 2", ptr);
|
||||
|
||||
endpwent();
|
||||
return 0;
|
||||
}
|
3
repos/libports/src/test/libc_getpwent/target.mk
Normal file
3
repos/libports/src/test/libc_getpwent/target.mk
Normal file
@ -0,0 +1,3 @@
|
||||
TARGET = test-libc_getpwent
|
||||
SRC_C = main.c
|
||||
LIBS = posix
|
Loading…
x
Reference in New Issue
Block a user