Line data Source code
1 : // Copyright (c) 2018-2025 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/snapdev
4 : // contact@m2osw.com
5 : //
6 : // This program is free software: you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation, either version 3 of the License, or
9 : // (at your option) any later version.
10 : //
11 : // This program is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License
17 : // along with this program. If not, see <https://www.gnu.org/licenses/>.
18 :
19 : /** \file
20 : * \brief Verify that the chownnm() function works.
21 : *
22 : * This file implements tests for the chownnm() function.
23 : */
24 :
25 : // self
26 : //
27 : #include <snapdev/chownnm.h>
28 :
29 : #include <snapdev/file_contents.h>
30 : #include <snapdev/user_groups.h>
31 : #include <snapdev/username.h>
32 :
33 : #include "catch_main.h"
34 :
35 :
36 : // C++
37 : //
38 : #include <set>
39 :
40 :
41 : // last include
42 : //
43 : #include <snapdev/poison.h>
44 :
45 :
46 :
47 :
48 2 : CATCH_TEST_CASE("chownnm", "[os]")
49 : {
50 2 : CATCH_START_SECTION("chownnm: change group")
51 : {
52 1 : struct group const * grp(getgrnam("snapwebsites"));
53 1 : if(grp == nullptr)
54 : {
55 : // adding a test otherwise this test fails when the snapwebsites
56 : // group is missing
57 : //
58 0 : CATCH_REQUIRE(grp == nullptr);
59 0 : std::cerr << "warning: skipping change group test because \"snapwebsites\" group doesn't exist.\n";
60 : }
61 : else
62 : {
63 1 : std::string const user(snapdev::username());
64 1 : CATCH_REQUIRE_FALSE(user.empty());
65 1 : bool permitted(true);
66 1 : if(user != "root")
67 : {
68 1 : std::set<std::string> our_groups(snapdev::user_group_names<std::set<std::string>>(user));
69 3 : if(our_groups.find("snapwebsites") == our_groups.end())
70 : {
71 1 : permitted = false;
72 1 : std::cerr << "warning: we expect the tester to be the \"root\" user or part of the \"snapwebsites\" group to run this test section.\n";
73 : }
74 1 : }
75 :
76 1 : if(permitted)
77 : {
78 0 : std::string const filename(SNAP_CATCH2_NAMESPACE::g_tmp_dir() + "/group-test.txt");
79 0 : snapdev::file_contents system_groups(filename);
80 0 : system_groups.contents("test file--testing changing group\n");
81 0 : system_groups.write_all();
82 :
83 0 : struct stat st;
84 0 : CATCH_REQUIRE(stat(filename.c_str(), &st) == 0);
85 0 : if(st.st_gid == grp->gr_gid)
86 : {
87 0 : std::cerr << "warning: your default group is \"snapwebsites\" so the test is not going to change anything\n";
88 : }
89 :
90 0 : CATCH_REQUIRE(snapdev::chownnm(filename, std::string(), "snapwebsites") == 0);
91 0 : struct stat verify;
92 0 : CATCH_REQUIRE(stat(filename.c_str(), &verify) == 0);
93 0 : CATCH_REQUIRE(verify.st_gid == grp->gr_gid);
94 :
95 : // restore former group
96 : //
97 0 : struct group * org_group(getgrgid(st.st_gid));
98 0 : CATCH_REQUIRE(org_group != nullptr);
99 0 : CATCH_REQUIRE(snapdev::chownnm(filename, std::string(), org_group->gr_name) == 0);
100 0 : CATCH_REQUIRE(stat(filename.c_str(), &verify) == 0);
101 0 : CATCH_REQUIRE(verify.st_gid == org_group->gr_gid);
102 0 : }
103 1 : }
104 : }
105 2 : CATCH_END_SECTION()
106 :
107 2 : CATCH_START_SECTION("chownnm: change owner")
108 : {
109 : // TODO: this is contradictory since we can't run this test as root...
110 : //
111 1 : std::string const user(snapdev::username());
112 1 : CATCH_REQUIRE_FALSE(user.empty());
113 1 : struct passwd const * pwd(getpwnam("snapwebsites"));
114 1 : if(pwd == nullptr
115 1 : || user != "root")
116 : {
117 1 : std::cerr << "warning: skipping change owner test because your are not root and/or the \"snapwebsites\" user doesn't exist.\n";
118 : }
119 : else
120 : {
121 0 : std::string const filename(SNAP_CATCH2_NAMESPACE::g_tmp_dir() + "/owner-test.txt");
122 0 : snapdev::file_contents system_groups(filename);
123 0 : system_groups.contents("test file--testing changing owner\n");
124 0 : system_groups.write_all();
125 :
126 0 : struct stat st;
127 0 : CATCH_REQUIRE(stat(filename.c_str(), &st) == 0);
128 0 : if(st.st_uid == pwd->pw_uid)
129 : {
130 : // this should not happen since we tested above that we are
131 : // root to properly run this test (otherwise we bail out)
132 : //
133 0 : std::cerr << "warning: your default owner is \"snapwebsites\" so the chownnm() call is not going to test anything.\n";
134 : }
135 :
136 0 : CATCH_REQUIRE(snapdev::chownnm(filename, "snapwebsites", std::string()) == 0);
137 0 : struct stat verify;
138 0 : CATCH_REQUIRE(stat(filename.c_str(), &verify) == 0);
139 0 : CATCH_REQUIRE(verify.st_uid == pwd->pw_uid);
140 :
141 : // restore former group
142 : //
143 0 : struct passwd * org_owner(getpwuid(st.st_uid));
144 0 : CATCH_REQUIRE(org_owner != nullptr);
145 0 : CATCH_REQUIRE(snapdev::chownnm(filename, std::string(), org_owner->pw_name) == 0);
146 0 : CATCH_REQUIRE(stat(filename.c_str(), &verify) == 0);
147 0 : CATCH_REQUIRE(verify.st_uid == org_owner->pw_uid);
148 0 : }
149 1 : }
150 2 : CATCH_END_SECTION()
151 2 : }
152 :
153 :
154 :
155 : // vim: ts=4 sw=4 et
|