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