blocxx
UserUtils.cpp
Go to the documentation of this file.
1/*******************************************************************************
2* Copyright (C) 2005, Vintela, Inc. All rights reserved.
3* Copyright (C) 2006, Novell, Inc. All rights reserved.
4*
5* Redistribution and use in source and binary forms, with or without
6* modification, are permitted provided that the following conditions are met:
7*
8* * Redistributions of source code must retain the above copyright notice,
9* this list of conditions and the following disclaimer.
10* * Redistributions in binary form must reproduce the above copyright
11* notice, this list of conditions and the following disclaimer in the
12* documentation and/or other materials provided with the distribution.
13* * Neither the name of
14* Vintela, Inc.,
15* nor Novell, Inc.,
16* nor the names of its contributors or employees may be used to
17* endorse or promote products derived from this software without
18* specific prior written permission.
19*
20* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30* POSSIBILITY OF SUCH DAMAGE.
31*******************************************************************************/
32
33
39#include "blocxx/BLOCXX_config.h"
40#include "blocxx/Mutex.hpp"
41#include "blocxx/MutexLock.hpp"
43#include "blocxx/UserUtils.hpp"
44
45#ifdef BLOCXX_HAVE_UNISTD_H
46#include <unistd.h>
47#endif
48
49#ifdef BLOCXX_HAVE_SYS_TYPES_H
50#include <sys/types.h>
51#endif
52
53#ifdef BLOCXX_HAVE_PWD_H
54#include <pwd.h>
55#endif
56
57#include <cerrno>
58#include <vector>
59
60#ifdef BLOCXX_WIN32
62BLOCXX_NAMESPACE::UserId geteuid(void )
63{
64 // SID/uid Win32/NIX wrapper
66 HANDLE pToken = (HANDLE)0L;
67 DWORD bufLength = 256;
68 static int* tkUser[256]; // only a static buffer we need with no SID copy privileges :(
69
70 if ( ::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &pToken) )
71 {
72 ::GetTokenInformation(pToken, TokenUser, tkUser, bufLength, &bufLength);
73 sid = ((TOKEN_USER*)tkUser)->User.Sid;
74 TCHAR sName[MAX_PATH], sDName[MAX_PATH];
75 DWORD sNameLen, sDNameLen = sNameLen = MAX_PATH;
76 SID_NAME_USE eUse;
77 ::LookupAccountSid( NULL, sid, sName, &sNameLen, sDName, &sDNameLen, &eUse);
78 CloseHandle(pToken);
79 }
80 return sid;
81}
82#endif //BLOCXX_WIN32
83
84namespace BLOCXX_NAMESPACE
85{
86
87namespace UserUtils
88{
89
92{
93#ifdef BLOCXX_WIN32
94 // TODO
95 // The user ID is represented by a SID on Win32. Going to return 0 for
96 // admin user on win32 for now. Eventually blocxx will
97 // deal with userid on Win32 the proper way.
98
99 // 20070625 Anton Afanasiev - maybe the better idea is to use ConvertSidToStringSid routing
100 // the code below implements the same
101 PSID_IDENTIFIER_AUTHORITY psia;
102 DWORD dwSubAuthorities;
103 DWORD dwSidRev=SID_REVISION;
104 DWORD dwCounter;
105 DWORD dwSidSize;
106 UserId uid = ::geteuid();
107 String strResult, strSubResult;
108
109 if (!uid || !IsValidSid(uid))
110 return String();
111 psia = GetSidIdentifierAuthority(uid);
112 dwSubAuthorities = *GetSidSubAuthorityCount(uid);
113 dwSidSize = (15 + 12 + (12 * dwSubAuthorities) + 1) * sizeof(TCHAR);
114 if ( (psia->Value[0] != 0) || (psia->Value[1] != 0) )
115 {
116 strSubResult.format(
117 TEXT("0x%02hx%02hx%02hx%02hx%02hx%02hx"),
118 (USHORT)psia->Value[0],
119 (USHORT)psia->Value[1],
120 (USHORT)psia->Value[2],
121 (USHORT)psia->Value[3],
122 (USHORT)psia->Value[4],
123 (USHORT)psia->Value[5]);
124 }
125 else
126 {
127 strSubResult.format(
128 TEXT("%lu"),
129 (ULONG)(psia->Value[5] ) +
130 (ULONG)(psia->Value[4] << 8) +
131 (ULONG)(psia->Value[3] << 16) +
132 (ULONG)(psia->Value[2] << 24) );
133 }
134
135 for (dwCounter=0 ; dwCounter < dwSubAuthorities ; dwCounter++)
136 {
137 strSubResult.format(
138 TEXT("%s-%lu"), strSubResult.c_str(),
139 *GetSidSubAuthority(uid, dwCounter) );
140 }
141
142 strResult.format(TEXT("S-%lu-%s"), dwSidRev, strSubResult);
143 return strResult;
144#else
145 return String(Int64(::geteuid()));
146#endif
147}
148
151{
152 bool ok;
153#ifdef BLOCXX_WIN32
154 return getUserName(geteuid(), ok);
155#else
156 return getUserName(getuid(),ok);
157#endif
158}
159
160namespace
161{
163}
164
165namespace // anonymous
166{
167 // Get a sysconf value. If no value is set (or another error occurs), return the default value.
168 long getSysconfValue(int name, long default_value, int& error)
169 {
170#ifdef BLOCXX_WIN32
171#pragma message(Reminder "TODO: Implement for Win if you use getSysconfValue not only for _SC_GETPW_R_SIZE_MAX")
172 error = 0;
173 return default_value;
174#else
175 errno = 0;
176
177 long l = sysconf(name);
178
179 if( l == -1 )
180 {
181 if( errno == 0 )
182 {
183 // The POSIX standard says this means the limit is indefinite (not infinite).
184 error = 0;
185 return default_value;
186 }
187 else
188 {
189 error = errno;
190 return default_value;
191 }
192 }
193 else
194 {
195 error = 0;
196 return l;
197 }
198#endif
199 }
200
201 long getSysconfValue(int name, long default_value)
202 {
203 int unused;
204 return getSysconfValue(name, default_value, unused);
205 }
206} // end annymous namespace
207
209String getUserName(uid_t uid,bool& ok)
210{
211#ifdef BLOCXX_WIN32
212 // TODO
213 // Ignore uid for right now. Just return the current User (WRONG!)
214 // Need to come back to this later when the uid_t stuff is worked out.
215
216 // 20070625 Anton Afanasiev
217 TCHAR cchName[256], cchDomainName[256];
218 SID_NAME_USE snuOutVar;
219 DWORD cchNameBufLen = sizeof(cchName), cchDomainNameBufLen = sizeof(cchDomainName);
220
221 ok = ::LookupAccountSid(NULL,
222 uid,
223 cchName,
224 &cchNameBufLen,
225 cchDomainName,
226 &cchDomainNameBufLen,
227 &snuOutVar);
228 return String(cchName);
229#else
230
231#ifdef BLOCXX_HAVE_GETPWUID_R
232 passwd pw;
233 size_t const additionalSize =
234#ifdef _SC_GETPW_R_SIZE_MAX
235 getSysconfValue(_SC_GETPW_R_SIZE_MAX, 10240);
236#else
237 10240;
238#endif
239 std::vector<char> additional(additionalSize);
240 passwd* result;
241 int rv = 0;
242 do
243 {
244 rv = ::getpwuid_r(uid, &pw, &additional[0], additional.size(), &result);
245 if (rv == ERANGE)
246 {
247 additional.resize(additional.size() * 2);
248 }
249 } while (rv == ERANGE);
250#else
251 MutexLock lock(g_getpwMutex);
252 passwd* result = ::getpwuid(uid);
253#endif
254 if (result)
255 {
256 ok = true;
257 return result->pw_name;
258 }
259 ok = false;
260 return "";
261#endif
262}
263
265UserID
266getUserId(const String& userName, bool& validUserName)
267{
268 validUserName = false;
269
270#ifdef BLOCXX_WIN32
271 // 20070625 Anton Afanasiev
272 static DWORD uid[64]; // AA: do we really need for 'static' here?
273 DWORD cbUid = sizeof(uid) * sizeof(DWORD);
274 SID_NAME_USE snuOutVar;
275 DWORD cbDomainBufSize = MAX_PATH;
276 TCHAR strDomainBuf[MAX_PATH] = {0};
277
278 return (validUserName=::LookupAccountName(
279 NULL,
280 userName.c_str(),
281 &uid,
282 &cbUid,
283 strDomainBuf,
284 &cbDomainBufSize,
285 &snuOutVar))? &uid : NULL;
286
287#else
288
289
290#ifdef BLOCXX_HAVE_GETPWNAM_R
291 size_t bufsize =
292#ifdef _SC_GETPW_R_SIZE_MAX
293 getSysconfValue(_SC_GETPW_R_SIZE_MAX, 10240);
294#else
295 1024;
296#endif
297 std::vector<char> buf(bufsize);
298 struct passwd pwd;
299 passwd* result = 0;
300 int rv = 0;
301 do
302 {
303 rv = ::getpwnam_r(userName.c_str(), &pwd, &buf[0], bufsize, &result);
304 if (rv == ERANGE)
305 {
306 buf.resize(buf.size() * 2);
307 }
308 } while (rv == ERANGE);
309
310 if (rv != 0)
311 {
312 return INVALID_USERID;
313 }
314
315#else
316 MutexLock ml(g_getpwMutex);
317 struct passwd* result;
318 result = ::getpwnam(userName.c_str());
319#endif
320 if (result)
321 {
322 validUserName = true;
323 return result->pw_uid;
324 }
325 return INVALID_USERID;
326#endif
327}
328} // end namespace UserUtils
329} // end namespace BLOCXX_NAMESPACE
330
331
#define BLOCXX_GLOBAL_MUTEX_INIT()
const char * name
This class can be used to store a global variable that is lazily initialized in a thread safe manner.
This String class is an abstract data type that represents as NULL terminated string of characters.
Definition String.hpp:67
const char * c_str() const
Definition String.cpp:905
int format(const char *fmt,...)
Format this string according to the given format and variable argument list (printf style)
Definition String.cpp:369
String getEffectiveUserId()
Get the effective user id.
Definition UserUtils.cpp:91
UserID getUserId(const String &userName, bool &validUserName)
Convert a textual username into a platform native user type.
String getUserName(uid_t uid, bool &ok)
If the username is invalid, or if getUserName() fails for any other reason, 'success' will be set to ...
Taken from RFC 1321.