Line data Source code
1 : // DUNE DAQ modification notice:
2 : // This file has been modified from the original ATLAS system source for the DUNE DAQ project.
3 : // Fork baseline commit: system-00-00-20 (2020-09-25).
4 : // Renamed since fork: yes (from src/User.cxx to src/User.cpp).
5 :
6 : /*
7 : * User.cxx
8 : * OksSystem
9 : *
10 : * Created by Matthias Wiesmann on 03.02.05.
11 : * Copyright 2005 CERN. All rights reserved.
12 : *
13 : */
14 :
15 : #include <pwd.h>
16 :
17 : #include <iostream>
18 : #include <sstream>
19 :
20 : #include "ers/ers.hpp"
21 :
22 : #include "okssystem/User.hpp"
23 : #include "okssystem/exceptions.hpp"
24 :
25 : const OksSystem::User OksSystem::User::ROOT(0);
26 :
27 19 : OksSystem::User::User() throw()
28 : {
29 19 : m_user_id = ::getuid();
30 19 : } // User
31 :
32 58 : OksSystem::User::User(uid_t user_id) throw()
33 : {
34 58 : m_user_id = user_id;
35 58 : } // User
36 :
37 0 : OksSystem::User::User(const std::string& s_name)
38 : {
39 :
40 0 : errno = 0;
41 0 : long bufSize = ::sysconf(_SC_GETPW_R_SIZE_MAX);
42 :
43 0 : if (bufSize == -1) {
44 0 : if (errno == 0) {
45 : bufSize = 1024;
46 : } else {
47 0 : std::string message = "with argument _SC_GETPW_R_SIZE_MAX while getting info about user " + s_name;
48 0 : throw OksSystem::OksSystemCallIssue(ERS_HERE, errno, "sysconf", message.c_str());
49 0 : }
50 : }
51 :
52 0 : struct passwd pwd;
53 0 : struct passwd* result;
54 0 : char* buf = new char[bufSize];
55 0 : errno = 0;
56 0 : int res = ::getpwnam_r(s_name.c_str(), &pwd, buf, bufSize, &result);
57 0 : if (res == 0) {
58 0 : if (result != 0) {
59 0 : m_user_id = result->pw_uid;
60 : } else {
61 0 : delete[] buf;
62 0 : std::string eMsg = "User " + s_name + " not found";
63 0 : throw OksSystem::OksSystemCallIssue(ERS_HERE, errno, "getpwnam_r", eMsg.c_str());
64 0 : }
65 : } else {
66 0 : delete[] buf;
67 0 : std::string message = "while getting info about user " + s_name;
68 0 : throw OksSystem::OksSystemCallIssue(ERS_HERE, res, "getpwnam_r", message.c_str());
69 0 : }
70 0 : delete[] buf;
71 :
72 0 : m_user_name = s_name;
73 0 : } // User
74 :
75 0 : OksSystem::User::User(const User& other) throw()
76 : {
77 0 : m_user_id = other.m_user_id;
78 0 : m_user_name = other.m_user_name;
79 0 : } // User
80 :
81 : // Operators
82 : // =========
83 :
84 0 : OksSystem::User::operator uid_t() const throw()
85 : {
86 0 : return m_user_id;
87 : } // uid_t
88 :
89 0 : OksSystem::User::operator std::string() const
90 : {
91 0 : return name();
92 : } // string
93 :
94 0 : OksSystem::User::operator const char*() const
95 : {
96 0 : if (m_user_name.empty()) {
97 0 : resolve();
98 : }
99 0 : return m_user_name.c_str();
100 : } // char*
101 :
102 : // Methods
103 : // =========
104 :
105 : /** Returns the user_id for user
106 : * \return user-id
107 : */
108 :
109 : uid_t
110 0 : OksSystem::User::identity() const throw()
111 : {
112 0 : return m_user_id;
113 : } // identity
114 :
115 : /** This method is responsible for filling in the mutable fields of the class
116 : * when needed, this is done by calling the \c getpwuid function,
117 : * all fields of the object are then filled in.
118 : * \throw OksSystem::OksSystemCallIssue if the user information cannot be found
119 : */
120 :
121 : void
122 0 : OksSystem::User::resolve() const
123 : {
124 :
125 0 : errno = 0;
126 0 : long bufSize = ::sysconf(_SC_GETPW_R_SIZE_MAX);
127 :
128 0 : if (bufSize == -1) {
129 0 : if (errno == 0) {
130 : bufSize = 1024;
131 : } else {
132 0 : std::ostringstream message;
133 0 : message << "with argument _SC_GETPW_R_SIZE_MAX while getting info about user with id " << m_user_id;
134 0 : throw OksSystem::OksSystemCallIssue(ERS_HERE, errno, "sysconf", message.str().c_str());
135 0 : }
136 : }
137 :
138 0 : struct passwd pwd;
139 0 : struct passwd* result;
140 0 : char* buf = new char[bufSize];
141 0 : errno = 0;
142 0 : int res = ::getpwuid_r(m_user_id, &pwd, buf, bufSize, &result);
143 0 : if (res == 0) {
144 0 : if (result != 0) {
145 0 : m_user_name = std::string(result->pw_name);
146 0 : m_user_home = std::string(result->pw_dir);
147 0 : m_user_real_name = std::string(result->pw_gecos);
148 : } else {
149 0 : delete[] buf;
150 0 : std::ostringstream eMsg;
151 0 : eMsg << "User " << m_user_id << " not found";
152 0 : throw OksSystem::OksSystemCallIssue(ERS_HERE, errno, "getpwuid_r", eMsg.str().c_str());
153 0 : }
154 : } else {
155 0 : delete[] buf;
156 0 : std::ostringstream message;
157 0 : message << "while getting info about user with id " << m_user_id;
158 0 : throw OksSystem::OksSystemCallIssue(ERS_HERE, res, "getpwnam_r", message.str().c_str());
159 0 : }
160 0 : delete[] buf;
161 :
162 0 : } //
163 :
164 : /** This method is the same as \c resolve() but does not throw exceptions.
165 : * Instead the method silently fails
166 : * \see OksSystem::User::resolve()
167 : */
168 :
169 : void
170 19 : OksSystem::User::resolve_safe() const throw()
171 : {
172 :
173 19 : errno = 0;
174 19 : long bufSize = ::sysconf(_SC_GETPW_R_SIZE_MAX);
175 :
176 19 : if (bufSize == -1) {
177 0 : if (errno == 0) {
178 : bufSize = 1024;
179 : } else {
180 0 : m_user_name = "unknown";
181 0 : m_user_home = "unknown";
182 0 : m_user_real_name = "unknown";
183 0 : return;
184 : }
185 : }
186 :
187 19 : struct passwd pwd;
188 19 : struct passwd* result;
189 19 : char* buf = new char[bufSize];
190 19 : int res = ::getpwuid_r(m_user_id, &pwd, buf, bufSize, &result);
191 19 : if (res == 0) {
192 19 : if (result != 0) {
193 19 : m_user_name = std::string(result->pw_name);
194 19 : m_user_home = std::string(result->pw_dir);
195 19 : m_user_real_name = std::string(result->pw_gecos);
196 : } else {
197 0 : m_user_name = "unknown";
198 0 : m_user_home = "unknown";
199 0 : m_user_real_name = "unknown";
200 : }
201 : } else {
202 0 : m_user_name = "unknown";
203 0 : m_user_home = "unknown";
204 0 : m_user_real_name = "unknown";
205 : }
206 19 : delete[] buf;
207 :
208 : } // resolve_safe
209 :
210 : /** Gets the (short) name of the user
211 : * \return the name of user
212 : */
213 :
214 : const std::string&
215 0 : OksSystem::User::name() const
216 : {
217 0 : if (m_user_name.empty()) {
218 0 : resolve();
219 : }
220 0 : return m_user_name;
221 : } // name
222 :
223 : /** Gets the (short) name of the user - no error is thrown in case of problem
224 : * \return the name of user
225 : */
226 :
227 : const std::string&
228 19 : OksSystem::User::name_safe() const throw()
229 : {
230 19 : if (m_user_name.empty()) {
231 19 : resolve_safe();
232 : }
233 19 : return m_user_name;
234 : } // name
235 :
236 : /** Gets the home directory of the user
237 : * \return path to home directory
238 : */
239 :
240 : const std::string&
241 0 : OksSystem::User::home() const
242 : {
243 0 : if (m_user_home.empty()) {
244 0 : resolve();
245 : }
246 0 : return m_user_home;
247 : } // home
248 :
249 : /** Gets the 'real name' of the user
250 : * \return real name
251 : */
252 :
253 : const std::string&
254 0 : OksSystem::User::real_name() const
255 : {
256 0 : if (m_user_real_name.empty()) {
257 0 : resolve();
258 : }
259 0 : return m_user_real_name;
260 : } // real_name
261 :
262 : /** Sets the user-identity of the current process to this user.
263 : * This method will only succeed if the current user has sufficient privileges to changed uids
264 : * (typically because the current user is root).
265 : */
266 :
267 : void
268 0 : OksSystem::User::setuid() const
269 : {
270 0 : const int status = ::setuid(m_user_id);
271 0 : if (status < 0) {
272 0 : std::ostringstream message;
273 0 : message << "while setting the effective user ID to " << m_user_id << "(" << this->name_safe() << ")";
274 0 : throw OksSystem::OksSystemCallIssue(ERS_HERE, errno, "setuid", message.str().c_str());
275 0 : }
276 0 : } // setuid
277 :
278 : /** Output operator, writes username followed by uid between parenthesis
279 : * \param stream the stream to write into
280 : * \param user the user object to write
281 : * \return parameter stream
282 : */
283 :
284 : std::ostream&
285 0 : operator<<(std::ostream& stream, const OksSystem::User& user) throw()
286 : {
287 0 : unsigned int i = (unsigned int)user.identity();
288 0 : const std::string name = user.name_safe();
289 0 : stream << name << '(' << i << ')';
290 0 : return stream;
291 0 : } // operator<<
292 :
293 : /** Equality operator
294 : * \param a first user to compare
295 : * \param b second user to compare
296 : * \return true if they are equal
297 : */
298 :
299 : bool
300 0 : operator==(const OksSystem::User& a, const OksSystem::User& b) throw()
301 : {
302 0 : return a.identity() == b.identity();
303 : } //
304 :
305 : /** Inequality operator
306 : * \param a first user to compare
307 : * \param b second user to compare
308 : * \return true if they are not equal
309 : */
310 :
311 : bool
312 0 : operator!=(const OksSystem::User& a, const OksSystem::User& b) throw()
313 : {
314 0 : return a.identity() != b.identity();
315 : } //
|