passwd.cpp revision 1.1 1 1.1 jmmv // Copyright 2010 Google Inc.
2 1.1 jmmv // All rights reserved.
3 1.1 jmmv //
4 1.1 jmmv // Redistribution and use in source and binary forms, with or without
5 1.1 jmmv // modification, are permitted provided that the following conditions are
6 1.1 jmmv // met:
7 1.1 jmmv //
8 1.1 jmmv // * Redistributions of source code must retain the above copyright
9 1.1 jmmv // notice, this list of conditions and the following disclaimer.
10 1.1 jmmv // * Redistributions in binary form must reproduce the above copyright
11 1.1 jmmv // notice, this list of conditions and the following disclaimer in the
12 1.1 jmmv // documentation and/or other materials provided with the distribution.
13 1.1 jmmv // * Neither the name of Google Inc. nor the names of its contributors
14 1.1 jmmv // may be used to endorse or promote products derived from this software
15 1.1 jmmv // without specific prior written permission.
16 1.1 jmmv //
17 1.1 jmmv // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 1.1 jmmv // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 1.1 jmmv // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 1.1 jmmv // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 1.1 jmmv // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 1.1 jmmv // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 1.1 jmmv // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 1.1 jmmv // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 1.1 jmmv // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 1.1 jmmv // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 1.1 jmmv // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 1.1 jmmv
29 1.1 jmmv #include "utils/passwd.hpp"
30 1.1 jmmv
31 1.1 jmmv extern "C" {
32 1.1 jmmv #include <sys/types.h>
33 1.1 jmmv
34 1.1 jmmv #include <pwd.h>
35 1.1 jmmv #include <unistd.h>
36 1.1 jmmv }
37 1.1 jmmv
38 1.1 jmmv #include <stdexcept>
39 1.1 jmmv
40 1.1 jmmv #include "utils/format/macros.hpp"
41 1.1 jmmv #include "utils/logging/macros.hpp"
42 1.1 jmmv #include "utils/optional.ipp"
43 1.1 jmmv #include "utils/sanity.hpp"
44 1.1 jmmv
45 1.1 jmmv namespace passwd_ns = utils::passwd;
46 1.1 jmmv
47 1.1 jmmv
48 1.1 jmmv namespace {
49 1.1 jmmv
50 1.1 jmmv
51 1.1 jmmv /// If defined, replaces the value returned by current_user().
52 1.1 jmmv static utils::optional< passwd_ns::user > fake_current_user;
53 1.1 jmmv
54 1.1 jmmv
55 1.1 jmmv /// If not empty, defines the current set of mock users.
56 1.1 jmmv static std::vector< passwd_ns::user > mock_users;
57 1.1 jmmv
58 1.1 jmmv
59 1.1 jmmv /// Formats a user for logging purposes.
60 1.1 jmmv ///
61 1.1 jmmv /// \param user The user to format.
62 1.1 jmmv ///
63 1.1 jmmv /// \return The user as a string.
64 1.1 jmmv static std::string
65 1.1 jmmv format_user(const passwd_ns::user& user)
66 1.1 jmmv {
67 1.1 jmmv return F("name=%s, uid=%s, gid=%s") % user.name % user.uid % user.gid;
68 1.1 jmmv }
69 1.1 jmmv
70 1.1 jmmv
71 1.1 jmmv } // anonymous namespace
72 1.1 jmmv
73 1.1 jmmv
74 1.1 jmmv /// Constructs a new user.
75 1.1 jmmv ///
76 1.1 jmmv /// \param name_ The name of the user.
77 1.1 jmmv /// \param uid_ The user identifier.
78 1.1 jmmv /// \param gid_ The login group identifier.
79 1.1 jmmv passwd_ns::user::user(const std::string& name_, const unsigned int uid_,
80 1.1 jmmv const unsigned int gid_) :
81 1.1 jmmv name(name_),
82 1.1 jmmv uid(uid_),
83 1.1 jmmv gid(gid_)
84 1.1 jmmv {
85 1.1 jmmv }
86 1.1 jmmv
87 1.1 jmmv
88 1.1 jmmv /// Checks if the user has superpowers or not.
89 1.1 jmmv ///
90 1.1 jmmv /// \return True if the user is root, false otherwise.
91 1.1 jmmv bool
92 1.1 jmmv passwd_ns::user::is_root(void) const
93 1.1 jmmv {
94 1.1 jmmv return uid == 0;
95 1.1 jmmv }
96 1.1 jmmv
97 1.1 jmmv
98 1.1 jmmv /// Gets the current user.
99 1.1 jmmv ///
100 1.1 jmmv /// \return The current user.
101 1.1 jmmv passwd_ns::user
102 1.1 jmmv passwd_ns::current_user(void)
103 1.1 jmmv {
104 1.1 jmmv if (fake_current_user) {
105 1.1 jmmv const user u = fake_current_user.get();
106 1.1 jmmv LD(F("Current user is fake: %s") % format_user(u));
107 1.1 jmmv return u;
108 1.1 jmmv } else {
109 1.1 jmmv const user u = find_user_by_uid(::getuid());
110 1.1 jmmv LD(F("Current user is: %s") % format_user(u));
111 1.1 jmmv return u;
112 1.1 jmmv }
113 1.1 jmmv }
114 1.1 jmmv
115 1.1 jmmv
116 1.1 jmmv /// Gets information about a user by its name.
117 1.1 jmmv ///
118 1.1 jmmv /// \param name The name of the user to query.
119 1.1 jmmv ///
120 1.1 jmmv /// \return The information about the user.
121 1.1 jmmv ///
122 1.1 jmmv /// \throw std::runtime_error If the user does not exist.
123 1.1 jmmv passwd_ns::user
124 1.1 jmmv passwd_ns::find_user_by_name(const std::string& name)
125 1.1 jmmv {
126 1.1 jmmv if (mock_users.empty()) {
127 1.1 jmmv const struct ::passwd* pw = ::getpwnam(name.c_str());
128 1.1 jmmv if (pw == NULL)
129 1.1 jmmv throw std::runtime_error(F("Failed to get information about the "
130 1.1 jmmv "user '%s'") % name);
131 1.1 jmmv INV(pw->pw_name == name);
132 1.1 jmmv return user(pw->pw_name, pw->pw_uid, pw->pw_gid);
133 1.1 jmmv } else {
134 1.1 jmmv for (std::vector< user >::const_iterator iter = mock_users.begin();
135 1.1 jmmv iter != mock_users.end(); iter++) {
136 1.1 jmmv if ((*iter).name == name)
137 1.1 jmmv return *iter;
138 1.1 jmmv }
139 1.1 jmmv throw std::runtime_error(F("Failed to get information about the "
140 1.1 jmmv "user '%s'") % name);
141 1.1 jmmv }
142 1.1 jmmv }
143 1.1 jmmv
144 1.1 jmmv
145 1.1 jmmv /// Gets information about a user by its identifier.
146 1.1 jmmv ///
147 1.1 jmmv /// \param uid The identifier of the user to query.
148 1.1 jmmv ///
149 1.1 jmmv /// \return The information about the user.
150 1.1 jmmv ///
151 1.1 jmmv /// \throw std::runtime_error If the user does not exist.
152 1.1 jmmv passwd_ns::user
153 1.1 jmmv passwd_ns::find_user_by_uid(const unsigned int uid)
154 1.1 jmmv {
155 1.1 jmmv if (mock_users.empty()) {
156 1.1 jmmv const struct ::passwd* pw = ::getpwuid(uid);
157 1.1 jmmv if (pw == NULL)
158 1.1 jmmv throw std::runtime_error(F("Failed to get information about the "
159 1.1 jmmv "user with UID %s") % uid);
160 1.1 jmmv INV(pw->pw_uid == uid);
161 1.1 jmmv return user(pw->pw_name, pw->pw_uid, pw->pw_gid);
162 1.1 jmmv } else {
163 1.1 jmmv for (std::vector< user >::const_iterator iter = mock_users.begin();
164 1.1 jmmv iter != mock_users.end(); iter++) {
165 1.1 jmmv if ((*iter).uid == uid)
166 1.1 jmmv return *iter;
167 1.1 jmmv }
168 1.1 jmmv throw std::runtime_error(F("Failed to get information about the "
169 1.1 jmmv "user with UID %s") % uid);
170 1.1 jmmv }
171 1.1 jmmv }
172 1.1 jmmv
173 1.1 jmmv
174 1.1 jmmv /// Overrides the current user for testing purposes.
175 1.1 jmmv ///
176 1.1 jmmv /// This DOES NOT change the current privileges!
177 1.1 jmmv ///
178 1.1 jmmv /// \param new_current_user The new current user.
179 1.1 jmmv void
180 1.1 jmmv passwd_ns::set_current_user_for_testing(const user& new_current_user)
181 1.1 jmmv {
182 1.1 jmmv fake_current_user = new_current_user;
183 1.1 jmmv }
184 1.1 jmmv
185 1.1 jmmv
186 1.1 jmmv /// Overrides the current set of users for testing purposes.
187 1.1 jmmv ///
188 1.1 jmmv /// \param users The new users set. Cannot be empty.
189 1.1 jmmv void
190 1.1 jmmv passwd_ns::set_mock_users_for_testing(const std::vector< user >& users)
191 1.1 jmmv {
192 1.1 jmmv PRE(!users.empty());
193 1.1 jmmv mock_users = users;
194 1.1 jmmv }
195