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"
42 #include "blocxx/GlobalMutex.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
61 
62 BLOCXX_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 
84 namespace BLOCXX_NAMESPACE
85 {
86 
87 namespace 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 
160 namespace
161 {
162 GlobalMutex g_getpwMutex = BLOCXX_GLOBAL_MUTEX_INIT();
163 }
164 
165 namespace // 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 
209 String 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 
265 UserID
266 getUserId(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