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