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