blocxx

UserUtils.cpp

Go to the documentation of this file.
00001 /*******************************************************************************
00002 * Copyright (C) 2005, Vintela, Inc. All rights reserved.
00003 * Copyright (C) 2006, Novell, Inc. All rights reserved.
00004 * 
00005 * Redistribution and use in source and binary forms, with or without
00006 * modification, are permitted provided that the following conditions are met:
00007 * 
00008 *     * Redistributions of source code must retain the above copyright notice,
00009 *       this list of conditions and the following disclaimer.
00010 *     * Redistributions in binary form must reproduce the above copyright
00011 *       notice, this list of conditions and the following disclaimer in the
00012 *       documentation and/or other materials provided with the distribution.
00013 *     * Neither the name of 
00014 *       Vintela, Inc., 
00015 *       nor Novell, Inc., 
00016 *       nor the names of its contributors or employees may be used to 
00017 *       endorse or promote products derived from this software without 
00018 *       specific prior written permission.
00019 * 
00020 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00021 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00022 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00023 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00024 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00025 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00026 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00027 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00028 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00029 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00030 * POSSIBILITY OF SUCH DAMAGE.
00031 *******************************************************************************/
00032 
00033 
00039 #include "blocxx/BLOCXX_config.h"
00040 #include "blocxx/Mutex.hpp"
00041 #include "blocxx/MutexLock.hpp"
00042 #include "blocxx/GlobalMutex.hpp"
00043 #include "blocxx/UserUtils.hpp"
00044 
00045 #ifdef BLOCXX_HAVE_UNISTD_H
00046 #include <unistd.h>
00047 #endif
00048 
00049 #ifdef BLOCXX_HAVE_SYS_TYPES_H
00050 #include <sys/types.h>
00051 #endif
00052 
00053 #ifdef BLOCXX_HAVE_PWD_H
00054 #include <pwd.h>
00055 #endif
00056 
00057 #include <cerrno>
00058 #include <vector>
00059 
00060 #ifdef BLOCXX_WIN32
00061 
00062 BLOCXX_NAMESPACE::UserId geteuid(void )
00063 {
00064    // SID/uid Win32/NIX wrapper 
00065    BLOCXX_NAMESPACE::UserId sid = (BLOCXX_NAMESPACE::UserId)NULL;
00066    HANDLE pToken = (HANDLE)0L;
00067    DWORD bufLength = 256;
00068    static int* tkUser[256]; // only a static buffer we need with no SID copy privileges :(
00069 
00070    if ( ::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &pToken) )
00071    {
00072       ::GetTokenInformation(pToken, TokenUser, tkUser, bufLength, &bufLength);
00073       sid = ((TOKEN_USER*)tkUser)->User.Sid;
00074       TCHAR sName[MAX_PATH], sDName[MAX_PATH];
00075       DWORD sNameLen, sDNameLen = sNameLen = MAX_PATH;
00076       SID_NAME_USE eUse;
00077       ::LookupAccountSid( NULL, sid, sName, &sNameLen, sDName, &sDNameLen, &eUse);
00078       CloseHandle(pToken);
00079    }
00080    return sid;
00081 }
00082 #endif //BLOCXX_WIN32
00083 
00084 namespace BLOCXX_NAMESPACE
00085 {
00086 
00087 namespace UserUtils
00088 {
00089 
00091 String getEffectiveUserId()
00092 {
00093 #ifdef BLOCXX_WIN32
00094    // TODO
00095    // The user ID is represented by a SID on Win32. Going to return 0 for
00096    // admin user on win32 for now. Eventually blocxx will
00097    // deal with userid on Win32 the proper way.
00098 
00099    // 20070625 Anton Afanasiev - maybe the better idea is to use ConvertSidToStringSid routing
00100    // the code below implements the same
00101    PSID_IDENTIFIER_AUTHORITY psia;
00102    DWORD dwSubAuthorities;
00103    DWORD dwSidRev=SID_REVISION;
00104    DWORD dwCounter;
00105    DWORD dwSidSize;
00106    UserId uid = ::geteuid();
00107    String strResult, strSubResult;
00108 
00109    if (!uid || !IsValidSid(uid))
00110       return String();
00111    psia = GetSidIdentifierAuthority(uid);
00112    dwSubAuthorities = *GetSidSubAuthorityCount(uid);
00113    dwSidSize = (15 + 12 + (12 * dwSubAuthorities) + 1) * sizeof(TCHAR);
00114    if ( (psia->Value[0] != 0) || (psia->Value[1] != 0) )
00115    {
00116       strSubResult.format(
00117          TEXT("0x%02hx%02hx%02hx%02hx%02hx%02hx"),
00118          (USHORT)psia->Value[0],
00119          (USHORT)psia->Value[1],
00120          (USHORT)psia->Value[2],
00121          (USHORT)psia->Value[3],
00122          (USHORT)psia->Value[4],
00123          (USHORT)psia->Value[5]);
00124    }
00125    else
00126    {
00127       strSubResult.format(
00128          TEXT("%lu"),
00129          (ULONG)(psia->Value[5]      )   +
00130          (ULONG)(psia->Value[4] <<  8)   +
00131          (ULONG)(psia->Value[3] << 16)   +
00132          (ULONG)(psia->Value[2] << 24) );
00133    }
00134    
00135    for (dwCounter=0 ; dwCounter < dwSubAuthorities ; dwCounter++)
00136    {
00137       strSubResult.format(
00138          TEXT("%s-%lu"), strSubResult.c_str(),
00139          *GetSidSubAuthority(uid, dwCounter) );
00140    }
00141 
00142    strResult.format(TEXT("S-%lu-%s"), dwSidRev, strSubResult);
00143    return strResult;
00144 #else
00145    return String(Int64(::geteuid()));
00146 #endif
00147 }
00148 
00150 String getCurrentUserName()
00151 {
00152    bool ok;
00153 #ifdef BLOCXX_WIN32
00154    return getUserName(geteuid(), ok);
00155 #else
00156    return getUserName(getuid(),ok);
00157 #endif
00158 }
00159 
00160 namespace
00161 {
00162 GlobalMutex g_getpwMutex = BLOCXX_GLOBAL_MUTEX_INIT();
00163 }
00164 
00165 namespace // anonymous
00166 {
00167    // Get a sysconf value.  If no value is set (or another error occurs), return the default value.
00168    long getSysconfValue(int name, long default_value, int& error)
00169    {
00170 #ifdef BLOCXX_WIN32
00171 #pragma message(Reminder "TODO: Implement for Win if you use getSysconfValue not only for _SC_GETPW_R_SIZE_MAX")
00172       error = 0;
00173       return default_value; 
00174 #else
00175       errno = 0;
00176 
00177       long l = sysconf(name);
00178 
00179       if( l == -1 )
00180       {
00181          if( errno == 0 )
00182          {
00183             // The POSIX standard says this means the limit is indefinite (not infinite).
00184             error = 0;
00185             return default_value;
00186          }
00187          else
00188          {
00189             error = errno;
00190             return default_value;
00191          }
00192       }
00193       else
00194       {
00195          error = 0;
00196          return l;
00197       }
00198 #endif
00199    }
00200 
00201    long getSysconfValue(int name, long default_value)
00202    {
00203       int unused;
00204       return getSysconfValue(name, default_value, unused);
00205    }
00206 } // end annymous namespace
00207 
00209 String getUserName(uid_t uid,bool& ok)
00210 {
00211 #ifdef BLOCXX_WIN32
00212    // TODO
00213    // Ignore uid for right now. Just return the current User (WRONG!)
00214    // Need to come back to this later when the uid_t stuff is worked out.
00215 
00216    // 20070625 Anton Afanasiev
00217    TCHAR cchName[256], cchDomainName[256];
00218    SID_NAME_USE snuOutVar;
00219    DWORD cchNameBufLen = sizeof(cchName), cchDomainNameBufLen = sizeof(cchDomainName);
00220 
00221    ok = ::LookupAccountSid(NULL, 
00222             uid,
00223             cchName,
00224             &cchNameBufLen,
00225             cchDomainName,
00226             &cchDomainNameBufLen,
00227             &snuOutVar);
00228    return String(cchName);
00229 #else
00230 
00231 #ifdef BLOCXX_HAVE_GETPWUID_R
00232    passwd pw;
00233    size_t const additionalSize =
00234 #ifdef _SC_GETPW_R_SIZE_MAX
00235       getSysconfValue(_SC_GETPW_R_SIZE_MAX, 10240);
00236 #else
00237       10240;
00238 #endif
00239    std::vector<char> additional(additionalSize);
00240    passwd* result;
00241    int rv = 0;
00242    do
00243    {
00244       rv = ::getpwuid_r(uid, &pw, &additional[0], additional.size(), &result);
00245       if (rv == ERANGE)
00246       {
00247          additional.resize(additional.size() * 2);
00248       }
00249    } while (rv == ERANGE);
00250 #else
00251    MutexLock lock(g_getpwMutex);
00252    passwd* result = ::getpwuid(uid);
00253 #endif  
00254    if (result)
00255    {
00256       ok = true;
00257       return result->pw_name;
00258    }
00259    ok = false;
00260    return "";
00261 #endif
00262 }
00263 
00265 UserID
00266 getUserId(const String& userName, bool& validUserName)
00267 {
00268    validUserName = false;
00269 
00270 #ifdef BLOCXX_WIN32
00271    // 20070625 Anton Afanasiev
00272    static DWORD uid[64]; // AA: do we really need for 'static' here?
00273    DWORD cbUid = sizeof(uid) * sizeof(DWORD);
00274    SID_NAME_USE snuOutVar; 
00275    DWORD cbDomainBufSize = MAX_PATH;
00276    TCHAR strDomainBuf[MAX_PATH] = {0};
00277 
00278    return (validUserName=::LookupAccountName(
00279          NULL, 
00280          userName.c_str(),
00281          &uid,
00282          &cbUid,
00283          strDomainBuf,
00284          &cbDomainBufSize,
00285          &snuOutVar))? &uid : NULL;
00286 
00287 #else
00288 
00289 
00290 #ifdef BLOCXX_HAVE_GETPWNAM_R
00291    size_t bufsize =
00292 #ifdef _SC_GETPW_R_SIZE_MAX
00293       getSysconfValue(_SC_GETPW_R_SIZE_MAX, 10240);
00294 #else
00295       1024;
00296 #endif
00297    std::vector<char> buf(bufsize);
00298    struct passwd pwd;
00299    passwd* result = 0;
00300    int rv = 0;
00301    do
00302    {
00303       rv = ::getpwnam_r(userName.c_str(), &pwd, &buf[0], bufsize, &result);
00304       if (rv == ERANGE)
00305       {
00306          buf.resize(buf.size() * 2);
00307       }
00308    } while (rv == ERANGE);
00309 
00310    if (rv != 0)
00311    {
00312       return INVALID_USERID;
00313    }
00314 
00315 #else
00316    MutexLock ml(g_getpwMutex);
00317    struct passwd* result;
00318    result = ::getpwnam(userName.c_str());
00319 #endif
00320    if (result)
00321    {
00322       validUserName = true;
00323       return result->pw_uid;
00324    }
00325    return INVALID_USERID;
00326 #endif
00327 }
00328 } // end namespace UserUtils
00329 } // end namespace BLOCXX_NAMESPACE
00330 
00331