Quelle security.cxx
Sprache: C
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project .
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License , v . 2 . 0 . If a copy of the MPL was not distributed with this
* file , You can obtain one at http : //mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice :
*
* Licensed to the Apache Software Foundation ( ASF ) under one or more
* contributor license agreements . See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership . The ASF licenses this file to you under the Apache
* License , Version 2 . 0 ( the " License " ) ; you may not use this file
* except in compliance with the License . You may obtain a copy of
* the License at http : //www.apache.org/licenses/LICENSE-2.0 .
*/
#include "system.h"
#include <userenv.h>
#include <cassert>
#include <osl/security.h>
#include <osl/diagnose.h>
#include <osl/thread.h>
#include <osl/file.h>
#include <systools/win32/comtools.hxx>
#include <systools/win32/uwinapi.h>
#include <sddl.h>
#include <sal/macros.h>
#include <sal/log.hxx>
#include <o3tl/char16_t2wchar_t.hxx>
#include "secimpl.hxx"
/* To get an impersonation token we need to create an impersonation
duplicate so every access token has to be created with duplicate
access rights */
#define TOKEN_DUP_QUERY (TOKEN_QUERY|TOKEN_DUPLICATE)
static bool GetSpecialFolder(rtl_uString **strPath, REFKNOWNFOLDERID rFolder);
// We use LPCTSTR here, because we use it with SE_foo_NAME constants
// which are defined in winnt.h as UNICODE-dependent TEXT("PrivilegeName")
static bool Privilege(LPCTSTR pszPrivilege, bool bEnable);
static bool getUserNameImpl(oslSecurity Security, rtl_uString **strName, bool bIncludeDomain);
oslSecurity SAL_CALL osl_getCurrentSecurity(void )
{
oslSecurityImpl* pSecImpl = static_cast <oslSecurityImpl *>(malloc(sizeof (oslSecurityImpl)));
if (pSecImpl)
{
pSecImpl->m_pNetResource = nullptr;
pSecImpl->m_User[0 ] = '\0' ;
pSecImpl->m_hToken = nullptr;
pSecImpl->m_hProfile = nullptr;
}
return pSecImpl;
}
oslSecurityError SAL_CALL osl_loginUser( rtl_uString *strUserName, rtl_uString *strPasswd, oslSecurity *pSecurity )
{
oslSecurityError ret;
sal_Unicode* strUser;
sal_Unicode* strDomain = o3tl::toU(_wcsdup(o3tl::toW(rtl_uString_getStr(strUserName))));
HANDLE hUserToken;
LUID luid;
if (nullptr != (strUser = o3tl::toU(wcschr(o3tl::toW(strDomain), L'/' ))))
*strUser++ = L'\0' ;
else
{
strUser = strDomain;
strDomain = nullptr;
}
// this process must have the right: 'act as a part of operatingsystem'
OSL_ASSERT(LookupPrivilegeValue(nullptr, SE_TCB_NAME, &luid));
(void ) luid;
if (LogonUserW(o3tl::toW(strUser), strDomain ? o3tl::toW(strDomain) : L"" , o3tl::toW(rtl_uString_getStr(strPasswd)),
LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
&hUserToken))
{
oslSecurityImpl* pSecImpl = static_cast <oslSecurityImpl *>(malloc(sizeof (oslSecurityImpl)));
if (pSecImpl)
{
pSecImpl->m_pNetResource = nullptr;
pSecImpl->m_hToken = hUserToken;
pSecImpl->m_hProfile = nullptr;
wcscpy(o3tl::toW(pSecImpl->m_User), o3tl::toW(strUser));
}
*pSecurity = pSecImpl;
ret = pSecImpl ? osl_Security_E_None : osl_Security_E_Unknown;
}
else
{
ret = osl_Security_E_UserUnknown;
}
if (strDomain)
free(strDomain);
else
free(strUser);
return ret;
}
oslSecurityError SAL_CALL osl_loginUserOnFileServer(rtl_uString *strUserName,
rtl_uString *strPasswd,
rtl_uString *strFileServer,
oslSecurity *pSecurity)
{
oslSecurityError ret;
DWORD err;
NETRESOURCEW netResource;
sal_Unicode* remoteName;
sal_Unicode* userName;
remoteName = static_cast <sal_Unicode *>(malloc((rtl_uString_getLength(strFileServer) + rtl_uString_getLength(strUserName) + 4 ) * sizeof (sal_Unicode)));
userName = static_cast <sal_Unicode *>(malloc((rtl_uString_getLength(strFileServer) + rtl_uString_getLength(strUserName) + 2 ) * sizeof (sal_Unicode)));
wcscpy(o3tl::toW(remoteName), L"\\\\" );
wcscat(o3tl::toW(remoteName), o3tl::toW(rtl_uString_getStr(strFileServer)));
wcscat(o3tl::toW(remoteName), L"\\" );
wcscat(o3tl::toW(remoteName), o3tl::toW(rtl_uString_getStr(strUserName)));
wcscpy(o3tl::toW(userName), o3tl::toW(rtl_uString_getStr(strFileServer)));
wcscat(o3tl::toW(userName), L"\\" );
wcscat(o3tl::toW(userName), o3tl::toW(rtl_uString_getStr(strUserName)));
netResource.dwScope = RESOURCE_GLOBALNET;
netResource.dwType = RESOURCETYPE_DISK;
netResource.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
netResource.dwUsage = RESOURCEUSAGE_CONNECTABLE;
netResource.lpLocalName = nullptr;
netResource.lpRemoteName = o3tl::toW(remoteName);
netResource.lpComment = nullptr;
netResource.lpProvider = nullptr;
err = WNetAddConnection2W(&netResource, o3tl::toW(rtl_uString_getStr(strPasswd)), o3tl::toW(userName), 0 );
if ((err == NO_ERROR) || (err == ERROR_ALREADY_ASSIGNED))
{
oslSecurityImpl* pSecImpl = static_cast <oslSecurityImpl *>(malloc(sizeof (oslSecurityImpl)));
if (pSecImpl)
{
pSecImpl->m_pNetResource = static_cast <NETRESOURCEW *>(malloc(sizeof (NETRESOURCE)));
if (pSecImpl->m_pNetResource)
{
*pSecImpl->m_pNetResource = netResource;
pSecImpl->m_hToken = nullptr;
pSecImpl->m_hProfile = nullptr;
wcscpy(o3tl::toW(pSecImpl->m_User), o3tl::toW(rtl_uString_getStr(strUserName)));
}
else
{
free(pSecImpl);
pSecImpl = nullptr;
}
}
*pSecurity = pSecImpl;
ret = pSecImpl ? osl_Security_E_None : osl_Security_E_Unknown;
}
else
{
ret = osl_Security_E_UserUnknown;
}
free(remoteName);
free(userName);
return ret;
}
sal_Bool SAL_CALL osl_isAdministrator(oslSecurity Security)
{
if (!Security)
return false ;
HANDLE hImpersonationToken = nullptr;
PSID psidAdministrators;
SID_IDENTIFIER_AUTHORITY siaNtAuthority = { SECURITY_NT_AUTHORITY };
bool bSuccess = false ;
/* If Security contains an access token we need to duplicate it to an impersonation
access token . NULL works with CheckTokenMembership ( ) as the current effective
impersonation token
*/
if ( static_cast <oslSecurityImpl*>(Security)->m_hToken )
{
if ( !DuplicateToken (static_cast <oslSecurityImpl*>(Security)->m_hToken, SecurityImpersonation, &hImpersonationToken) )
return false ;
}
/* CheckTokenMembership() can be used on W2K and higher (NT4 no longer supported by OOo)
and also works on Vista to retrieve the effective user rights . Just checking for
membership of Administrators group is not enough on Vista this would require additional
complicated checks as described in KB article Q118626 : http : //support.microsoft.com/kb/118626/en-us
*/
if (AllocateAndInitializeSid(&siaNtAuthority,
2 ,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0 , 0 , 0 , 0 , 0 , 0 ,
&psidAdministrators))
{
BOOL fSuccess = FALSE ;
if (CheckTokenMembership(hImpersonationToken, psidAdministrators, &fSuccess) && fSuccess)
bSuccess = true ;
FreeSid(psidAdministrators);
}
if (hImpersonationToken)
CloseHandle(hImpersonationToken);
return bSuccess;
}
void SAL_CALL osl_freeSecurityHandle(oslSecurity Security)
{
if (!Security)
return ;
oslSecurityImpl *pSecImpl = static_cast <oslSecurityImpl*>(Security);
if (pSecImpl->m_pNetResource != nullptr)
{
WNetCancelConnection2W(pSecImpl->m_pNetResource->lpRemoteName, 0 , true );
free(pSecImpl->m_pNetResource->lpRemoteName);
free(pSecImpl->m_pNetResource);
}
if (pSecImpl->m_hToken)
CloseHandle(pSecImpl->m_hToken);
if ( pSecImpl->m_hProfile )
CloseHandle(pSecImpl->m_hProfile);
free (pSecImpl);
}
sal_Bool SAL_CALL osl_getUserIdent(oslSecurity Security, rtl_uString **strIdent)
{
if (!Security)
return false ;
oslSecurityImpl *pSecImpl = static_cast <oslSecurityImpl*>(Security);
HANDLE hAccessToken = pSecImpl->m_hToken;
if (hAccessToken == nullptr)
OpenProcessToken(GetCurrentProcess(), TOKEN_DUP_QUERY, &hAccessToken);
if (hAccessToken)
{
DWORD nInfoBuffer = 512 ;
UCHAR* pInfoBuffer = static_cast <UCHAR *>(malloc(nInfoBuffer));
while (!GetTokenInformation(hAccessToken, TokenUser,
pInfoBuffer, nInfoBuffer, &nInfoBuffer))
{
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
if (auto p = static_cast <UCHAR *>(realloc(pInfoBuffer, nInfoBuffer)))
pInfoBuffer = p;
else
{
free(pInfoBuffer);
pInfoBuffer = nullptr;
break ;
}
}
else
{
free(pInfoBuffer);
pInfoBuffer = nullptr;
break ;
}
}
if (pSecImpl->m_hToken == nullptr)
CloseHandle(hAccessToken);
if (pInfoBuffer)
{
PSID pSid = reinterpret_cast <PTOKEN_USER>(pInfoBuffer)->User.Sid;
LPWSTR pSidStr = nullptr;
bool bResult = ConvertSidToStringSidW(pSid, &pSidStr);
if (bResult)
{
rtl_uString_newFromStr(strIdent, o3tl::toU(pSidStr));
LocalFree(pSidStr);
}
else
{
const DWORD dwError = GetLastError();
SAL_WARN(
"sal.osl" ,
"ConvertSidToStringSidW failed. GetLastError returned: " << dwError);
}
free(pInfoBuffer);
return bResult;
}
}
else
{
DWORD needed = 0 ;
WNetGetUserW(nullptr, nullptr, &needed);
if (needed < 16 )
needed = 16 ;
if (auto Ident = static_cast <sal_Unicode *>(malloc(needed*sizeof (sal_Unicode))))
{
if (WNetGetUserW(nullptr, o3tl::toW(Ident), &needed) != NO_ERROR)
{
wcscpy(o3tl::toW(Ident), L"unknown" );
Ident[7 ] = L'\0' ;
}
rtl_uString_newFromStr( strIdent, Ident);
free(Ident);
return true ;
}
}
return false ;
}
sal_Bool SAL_CALL osl_getUserName(oslSecurity Security, rtl_uString **strName)
{
return getUserNameImpl(Security, strName, true );
}
sal_Bool SAL_CALL osl_getShortUserName(oslSecurity Security, rtl_uString **strName)
{
return getUserNameImpl(Security, strName, false );
}
sal_Bool SAL_CALL osl_getHomeDir(oslSecurity Security, rtl_uString **pustrDirectory)
{
if (!Security)
return false ;
rtl_uString *ustrSysDir = nullptr;
bool bSuccess = false ;
oslSecurityImpl *pSecImpl = static_cast <oslSecurityImpl*>(Security);
if (pSecImpl->m_pNetResource != nullptr)
{
rtl_uString_newFromStr( &ustrSysDir, o3tl::toU(pSecImpl->m_pNetResource->lpRemoteName));
bSuccess = osl_File_E_None == osl_getFileURLFromSystemPath( ustrSysDir, pustrDirectory );
}
else
{
bSuccess = GetSpecialFolder(&ustrSysDir, FOLDERID_Documents) &&
(osl_File_E_None == osl_getFileURLFromSystemPath(ustrSysDir, pustrDirectory));
}
if ( ustrSysDir )
rtl_uString_release( ustrSysDir );
return bSuccess;
}
sal_Bool SAL_CALL osl_getConfigDir(oslSecurity Security, rtl_uString **pustrDirectory)
{
if (!Security)
return false ;
bool bSuccess = false ;
oslSecurityImpl *pSecImpl = static_cast <oslSecurityImpl*>(Security);
if (pSecImpl->m_pNetResource != nullptr)
{
rtl_uString *ustrSysDir = nullptr;
rtl_uString_newFromStr( &ustrSysDir, o3tl::toU(pSecImpl->m_pNetResource->lpRemoteName));
bSuccess = osl_File_E_None == osl_getFileURLFromSystemPath( ustrSysDir, pustrDirectory);
if ( ustrSysDir )
rtl_uString_release( ustrSysDir );
}
else
{
if (pSecImpl->m_hToken)
{
/* not implemented */
OSL_ASSERT(false );
}
else
{
rtl_uString *ustrFile = nullptr;
sal_Unicode sFile[_MAX_PATH];
if ( !GetSpecialFolder( &ustrFile, FOLDERID_RoamingAppData) )
{
OSL_VERIFY(GetWindowsDirectoryW(o3tl::toW(sFile), _MAX_DIR) > 0 );
rtl_uString_newFromStr( &ustrFile, sFile);
}
bSuccess = osl_File_E_None == osl_getFileURLFromSystemPath(ustrFile, pustrDirectory);
if ( ustrFile )
rtl_uString_release( ustrFile );
}
}
return bSuccess;
}
sal_Bool SAL_CALL osl_loadUserProfile(oslSecurity Security)
{
/* CreateProcessAsUser does not load the specified user's profile
into the HKEY_USERS registry key . This means that access to information
in the HKEY_CURRENT_USER registry key may not produce results consistent
with a normal interactive logon .
It is your responsibility to load the user ' s registry hive into HKEY_USERS
with the LoadUserProfile function before calling CreateProcessAsUser .
*/
RegCloseKey(HKEY_CURRENT_USER);
if (!Privilege(SE_RESTORE_NAME, true ))
return false ;
bool bOk = false ;
HANDLE hAccessToken = static_cast <oslSecurityImpl*>(Security)->m_hToken;
/* try to create user profile */
if ( !hAccessToken )
{
/* retrieve security handle if not done before e.g. osl_getCurrentSecurity()
*/
HANDLE hProcess = GetCurrentProcess();
if (hProcess != nullptr)
{
OpenProcessToken(hProcess, TOKEN_IMPERSONATE, &hAccessToken);
CloseHandle(hProcess);
}
}
rtl_uString *buffer = nullptr;
PROFILEINFOW pi;
getUserNameImpl(Security, &buffer, false );
ZeroMemory(&pi, sizeof (pi));
pi.dwSize = sizeof (pi);
pi.lpUserName = o3tl::toW(rtl_uString_getStr(buffer));
pi.dwFlags = PI_NOUI;
if (LoadUserProfileW(hAccessToken, &pi))
{
UnloadUserProfile(hAccessToken, pi.hProfile);
bOk = true ;
}
rtl_uString_release(buffer);
if (hAccessToken && (hAccessToken != static_cast <oslSecurityImpl*>(Security)->m_hToken))
CloseHandle(hAccessToken);
return bOk;
}
void SAL_CALL osl_unloadUserProfile(oslSecurity Security)
{
if ( static_cast <oslSecurityImpl*>(Security)->m_hProfile == nullptr )
return ;
HANDLE hAccessToken = static_cast <oslSecurityImpl*>(Security)->m_hToken;
if ( !hAccessToken )
{
/* retrieve security handle if not done before e.g. osl_getCurrentSecurity()
*/
HANDLE hProcess = GetCurrentProcess();
if (hProcess != nullptr)
{
OpenProcessToken(hProcess, TOKEN_IMPERSONATE, &hAccessToken);
CloseHandle(hProcess);
}
}
/* unloading the user profile */
UnloadUserProfile(hAccessToken, static_cast <oslSecurityImpl*>(Security)->m_hProfile);
static_cast <oslSecurityImpl*>(Security)->m_hProfile = nullptr;
if (hAccessToken && (hAccessToken != static_cast <oslSecurityImpl*>(Security)->m_hToken))
CloseHandle(hAccessToken);
}
static bool GetSpecialFolder(rtl_uString **strPath, REFKNOWNFOLDERID rFolder)
{
sal::systools::CoTaskMemAllocated<wchar_t > PathW;
if (SUCCEEDED(SHGetKnownFolderPath(rFolder, KF_FLAG_CREATE, nullptr, &PathW)))
{
rtl_uString_newFromStr(strPath, o3tl::toU(PathW));
return true ;
}
return false ;
}
// We use LPCTSTR here, because we use it with SE_foo_NAME constants
// which are defined in winnt.h as UNICODE-dependent TEXT("PrivilegeName")
static bool Privilege(LPCTSTR strPrivilege, bool bEnable)
{
HANDLE hToken;
TOKEN_PRIVILEGES tp;
// obtain the processes token
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_DUP_QUERY, &hToken))
return false ;
// get the luid
if (!LookupPrivilegeValue(nullptr, strPrivilege, &tp.Privileges[0 ].Luid))
return false ;
tp.PrivilegeCount = 1 ;
if (bEnable)
tp.Privileges[0 ].Attributes = SE_PRIVILEGE_ENABLED;
else
tp.Privileges[0 ].Attributes = 0 ;
// enable or disable the privilege
if (!AdjustTokenPrivileges(hToken, FALSE , &tp, 0 , nullptr, nullptr))
return false ;
if (!CloseHandle(hToken))
return false ;
return true ;
}
static bool getUserNameImpl(oslSecurity Security, rtl_uString **strName, bool bIncludeDomain)
{
if (!Security)
return false ;
oslSecurityImpl *pSecImpl = static_cast <oslSecurityImpl*>(Security);
HANDLE hAccessToken = pSecImpl->m_hToken;
if (hAccessToken == nullptr)
OpenProcessToken(GetCurrentProcess(), TOKEN_DUP_QUERY, &hAccessToken);
if (hAccessToken)
{
DWORD nInfoBuffer = 512 ;
UCHAR* pInfoBuffer = static_cast <UCHAR *>(malloc(nInfoBuffer));
while (!GetTokenInformation(hAccessToken, TokenUser,
pInfoBuffer, nInfoBuffer, &nInfoBuffer))
{
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
if (auto p = static_cast <UCHAR *>(realloc(pInfoBuffer, nInfoBuffer)))
pInfoBuffer = p;
else
{
free(pInfoBuffer);
pInfoBuffer = nullptr;
break ;
}
}
else
{
free(pInfoBuffer);
pInfoBuffer = nullptr;
break ;
}
}
if (pSecImpl->m_hToken == nullptr)
CloseHandle(hAccessToken);
if (pInfoBuffer)
{
sal_Unicode UserName[128 ];
sal_Unicode DomainName[128 ];
sal_Unicode Name[257 ];
DWORD nUserName = SAL_N_ELEMENTS(UserName);
DWORD nDomainName = SAL_N_ELEMENTS(DomainName);
SID_NAME_USE sUse;
if (LookupAccountSidW(nullptr, reinterpret_cast <PTOKEN_USER>(pInfoBuffer)->User.Sid,
o3tl::toW(UserName), &nUserName,
o3tl::toW(DomainName), &nDomainName, &sUse))
{
if (bIncludeDomain)
{
wcscpy(o3tl::toW(Name), o3tl::toW(DomainName));
wcscat(o3tl::toW(Name), L"/" );
wcscat(o3tl::toW(Name), o3tl::toW(UserName));
}
else
{
wcscpy(o3tl::toW(Name), o3tl::toW(UserName));
}
rtl_uString_newFromStr(strName, Name);
free(pInfoBuffer);
return true ;
}
}
}
else
{
DWORD needed=0 ;
sal_Unicode *pNameW=nullptr;
WNetGetUserW(nullptr, nullptr, &needed);
pNameW = static_cast <sal_Unicode *>(malloc (needed*sizeof (sal_Unicode)));
assert(pNameW); // Don't handle OOM conditions
if (WNetGetUserW(nullptr, o3tl::toW(pNameW), &needed) == NO_ERROR)
{
rtl_uString_newFromStr( strName, pNameW);
if (pNameW)
free(pNameW);
return true ;
}
else if (pSecImpl->m_User[0 ] != '\0' )
{
rtl_uString_newFromStr(strName, o3tl::toU(pSecImpl->m_pNetResource->lpRemoteName));
if (pNameW)
free(pNameW);
return true ;
}
if (pNameW)
free(pNameW);
}
return false ;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Messung V0.5 in Prozent C=97 H=99 G=97
¤ Dauer der Verarbeitung: 0.59 Sekunden
(vorverarbeitet am 2026-09-29)
¤
*© Formatika GbR, Deutschland
2026-10-10
Neuigkeiten
Aktuelles
Motto des Tages
Open Source Software
Jenseits des Üblichen ....
Besucherstatistik
Statistik
#Sources=1126864
#Domains=2039723