mirror of
https://github.com/systemd/systemd-stable.git
synced 2024-10-28 20:25:25 +03:00
Merge pull request #8303 from yuwata/fix-8276
test: use synthesize_nobody() in test-execute
This commit is contained in:
commit
48449f41b4
@ -40,6 +40,7 @@
|
|||||||
#include "test-helper.h"
|
#include "test-helper.h"
|
||||||
#include "tests.h"
|
#include "tests.h"
|
||||||
#include "unit.h"
|
#include "unit.h"
|
||||||
|
#include "user-util.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "virt.h"
|
#include "virt.h"
|
||||||
|
|
||||||
@ -75,6 +76,51 @@ static void check(Manager *m, Unit *unit, int status_expected, int code_expected
|
|||||||
assert_se(service->main_exec_status.code == code_expected);
|
assert_se(service->main_exec_status.code == code_expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool check_nobody_user_and_group(void) {
|
||||||
|
static int cache = -1;
|
||||||
|
struct passwd *p;
|
||||||
|
struct group *g;
|
||||||
|
|
||||||
|
if (cache >= 0)
|
||||||
|
return !!cache;
|
||||||
|
|
||||||
|
if (!synthesize_nobody())
|
||||||
|
goto invalid;
|
||||||
|
|
||||||
|
p = getpwnam(NOBODY_USER_NAME);
|
||||||
|
if (!p ||
|
||||||
|
!streq(p->pw_name, NOBODY_USER_NAME) ||
|
||||||
|
p->pw_uid != UID_NOBODY ||
|
||||||
|
p->pw_gid != GID_NOBODY)
|
||||||
|
goto invalid;
|
||||||
|
|
||||||
|
p = getpwuid(UID_NOBODY);
|
||||||
|
if (!p ||
|
||||||
|
!streq(p->pw_name, NOBODY_USER_NAME) ||
|
||||||
|
p->pw_uid != UID_NOBODY ||
|
||||||
|
p->pw_gid != GID_NOBODY)
|
||||||
|
goto invalid;
|
||||||
|
|
||||||
|
g = getgrnam(NOBODY_GROUP_NAME);
|
||||||
|
if (!g ||
|
||||||
|
!streq(g->gr_name, NOBODY_GROUP_NAME) ||
|
||||||
|
g->gr_gid != GID_NOBODY)
|
||||||
|
goto invalid;
|
||||||
|
|
||||||
|
g = getgrgid(GID_NOBODY);
|
||||||
|
if (!g ||
|
||||||
|
!streq(g->gr_name, NOBODY_GROUP_NAME) ||
|
||||||
|
g->gr_gid != GID_NOBODY)
|
||||||
|
goto invalid;
|
||||||
|
|
||||||
|
cache = 1;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
invalid:
|
||||||
|
cache = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static bool is_inaccessible_available(void) {
|
static bool is_inaccessible_available(void) {
|
||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
@ -332,33 +378,53 @@ static void test_exec_systemcallfilter_system(Manager *m) {
|
|||||||
log_notice("Seccomp not available, skipping %s", __func__);
|
log_notice("Seccomp not available, skipping %s", __func__);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (getpwnam("nobody"))
|
|
||||||
test(m, "exec-systemcallfilter-system-user.service", 0, CLD_EXITED);
|
test(m, "exec-systemcallfilter-system-user.service", 0, CLD_EXITED);
|
||||||
else if (getpwnam("nfsnobody"))
|
|
||||||
test(m, "exec-systemcallfilter-system-user-nfsnobody.service", 0, CLD_EXITED);
|
if (!check_nobody_user_and_group()) {
|
||||||
else
|
log_error_errno(errno, "nobody user/group is not synthesized or may conflict to other entries, skipping remaining tests in %s", __func__);
|
||||||
log_error_errno(errno, "Skipping %s, could not find nobody/nfsnobody user: %m", __func__);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!STR_IN_SET(NOBODY_USER_NAME, "nobody", "nfsnobody")) {
|
||||||
|
log_error("Unsupported nobody user name '%s', skipping remaining tests in %s", NOBODY_USER_NAME, __func__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
test(m, "exec-systemcallfilter-system-user-" NOBODY_USER_NAME ".service", 0, CLD_EXITED);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_exec_user(Manager *m) {
|
static void test_exec_user(Manager *m) {
|
||||||
if (getpwnam("nobody"))
|
test(m, "exec-user.service", 0, CLD_EXITED);
|
||||||
test(m, "exec-user.service", 0, CLD_EXITED);
|
|
||||||
else if (getpwnam("nfsnobody"))
|
if (!check_nobody_user_and_group()) {
|
||||||
test(m, "exec-user-nfsnobody.service", 0, CLD_EXITED);
|
log_error_errno(errno, "nobody user/group is not synthesized or may conflict to other entries, skipping remaining tests in %s", __func__);
|
||||||
else
|
return;
|
||||||
log_error_errno(errno, "Skipping %s, could not find nobody/nfsnobody user: %m", __func__);
|
}
|
||||||
|
|
||||||
|
if (!STR_IN_SET(NOBODY_USER_NAME, "nobody", "nfsnobody")) {
|
||||||
|
log_error("Unsupported nobody user name '%s', skipping remaining tests in %s", NOBODY_USER_NAME, __func__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
test(m, "exec-user-" NOBODY_USER_NAME ".service", 0, CLD_EXITED);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_exec_group(Manager *m) {
|
static void test_exec_group(Manager *m) {
|
||||||
if (getgrnam("nobody"))
|
test(m, "exec-group.service", 0, CLD_EXITED);
|
||||||
test(m, "exec-group.service", 0, CLD_EXITED);
|
|
||||||
else if (getgrnam("nfsnobody"))
|
if (!check_nobody_user_and_group()) {
|
||||||
test(m, "exec-group-nfsnobody.service", 0, CLD_EXITED);
|
log_error_errno(errno, "nobody user/group is not synthesized or may conflict to other entries, skipping remaining tests in %s", __func__);
|
||||||
else if (getgrnam("nogroup"))
|
return;
|
||||||
test(m, "exec-group-nogroup.service", 0, CLD_EXITED);
|
}
|
||||||
else
|
|
||||||
log_error_errno(errno, "Skipping %s, could not find nobody/nfsnobody/nogroup group: %m", __func__);
|
if (!STR_IN_SET(NOBODY_GROUP_NAME, "nobody", "nfsnobody", "nogroup")) {
|
||||||
|
log_error("Unsupported nobody group name '%s', skipping remaining tests in %s", NOBODY_GROUP_NAME, __func__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
test(m, "exec-group-" NOBODY_GROUP_NAME ".service", 0, CLD_EXITED);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_exec_supplementarygroups(Manager *m) {
|
static void test_exec_supplementarygroups(Manager *m) {
|
||||||
@ -442,12 +508,19 @@ static void test_exec_umask(Manager *m) {
|
|||||||
static void test_exec_runtimedirectory(Manager *m) {
|
static void test_exec_runtimedirectory(Manager *m) {
|
||||||
test(m, "exec-runtimedirectory.service", 0, CLD_EXITED);
|
test(m, "exec-runtimedirectory.service", 0, CLD_EXITED);
|
||||||
test(m, "exec-runtimedirectory-mode.service", 0, CLD_EXITED);
|
test(m, "exec-runtimedirectory-mode.service", 0, CLD_EXITED);
|
||||||
if (getgrnam("nobody"))
|
test(m, "exec-runtimedirectory-owner.service", 0, CLD_EXITED);
|
||||||
test(m, "exec-runtimedirectory-owner.service", 0, CLD_EXITED);
|
|
||||||
else if (getgrnam("nfsnobody"))
|
if (!check_nobody_user_and_group()) {
|
||||||
test(m, "exec-runtimedirectory-owner-nfsnobody.service", 0, CLD_EXITED);
|
log_error_errno(errno, "nobody user/group is not synthesized or may conflict to other entries, skipping remaining tests in %s", __func__);
|
||||||
else
|
return;
|
||||||
log_error_errno(errno, "Skipping %s, could not find nobody/nfsnobody group: %m", __func__);
|
}
|
||||||
|
|
||||||
|
if (!STR_IN_SET(NOBODY_GROUP_NAME, "nobody", "nfsnobody", "nogroup")) {
|
||||||
|
log_error("Unsupported nobody group name '%s', skipping remaining tests in %s", NOBODY_GROUP_NAME, __func__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
test(m, "exec-runtimedirectory-owner-" NOBODY_GROUP_NAME ".service", 0, CLD_EXITED);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_exec_capabilityboundingset(Manager *m) {
|
static void test_exec_capabilityboundingset(Manager *m) {
|
||||||
@ -478,14 +551,21 @@ static void test_exec_capabilityambientset(Manager *m) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getpwnam("nobody")) {
|
test(m, "exec-capabilityambientset.service", 0, CLD_EXITED);
|
||||||
test(m, "exec-capabilityambientset.service", 0, CLD_EXITED);
|
test(m, "exec-capabilityambientset-merge.service", 0, CLD_EXITED);
|
||||||
test(m, "exec-capabilityambientset-merge.service", 0, CLD_EXITED);
|
|
||||||
} else if (getpwnam("nfsnobody")) {
|
if (!check_nobody_user_and_group()) {
|
||||||
test(m, "exec-capabilityambientset-nfsnobody.service", 0, CLD_EXITED);
|
log_error_errno(errno, "nobody user/group is not synthesized or may conflict to other entries, skipping remaining tests in %s", __func__);
|
||||||
test(m, "exec-capabilityambientset-merge-nfsnobody.service", 0, CLD_EXITED);
|
return;
|
||||||
} else
|
}
|
||||||
log_error_errno(errno, "Skipping %s, could not find nobody/nfsnobody user: %m", __func__);
|
|
||||||
|
if (!STR_IN_SET(NOBODY_USER_NAME, "nobody", "nfsnobody")) {
|
||||||
|
log_error("Unsupported nobody user name '%s', skipping remaining tests in %s", NOBODY_USER_NAME, __func__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
test(m, "exec-capabilityambientset-" NOBODY_USER_NAME ".service", 0, CLD_EXITED);
|
||||||
|
test(m, "exec-capabilityambientset-merge-" NOBODY_USER_NAME ".service", 0, CLD_EXITED);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_exec_privatenetwork(Manager *m) {
|
static void test_exec_privatenetwork(Manager *m) {
|
||||||
|
@ -47,8 +47,10 @@ test_data_files = '''
|
|||||||
sysinit.target
|
sysinit.target
|
||||||
test-execute/exec-bindpaths.service
|
test-execute/exec-bindpaths.service
|
||||||
test-execute/exec-capabilityambientset-merge-nfsnobody.service
|
test-execute/exec-capabilityambientset-merge-nfsnobody.service
|
||||||
|
test-execute/exec-capabilityambientset-merge-nobody.service
|
||||||
test-execute/exec-capabilityambientset-merge.service
|
test-execute/exec-capabilityambientset-merge.service
|
||||||
test-execute/exec-capabilityambientset-nfsnobody.service
|
test-execute/exec-capabilityambientset-nfsnobody.service
|
||||||
|
test-execute/exec-capabilityambientset-nobody.service
|
||||||
test-execute/exec-capabilityambientset.service
|
test-execute/exec-capabilityambientset.service
|
||||||
test-execute/exec-capabilityboundingset-invert.service
|
test-execute/exec-capabilityboundingset-invert.service
|
||||||
test-execute/exec-capabilityboundingset-merge.service
|
test-execute/exec-capabilityboundingset-merge.service
|
||||||
@ -68,6 +70,7 @@ test_data_files = '''
|
|||||||
test-execute/exec-environment.service
|
test-execute/exec-environment.service
|
||||||
test-execute/exec-environmentfile.service
|
test-execute/exec-environmentfile.service
|
||||||
test-execute/exec-group-nfsnobody.service
|
test-execute/exec-group-nfsnobody.service
|
||||||
|
test-execute/exec-group-nobody.service
|
||||||
test-execute/exec-group-nogroup.service
|
test-execute/exec-group-nogroup.service
|
||||||
test-execute/exec-group.service
|
test-execute/exec-group.service
|
||||||
test-execute/exec-ignoresigpipe-no.service
|
test-execute/exec-ignoresigpipe-no.service
|
||||||
@ -113,6 +116,8 @@ test_data_files = '''
|
|||||||
test-execute/exec-restrictnamespaces-yes.service
|
test-execute/exec-restrictnamespaces-yes.service
|
||||||
test-execute/exec-runtimedirectory-mode.service
|
test-execute/exec-runtimedirectory-mode.service
|
||||||
test-execute/exec-runtimedirectory-owner-nfsnobody.service
|
test-execute/exec-runtimedirectory-owner-nfsnobody.service
|
||||||
|
test-execute/exec-runtimedirectory-owner-nobody.service
|
||||||
|
test-execute/exec-runtimedirectory-owner-nogroup.service
|
||||||
test-execute/exec-runtimedirectory-owner.service
|
test-execute/exec-runtimedirectory-owner.service
|
||||||
test-execute/exec-runtimedirectory.service
|
test-execute/exec-runtimedirectory.service
|
||||||
test-execute/exec-specifier-interpolation.service
|
test-execute/exec-specifier-interpolation.service
|
||||||
@ -133,6 +138,7 @@ test_data_files = '''
|
|||||||
test-execute/exec-systemcallfilter-not-failing.service
|
test-execute/exec-systemcallfilter-not-failing.service
|
||||||
test-execute/exec-systemcallfilter-not-failing2.service
|
test-execute/exec-systemcallfilter-not-failing2.service
|
||||||
test-execute/exec-systemcallfilter-system-user-nfsnobody.service
|
test-execute/exec-systemcallfilter-system-user-nfsnobody.service
|
||||||
|
test-execute/exec-systemcallfilter-system-user-nobody.service
|
||||||
test-execute/exec-systemcallfilter-system-user.service
|
test-execute/exec-systemcallfilter-system-user.service
|
||||||
test-execute/exec-systemcallfilter-with-errno-name.service
|
test-execute/exec-systemcallfilter-with-errno-name.service
|
||||||
test-execute/exec-systemcallfilter-with-errno-number.service
|
test-execute/exec-systemcallfilter-with-errno-number.service
|
||||||
@ -144,6 +150,7 @@ test_data_files = '''
|
|||||||
test-execute/exec-umask-default.service
|
test-execute/exec-umask-default.service
|
||||||
test-execute/exec-unsetenvironment.service
|
test-execute/exec-unsetenvironment.service
|
||||||
test-execute/exec-user-nfsnobody.service
|
test-execute/exec-user-nfsnobody.service
|
||||||
|
test-execute/exec-user-nobody.service
|
||||||
test-execute/exec-user.service
|
test-execute/exec-user.service
|
||||||
test-execute/exec-workingdirectory.service
|
test-execute/exec-workingdirectory.service
|
||||||
test-path/basic.target
|
test-path/basic.target
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Test for AmbientCapabilities
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/bin/sh -x -c 'c=$$(grep "CapAmb:" /proc/self/status); test "$$c" = "CapAmb: 0000000000003000"'
|
||||||
|
Type=oneshot
|
||||||
|
User=nobody
|
||||||
|
AmbientCapabilities=CAP_NET_ADMIN
|
||||||
|
AmbientCapabilities=CAP_NET_RAW
|
@ -1,9 +1,9 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
Description=Test for AmbientCapabilities
|
Description=Test for AmbientCapabilities (daemon)
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
ExecStart=/bin/sh -x -c 'c=$$(grep "CapAmb:" /proc/self/status); test "$$c" = "CapAmb: 0000000000003000"'
|
ExecStart=/bin/sh -x -c 'c=$$(grep "CapAmb:" /proc/self/status); test "$$c" = "CapAmb: 0000000000003000"'
|
||||||
Type=oneshot
|
Type=oneshot
|
||||||
User=nobody
|
User=daemon
|
||||||
AmbientCapabilities=CAP_NET_ADMIN
|
AmbientCapabilities=CAP_NET_ADMIN
|
||||||
AmbientCapabilities=CAP_NET_RAW
|
AmbientCapabilities=CAP_NET_RAW
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Test for AmbientCapabilities
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/bin/sh -x -c 'c=$$(grep "CapAmb:" /proc/self/status); test "$$c" = "CapAmb: 0000000000003000"'
|
||||||
|
Type=oneshot
|
||||||
|
User=nobody
|
||||||
|
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW
|
@ -1,8 +1,8 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
Description=Test for AmbientCapabilities
|
Description=Test for AmbientCapabilities (daemon)
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
ExecStart=/bin/sh -x -c 'c=$$(grep "CapAmb:" /proc/self/status); test "$$c" = "CapAmb: 0000000000003000"'
|
ExecStart=/bin/sh -x -c 'c=$$(grep "CapAmb:" /proc/self/status); test "$$c" = "CapAmb: 0000000000003000"'
|
||||||
Type=oneshot
|
Type=oneshot
|
||||||
User=nobody
|
User=daemon
|
||||||
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW
|
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW
|
||||||
|
7
test/test-execute/exec-group-nobody.service
Normal file
7
test/test-execute/exec-group-nobody.service
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Test for Group
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/bin/sh -x -c 'test "$$(id -n -g)" = "nobody"'
|
||||||
|
Type=oneshot
|
||||||
|
Group=nobody
|
@ -1,7 +1,7 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
Description=Test for Group
|
Description=Test for Group (daemon)
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
ExecStart=/bin/sh -x -c 'test "$$(id -n -g)" = "nobody"'
|
ExecStart=/bin/sh -x -c 'test "$$(id -n -g)" = "daemon"'
|
||||||
Type=oneshot
|
Type=oneshot
|
||||||
Group=nobody
|
Group=daemon
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Test for RuntimeDirectory owner (must not be the default group of the user if Group is set)
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/bin/sh -x -c 'group=$$(stat -c %%G %t/test-exec_runtimedirectory-owner); test "$$group" = "nobody"'
|
||||||
|
Type=oneshot
|
||||||
|
Group=nobody
|
||||||
|
User=root
|
||||||
|
RuntimeDirectory=test-exec_runtimedirectory-owner
|
@ -0,0 +1,9 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Test for RuntimeDirectory owner (must not be the default group of the user if Group is set)
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/bin/sh -x -c 'group=$$(stat -c %%G %t/test-exec_runtimedirectory-owner); test "$$group" = "nogroup"'
|
||||||
|
Type=oneshot
|
||||||
|
Group=nogroup
|
||||||
|
User=root
|
||||||
|
RuntimeDirectory=test-exec_runtimedirectory-owner
|
@ -2,8 +2,8 @@
|
|||||||
Description=Test for RuntimeDirectory owner (must not be the default group of the user if Group is set)
|
Description=Test for RuntimeDirectory owner (must not be the default group of the user if Group is set)
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
ExecStart=/bin/sh -x -c 'group=$$(stat -c %%G %t/test-exec_runtimedirectory-owner); test "$$group" = "nobody"'
|
ExecStart=/bin/sh -x -c 'group=$$(stat -c %%G %t/test-exec_runtimedirectory-owner-daemon); test "$$group" = "daemon"'
|
||||||
Type=oneshot
|
Type=oneshot
|
||||||
Group=nobody
|
Group=daemon
|
||||||
User=root
|
User=root
|
||||||
RuntimeDirectory=test-exec_runtimedirectory-owner
|
RuntimeDirectory=test-exec_runtimedirectory-owner-daemon
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Test for SystemCallFilter in system mode with User set
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/bin/sh -c 'echo "Foo bar"'
|
||||||
|
Type=oneshot
|
||||||
|
User=nobody
|
||||||
|
SystemCallFilter=~read write open execve ioperm
|
||||||
|
SystemCallFilter=ioctl
|
||||||
|
SystemCallFilter=read write open execve
|
||||||
|
SystemCallFilter=~ioperm
|
@ -1,10 +1,10 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
Description=Test for SystemCallFilter in system mode with User set
|
Description=Test for SystemCallFilter in system mode with User set (daemon)
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
ExecStart=/bin/sh -c 'echo "Foo bar"'
|
ExecStart=/bin/sh -c 'echo "Foo bar"'
|
||||||
Type=oneshot
|
Type=oneshot
|
||||||
User=nobody
|
User=daemon
|
||||||
SystemCallFilter=~read write open execve ioperm
|
SystemCallFilter=~read write open execve ioperm
|
||||||
SystemCallFilter=ioctl
|
SystemCallFilter=ioctl
|
||||||
SystemCallFilter=read write open execve
|
SystemCallFilter=read write open execve
|
||||||
|
7
test/test-execute/exec-user-nobody.service
Normal file
7
test/test-execute/exec-user-nobody.service
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Test for User
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/bin/sh -x -c 'test "$$USER" = "nobody"'
|
||||||
|
Type=oneshot
|
||||||
|
User=nobody
|
@ -1,7 +1,7 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
Description=Test for User
|
Description=Test for User (daemon)
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
ExecStart=/bin/sh -x -c 'test "$$USER" = "nobody"'
|
ExecStart=/bin/sh -x -c 'test "$$USER" = "daemon"'
|
||||||
Type=oneshot
|
Type=oneshot
|
||||||
User=nobody
|
User=daemon
|
||||||
|
Loading…
Reference in New Issue
Block a user