blob: a024cab96fc0572e9a9bc9470e3bb91025b24803 [file]
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Unit tests for initgroups.
///
//===----------------------------------------------------------------------===//
#include "hdr/errno_macros.h"
#include "hdr/signal_macros.h"
#include "hdr/types/gid_t.h"
#include "hdr/types/size_t.h"
#include "hdr/types/struct_group.h"
#include "src/grp/endgrent.h"
#include "src/grp/getgrent.h"
#include "src/grp/grp_utils.h"
#include "src/grp/initgroups.h"
#include "src/grp/setgrent.h"
#include "src/unistd/getuid.h"
#include "test/UnitTest/ErrnoSetterMatcher.h"
#include "test/UnitTest/Test.h"
#include "test/src/grp/grp_test_utils.h"
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails;
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
TEST_F(LlvmLibcGrpTest, InitgroupsPrivilegeCheck) {
const char *content = "root:x:0:root\n"
"users:x:100:user1,user2\n"
"admins:x:300:user1\n";
ScopedGroupFile test_file(libc_make_test_file_path("initgroups_priv.test"),
content);
if (LIBC_NAMESPACE::getuid() == 0) {
EXPECT_THAT(LIBC_NAMESPACE::initgroups("user1", 1000), Succeeds(0));
} else {
EXPECT_THAT(LIBC_NAMESPACE::initgroups("user1", 1000), Fails(EPERM));
}
}
TEST_F(LlvmLibcGrpTest, InitgroupsNonexistentUser) {
const char *content = "wheel:x:10:root\n";
ScopedGroupFile test_file(
libc_make_test_file_path("initgroups_nonexist.test"), content);
if (LIBC_NAMESPACE::getuid() == 0) {
EXPECT_THAT(LIBC_NAMESPACE::initgroups("nonexistent", 1000), Succeeds(0));
} else {
EXPECT_THAT(LIBC_NAMESPACE::initgroups("nonexistent", 1000), Fails(EPERM));
}
}
TEST_F(LlvmLibcGrpTest, InitgroupsNonexistentFile) {
LIBC_NAMESPACE::grp::TESTONLY_set_group_path(
libc_make_test_file_path("initgroups_missing.test"));
if (LIBC_NAMESPACE::getuid() == 0) {
EXPECT_THAT(LIBC_NAMESPACE::initgroups("anyuser", 1000), Succeeds(0));
} else {
EXPECT_THAT(LIBC_NAMESPACE::initgroups("anyuser", 1000), Fails(EPERM));
}
}
TEST_F(LlvmLibcGrpTest, InitgroupsDoesNotDisturbIteration) {
const char *content = "group1:x:1:user1\n"
"group2:x:2:user2\n"
"group3:x:3:user1\n";
ScopedGroupFile test_file(libc_make_test_file_path("initgroups_iter.test"),
content);
LIBC_NAMESPACE::setgrent();
const auto first = LIBC_NAMESPACE::grp::read_next();
ASSERT_TRUE(first.has_value());
ASSERT_NE(first.value(), nullptr);
EXPECT_STREQ(first.value()->gr_name, "group1");
// initgroups reads the database using a scoped stream.
if (LIBC_NAMESPACE::getuid() == 0) {
EXPECT_THAT(LIBC_NAMESPACE::initgroups("user2", 50), Succeeds(0));
} else {
EXPECT_THAT(LIBC_NAMESPACE::initgroups("user2", 50), Fails(EPERM));
}
const auto second = LIBC_NAMESPACE::grp::read_next();
ASSERT_TRUE(second.has_value());
ASSERT_NE(second.value(), nullptr);
EXPECT_STREQ(second.value()->gr_name, "group2");
LIBC_NAMESPACE::endgrent();
}
#if defined(LIBC_ADD_NULL_CHECKS)
TEST_F(LlvmLibcGrpTest, NullUserCrash) {
ASSERT_DEATH([] { LIBC_NAMESPACE::initgroups(nullptr, 1000); },
WITH_SIGNAL(-1));
}
#endif // LIBC_ADD_NULL_CHECKS