mirror of
https://github.com/falk-werner/webfused
synced 2024-10-27 20:44:08 +00:00
Merge pull request #2 from falk-werner/change_user
switch user and group when started as root
This commit is contained in:
commit
38f5c60e7b
@ -51,6 +51,7 @@ target_compile_options(userdb PUBLIC ${OPENSSL_CFLAGS_OTHER})
|
||||
add_library(webfused-static STATIC
|
||||
src/webfused/daemon.c
|
||||
src/webfused/mountpoint_factory.c
|
||||
src/webfused/change_user.c
|
||||
src/webfused/config/config.c
|
||||
src/webfused/config/factory.c
|
||||
src/webfused/config/builder.c
|
||||
|
18
README.md
18
README.md
@ -63,6 +63,12 @@ log:
|
||||
log_pid = true
|
||||
}
|
||||
}
|
||||
|
||||
user:
|
||||
{
|
||||
name = "webfused"
|
||||
group = "webfused"
|
||||
}
|
||||
```
|
||||
|
||||
### Version
|
||||
@ -154,6 +160,18 @@ This logger does not provide any settings.
|
||||
| facility | string | daemon | Syslog facility (see syslog documentation) |
|
||||
| log_pid | bool | false | Add process ID to log messages |
|
||||
|
||||
### User
|
||||
|
||||
| Setting | Type | Default value | Description |
|
||||
| ------- | ------ | ------------- | ------------------------------- |
|
||||
| name | string | *-required-* | Name of the user to switch to. |
|
||||
| group | string | *-required-* | Name of the group to switch to. |
|
||||
|
||||
Webfuse daemon will not run as root. If started as root, webfuse daemon tries to
|
||||
switch to *user* and *group* provided in config file.
|
||||
|
||||
*Note*: user and group are not switched, when webfuse daemon is not started as root.
|
||||
|
||||
## Dependencies
|
||||
|
||||
- [webfuse](https://github.com/falk-werner/webfuse)
|
||||
|
@ -43,3 +43,9 @@ log:
|
||||
log_pid = true
|
||||
}
|
||||
}
|
||||
|
||||
#user:
|
||||
#{
|
||||
# name = "webfused"
|
||||
# group = "webfused"
|
||||
#}
|
||||
|
116
src/webfused/change_user.c
Normal file
116
src/webfused/change_user.c
Normal file
@ -0,0 +1,116 @@
|
||||
#include "webfused/change_user.h"
|
||||
#include "webfused/log/log.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
static bool
|
||||
wfd_switch_group(
|
||||
char const * group_name)
|
||||
{
|
||||
struct group * group = getgrnam(group_name);
|
||||
bool result = (NULL != group);
|
||||
if (!result)
|
||||
{
|
||||
WFD_ERROR("failed to switch group: unknown group \'%s\'", group_name);
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
result = (0 != group->gr_gid);
|
||||
if (!result)
|
||||
{
|
||||
WFD_ERROR("failed to switch group: switch to root (gid 0) is not allowed");
|
||||
}
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
result = (0 == setgid(group->gr_gid));
|
||||
if (!result)
|
||||
{
|
||||
WFD_ERROR("failed to set group id: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
result = (0 == setgroups(0, NULL));
|
||||
if (!result)
|
||||
{
|
||||
WFD_ERROR("failed to release supplemenatary groups (setgroups): %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool
|
||||
wfd_switch_user(
|
||||
char const * user_name)
|
||||
{
|
||||
struct passwd * user = getpwnam(user_name);
|
||||
bool result = (NULL != user);
|
||||
if (!result)
|
||||
{
|
||||
WFD_ERROR("failed to switch user: unknown user \'%s\'", user_name);
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
result = (0 != user->pw_uid);
|
||||
if (!result)
|
||||
{
|
||||
WFD_ERROR("failed to switch user: switch to root (uid 0) is not allowed");
|
||||
}
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
result = (0 == setuid(user->pw_uid));
|
||||
if (!result)
|
||||
{
|
||||
WFD_ERROR("failed to switch user (setuid): %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
wfd_change_user(
|
||||
char const * user,
|
||||
char const * group)
|
||||
{
|
||||
bool result = true;
|
||||
bool const is_root = (0 == getuid());
|
||||
|
||||
if (is_root)
|
||||
{
|
||||
result = ((NULL != user) || (NULL != group));
|
||||
if (!result)
|
||||
{
|
||||
WFD_ERROR("webfuse daemon cannot be run as root: specify user and group in config");
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
result = wfd_switch_group(group);
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
result = wfd_switch_user(user);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
22
src/webfused/change_user.h
Normal file
22
src/webfused/change_user.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef WFD_CHANGE_USER_H
|
||||
#define WFD_CHANGE_USER_H
|
||||
|
||||
#ifndef __cplusplus
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
extern bool
|
||||
wfd_change_user(
|
||||
char const * user,
|
||||
char const * group);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -68,5 +68,14 @@ wfd_config_builder_set_logger(
|
||||
return builder.vtable->set_logger(builder.data, provider, level, settings);
|
||||
}
|
||||
|
||||
void
|
||||
wfd_config_builder_set_user(
|
||||
struct wfd_config_builder builder,
|
||||
char const * user,
|
||||
char const * group)
|
||||
{
|
||||
return builder.vtable->set_user(builder.data, user, group);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -56,6 +56,12 @@ wfd_config_builder_set_logger_fn(
|
||||
int level,
|
||||
struct wfd_settings * settings);
|
||||
|
||||
typedef void
|
||||
wfd_config_builder_set_user_fn(
|
||||
void * data,
|
||||
char const * user,
|
||||
char const * group);
|
||||
|
||||
struct wfd_config_builder_vtable
|
||||
{
|
||||
wfd_config_builder_set_server_vhostname_fn * set_server_vhostname;
|
||||
@ -66,6 +72,7 @@ struct wfd_config_builder_vtable
|
||||
wfd_config_builder_add_auth_provider_fn * add_auth_provider;
|
||||
wfd_config_builder_add_filesystem_fn * add_filesystem;
|
||||
wfd_config_builder_set_logger_fn * set_logger;
|
||||
wfd_config_builder_set_user_fn * set_user;
|
||||
};
|
||||
|
||||
struct wfd_config_builder
|
||||
@ -118,6 +125,12 @@ wfd_config_builder_set_logger(
|
||||
int level,
|
||||
struct wfd_settings * settings);
|
||||
|
||||
extern void
|
||||
wfd_config_builder_set_user(
|
||||
struct wfd_config_builder builder,
|
||||
char const * user,
|
||||
char const * group);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "webfused/log/manager.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define WFD_CONFIG_DEFAULT_PORT (8080)
|
||||
#define WFD_CONFIG_DEFAULT_VHOSTNAME ("localhost")
|
||||
@ -16,6 +17,8 @@ struct wfd_config
|
||||
bool has_authenticator;
|
||||
struct wfd_authenticator authenticator;
|
||||
struct wfd_mountpoint_factory * mountpoint_factory;
|
||||
char * user;
|
||||
char * group;
|
||||
};
|
||||
|
||||
static void
|
||||
@ -112,6 +115,17 @@ wfd_config_set_logger(
|
||||
return wfd_log_manager_set_logger(provider, level, settings);
|
||||
}
|
||||
|
||||
static void
|
||||
wfd_config_set_user(
|
||||
void * data,
|
||||
char const * user,
|
||||
char const * group)
|
||||
{
|
||||
struct wfd_config * config = data;
|
||||
config->user = strdup(user);
|
||||
config->group = strdup(group);
|
||||
}
|
||||
|
||||
static const struct wfd_config_builder_vtable
|
||||
wfd_config_vtable_config_builder =
|
||||
{
|
||||
@ -122,7 +136,8 @@ wfd_config_vtable_config_builder =
|
||||
.set_server_document_root = &wfd_config_set_server_document_root,
|
||||
.add_auth_provider = &wfd_config_add_auth_provider,
|
||||
.add_filesystem = &wfd_config_add_filesystem,
|
||||
.set_logger = &wfd_config_set_logger
|
||||
.set_logger = &wfd_config_set_logger,
|
||||
.set_user = &wfd_config_set_user
|
||||
};
|
||||
|
||||
struct wfd_config *
|
||||
@ -138,6 +153,8 @@ wfd_config_create(void)
|
||||
wf_server_config_set_mountpoint_factory(config->server,
|
||||
wfd_mountpoint_factory_create_mountpoint,
|
||||
config->mountpoint_factory);
|
||||
config->user = NULL;
|
||||
config->group = NULL;
|
||||
|
||||
return config;
|
||||
}
|
||||
@ -153,6 +170,8 @@ wfd_config_dispose(
|
||||
}
|
||||
wfd_mountpoint_factory_dispose(config->mountpoint_factory);
|
||||
|
||||
free(config->user);
|
||||
free(config->group);
|
||||
free(config);
|
||||
}
|
||||
|
||||
@ -176,3 +195,17 @@ wfd_config_get_server_config(
|
||||
return config->server;
|
||||
}
|
||||
|
||||
char const *
|
||||
wfd_config_get_user(
|
||||
struct wfd_config * config)
|
||||
{
|
||||
return config->user;
|
||||
}
|
||||
|
||||
char const *
|
||||
wfd_config_get_group(
|
||||
struct wfd_config * config)
|
||||
{
|
||||
return config->group;
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,14 @@ extern struct wf_server_config *
|
||||
wfd_config_get_server_config(
|
||||
struct wfd_config * config);
|
||||
|
||||
extern char const *
|
||||
wfd_config_get_user(
|
||||
struct wfd_config * config);
|
||||
|
||||
extern char const *
|
||||
wfd_config_get_group(
|
||||
struct wfd_config * config);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -262,6 +262,46 @@ wfd_config_read_filesystems(
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool
|
||||
wfd_config_read_user(
|
||||
config_t * config,
|
||||
struct wfd_config_builder builder)
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
bool has_user = (NULL != config_lookup(config, "user"));
|
||||
if (has_user)
|
||||
{
|
||||
char const * user;
|
||||
{
|
||||
int rc = config_lookup_string(config, "user.name", &user);
|
||||
if (CONFIG_TRUE != rc)
|
||||
{
|
||||
WFD_ERROR("failed to load config: missing required user propert: \'name\'");
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
|
||||
char const * group;
|
||||
if (result)
|
||||
{
|
||||
int rc = config_lookup_string(config, "user.group", &group);
|
||||
if (CONFIG_TRUE != rc)
|
||||
{
|
||||
WFD_ERROR("failed to load config: missing required user propert: \'group\'");
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
wfd_config_builder_set_user(builder, user, group);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool
|
||||
wfd_config_load(
|
||||
struct wfd_config_builder builder,
|
||||
@ -273,6 +313,7 @@ wfd_config_load(
|
||||
&& wfd_config_read_server(config, builder)
|
||||
&& wfd_config_read_authentication(config, builder)
|
||||
&& wfd_config_read_filesystems(config, builder)
|
||||
&& wfd_config_read_user(config, builder)
|
||||
;
|
||||
|
||||
return result;
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "webfused/log/log.h"
|
||||
#include "webfused/log/logger.h"
|
||||
#include "webfused/log/stderr_logger.h"
|
||||
#include "webfused/change_user.h"
|
||||
|
||||
#define WFD_SERVICE_TIMEOUT (1 * 1000)
|
||||
#define WFD_DEFAULT_CONFIG_FILE ("/etc/webfuse.conf")
|
||||
@ -111,6 +112,19 @@ int wfd_daemon_run(int argc, char * argv[])
|
||||
struct wfd_config * config = wfd_config_create();
|
||||
struct wfd_config_builder builder = wfd_config_get_builder(config);
|
||||
bool success = wfd_config_load_file(builder, args.config_file);
|
||||
if (!success)
|
||||
{
|
||||
fprintf(stderr, "fatal: failed to load server config\n");
|
||||
result = EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (success)
|
||||
{
|
||||
success = wfd_change_user(
|
||||
wfd_config_get_user(config),
|
||||
wfd_config_get_group(config));
|
||||
}
|
||||
|
||||
if (success)
|
||||
{
|
||||
struct wf_server_config * server_config = wfd_config_get_server_config(config);
|
||||
@ -130,11 +144,6 @@ int wfd_daemon_run(int argc, char * argv[])
|
||||
result = EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "fatal: failed to load server config\n");
|
||||
result = EXIT_FAILURE;
|
||||
}
|
||||
|
||||
wfd_config_dispose(config);
|
||||
}
|
||||
|
@ -80,6 +80,15 @@ wfd_MockConfigBuilder_set_logger(
|
||||
return builder->setLogger(provider, level, settings);
|
||||
}
|
||||
|
||||
static void
|
||||
wfd_MockConfigBuilder_set_user(
|
||||
void * data,
|
||||
char const * user,
|
||||
char const * group)
|
||||
{
|
||||
auto * builder = reinterpret_cast<IConfigBuilder*>(data);
|
||||
return builder->setUser(user, group);
|
||||
}
|
||||
|
||||
static const wfd_config_builder_vtable wfd_MockConfigBuilder_vtable =
|
||||
{
|
||||
@ -90,7 +99,8 @@ static const wfd_config_builder_vtable wfd_MockConfigBuilder_vtable =
|
||||
&wfd_MockConfigBuilder_set_server_document_root,
|
||||
&wfd_MockConfigBuilder_add_auth_provider,
|
||||
&wfd_MockConfigBuilder_add_filesystem,
|
||||
&wfd_MockConfigBuilder_set_logger
|
||||
&wfd_MockConfigBuilder_set_logger,
|
||||
&wfd_MockConfigBuilder_set_user
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ public:
|
||||
virtual bool addAuthProvider(char const * provider, wfd_settings * settings) = 0;
|
||||
virtual bool addFilesystem(char const * name, char const * mountpoint) = 0;
|
||||
virtual bool setLogger(char const * provider, int level, wfd_settings * settings) = 0;
|
||||
virtual void setUser(char const * user, char const * group) = 0;
|
||||
};
|
||||
|
||||
class MockConfigBuilder: public IConfigBuilder
|
||||
@ -33,6 +34,7 @@ public:
|
||||
MOCK_METHOD2(addAuthProvider, bool (char const * provider, wfd_settings * settings));
|
||||
MOCK_METHOD2(addFilesystem, bool (char const * name, char const * mountpoint));
|
||||
MOCK_METHOD3(setLogger, bool (char const * provider, int level, wfd_settings * settings));
|
||||
MOCK_METHOD2(setUser, void (char const * user, char const * group));
|
||||
|
||||
struct wfd_config_builder getBuilder();
|
||||
};
|
||||
|
@ -103,3 +103,17 @@ TEST(config, set_logger)
|
||||
|
||||
wfd_config_dispose(config);
|
||||
}
|
||||
|
||||
TEST(config, do_set_user)
|
||||
{
|
||||
wfd_config * config = wfd_config_create();
|
||||
ASSERT_NE(nullptr, config);
|
||||
|
||||
wfd_config_builder builder = wfd_config_get_builder(config);
|
||||
|
||||
wfd_config_builder_set_user(builder, "some.user", "some.group");
|
||||
ASSERT_STREQ("some.user", wfd_config_get_user(config));
|
||||
ASSERT_STREQ("some.group", wfd_config_get_group(config));
|
||||
|
||||
wfd_config_dispose(config);
|
||||
}
|
@ -546,3 +546,63 @@ TEST(config, log_fail_invalid_level)
|
||||
ASSERT_FALSE(result);
|
||||
}
|
||||
|
||||
TEST(config, set_user)
|
||||
{
|
||||
MockLogger logger;
|
||||
EXPECT_CALL(logger, log(_, _, _)).Times(0);
|
||||
EXPECT_CALL(logger, onclose()).Times(1);
|
||||
|
||||
StrictMock<MockConfigBuilder> builder;
|
||||
EXPECT_CALL(builder, setUser(_, _)).Times(1);
|
||||
|
||||
char const config_text[] =
|
||||
"version = { major = 1, minor = 0 }\n"
|
||||
"user:\n"
|
||||
"{\n"
|
||||
" name = \"webfused\"\n"
|
||||
" group = \"webfused\"\n"
|
||||
"}\n"
|
||||
;
|
||||
bool result = wfd_config_load_string(builder.getBuilder(), config_text);
|
||||
ASSERT_TRUE(result);
|
||||
}
|
||||
|
||||
TEST(config, set_user_fail_missing_name)
|
||||
{
|
||||
MockLogger logger;
|
||||
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, _, _)).Times(1);
|
||||
EXPECT_CALL(logger, onclose()).Times(1);
|
||||
|
||||
StrictMock<MockConfigBuilder> builder;
|
||||
EXPECT_CALL(builder, setUser(_, _)).Times(0);
|
||||
|
||||
char const config_text[] =
|
||||
"version = { major = 1, minor = 0 }\n"
|
||||
"user:\n"
|
||||
"{\n"
|
||||
" group = \"webfused\"\n"
|
||||
"}\n"
|
||||
;
|
||||
bool result = wfd_config_load_string(builder.getBuilder(), config_text);
|
||||
ASSERT_FALSE(result);
|
||||
}
|
||||
|
||||
TEST(config, set_user_fail_missing_group)
|
||||
{
|
||||
MockLogger logger;
|
||||
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, _, _)).Times(1);
|
||||
EXPECT_CALL(logger, onclose()).Times(1);
|
||||
|
||||
StrictMock<MockConfigBuilder> builder;
|
||||
EXPECT_CALL(builder, setUser(_, _)).Times(0);
|
||||
|
||||
char const config_text[] =
|
||||
"version = { major = 1, minor = 0 }\n"
|
||||
"user:\n"
|
||||
"{\n"
|
||||
" name = \"webfused\"\n"
|
||||
"}\n"
|
||||
;
|
||||
bool result = wfd_config_load_string(builder.getBuilder(), config_text);
|
||||
ASSERT_FALSE(result);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user