tdf#154546 skip dispatch when presenter controller is not set
[LibreOffice.git] / sal / osl / w32 / security.cxx
blob21ed64a7862a69756820dcdc4b5ddfc51fb44c55
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "system.h"
21 #include <userenv.h>
23 #include <cassert>
24 #include <osl/security.h>
25 #include <osl/diagnose.h>
26 #include <osl/thread.h>
27 #include <osl/file.h>
28 #include <systools/win32/uwinapi.h>
29 #include <sddl.h>
30 #include <sal/macros.h>
31 #include <sal/log.hxx>
32 #include <o3tl/char16_t2wchar_t.hxx>
33 #include "secimpl.hxx"
35 /* To get an impersonation token we need to create an impersonation
36 duplicate so every access token has to be created with duplicate
37 access rights */
39 #define TOKEN_DUP_QUERY (TOKEN_QUERY|TOKEN_DUPLICATE)
41 static bool GetSpecialFolder(rtl_uString **strPath, REFKNOWNFOLDERID rFolder);
42 // We use LPCTSTR here, because we use it with SE_foo_NAME constants
43 // which are defined in winnt.h as UNICODE-dependent TEXT("PrivilegeName")
44 static bool Privilege(LPCTSTR pszPrivilege, bool bEnable);
45 static bool getUserNameImpl(oslSecurity Security, rtl_uString **strName, bool bIncludeDomain);
47 oslSecurity SAL_CALL osl_getCurrentSecurity(void)
49 oslSecurityImpl* pSecImpl = static_cast<oslSecurityImpl *>(malloc(sizeof(oslSecurityImpl)));
50 if (pSecImpl)
52 pSecImpl->m_pNetResource = nullptr;
53 pSecImpl->m_User[0] = '\0';
54 pSecImpl->m_hToken = nullptr;
55 pSecImpl->m_hProfile = nullptr;
57 return pSecImpl;
60 oslSecurityError SAL_CALL osl_loginUser( rtl_uString *strUserName, rtl_uString *strPasswd, oslSecurity *pSecurity )
62 oslSecurityError ret;
64 sal_Unicode* strUser;
65 sal_Unicode* strDomain = o3tl::toU(_wcsdup(o3tl::toW(rtl_uString_getStr(strUserName))));
66 HANDLE hUserToken;
67 LUID luid;
69 if (nullptr != (strUser = o3tl::toU(wcschr(o3tl::toW(strDomain), L'/'))))
70 *strUser++ = L'\0';
71 else
73 strUser = strDomain;
74 strDomain = nullptr;
77 // this process must have the right: 'act as a part of operatingsystem'
78 OSL_ASSERT(LookupPrivilegeValue(nullptr, SE_TCB_NAME, &luid));
79 (void) luid;
81 if (LogonUserW(o3tl::toW(strUser), strDomain ? o3tl::toW(strDomain) : L"", o3tl::toW(rtl_uString_getStr(strPasswd)),
82 LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
83 &hUserToken))
85 oslSecurityImpl* pSecImpl = static_cast<oslSecurityImpl *>(malloc(sizeof(oslSecurityImpl)));
86 if (pSecImpl)
88 pSecImpl->m_pNetResource = nullptr;
89 pSecImpl->m_hToken = hUserToken;
90 pSecImpl->m_hProfile = nullptr;
91 wcscpy(o3tl::toW(pSecImpl->m_User), o3tl::toW(strUser));
93 *pSecurity = pSecImpl;
94 ret = pSecImpl ? osl_Security_E_None : osl_Security_E_Unknown;
96 else
98 ret = osl_Security_E_UserUnknown;
101 if (strDomain)
102 free(strDomain);
103 else
104 free(strUser);
106 return ret;
109 oslSecurityError SAL_CALL osl_loginUserOnFileServer(rtl_uString *strUserName,
110 rtl_uString *strPasswd,
111 rtl_uString *strFileServer,
112 oslSecurity *pSecurity)
114 oslSecurityError ret;
115 DWORD err;
116 NETRESOURCEW netResource;
117 sal_Unicode* remoteName;
118 sal_Unicode* userName;
120 remoteName = static_cast<sal_Unicode *>(malloc((rtl_uString_getLength(strFileServer) + rtl_uString_getLength(strUserName) + 4) * sizeof(sal_Unicode)));
121 userName = static_cast<sal_Unicode *>(malloc((rtl_uString_getLength(strFileServer) + rtl_uString_getLength(strUserName) + 2) * sizeof(sal_Unicode)));
123 wcscpy(o3tl::toW(remoteName), L"\\\\");
124 wcscat(o3tl::toW(remoteName), o3tl::toW(rtl_uString_getStr(strFileServer)));
125 wcscat(o3tl::toW(remoteName), L"\\");
126 wcscat(o3tl::toW(remoteName), o3tl::toW(rtl_uString_getStr(strUserName)));
128 wcscpy(o3tl::toW(userName), o3tl::toW(rtl_uString_getStr(strFileServer)));
129 wcscat(o3tl::toW(userName), L"\\");
130 wcscat(o3tl::toW(userName), o3tl::toW(rtl_uString_getStr(strUserName)));
132 netResource.dwScope = RESOURCE_GLOBALNET;
133 netResource.dwType = RESOURCETYPE_DISK;
134 netResource.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
135 netResource.dwUsage = RESOURCEUSAGE_CONNECTABLE;
136 netResource.lpLocalName = nullptr;
137 netResource.lpRemoteName = o3tl::toW(remoteName);
138 netResource.lpComment = nullptr;
139 netResource.lpProvider = nullptr;
141 err = WNetAddConnection2W(&netResource, o3tl::toW(rtl_uString_getStr(strPasswd)), o3tl::toW(userName), 0);
143 if ((err == NO_ERROR) || (err == ERROR_ALREADY_ASSIGNED))
145 oslSecurityImpl* pSecImpl = static_cast<oslSecurityImpl *>(malloc(sizeof(oslSecurityImpl)));
146 if (pSecImpl)
148 pSecImpl->m_pNetResource = static_cast<NETRESOURCEW *>(malloc(sizeof(NETRESOURCE)));
149 if (pSecImpl->m_pNetResource)
151 *pSecImpl->m_pNetResource = netResource;
152 pSecImpl->m_hToken = nullptr;
153 pSecImpl->m_hProfile = nullptr;
154 wcscpy(o3tl::toW(pSecImpl->m_User), o3tl::toW(rtl_uString_getStr(strUserName)));
156 else
158 free(pSecImpl);
159 pSecImpl = nullptr;
162 *pSecurity = pSecImpl;
164 ret = pSecImpl ? osl_Security_E_None : osl_Security_E_Unknown;
166 else
168 ret = osl_Security_E_UserUnknown;
171 free(remoteName);
172 free(userName);
174 return ret;
177 sal_Bool SAL_CALL osl_isAdministrator(oslSecurity Security)
179 if (!Security)
180 return false;
182 HANDLE hImpersonationToken = nullptr;
183 PSID psidAdministrators;
184 SID_IDENTIFIER_AUTHORITY siaNtAuthority = { SECURITY_NT_AUTHORITY };
185 bool bSuccess = false;
187 /* If Security contains an access token we need to duplicate it to an impersonation
188 access token. NULL works with CheckTokenMembership() as the current effective
189 impersonation token
192 if ( static_cast<oslSecurityImpl*>(Security)->m_hToken )
194 if ( !DuplicateToken (static_cast<oslSecurityImpl*>(Security)->m_hToken, SecurityImpersonation, &hImpersonationToken) )
195 return false;
198 /* CheckTokenMembership() can be used on W2K and higher (NT4 no longer supported by OOo)
199 and also works on Vista to retrieve the effective user rights. Just checking for
200 membership of Administrators group is not enough on Vista this would require additional
201 complicated checks as described in KB article Q118626: http://support.microsoft.com/kb/118626/en-us
204 if (AllocateAndInitializeSid(&siaNtAuthority,
206 SECURITY_BUILTIN_DOMAIN_RID,
207 DOMAIN_ALIAS_RID_ADMINS,
208 0, 0, 0, 0, 0, 0,
209 &psidAdministrators))
211 BOOL fSuccess = FALSE;
213 if (CheckTokenMembership(hImpersonationToken, psidAdministrators, &fSuccess) && fSuccess)
214 bSuccess = true;
216 FreeSid(psidAdministrators);
219 if (hImpersonationToken)
220 CloseHandle(hImpersonationToken);
222 return bSuccess;
225 void SAL_CALL osl_freeSecurityHandle(oslSecurity Security)
227 if (!Security)
228 return;
230 oslSecurityImpl *pSecImpl = static_cast<oslSecurityImpl*>(Security);
232 if (pSecImpl->m_pNetResource != nullptr)
234 WNetCancelConnection2W(pSecImpl->m_pNetResource->lpRemoteName, 0, true);
236 free(pSecImpl->m_pNetResource->lpRemoteName);
237 free(pSecImpl->m_pNetResource);
240 if (pSecImpl->m_hToken)
241 CloseHandle(pSecImpl->m_hToken);
243 if ( pSecImpl->m_hProfile )
244 CloseHandle(pSecImpl->m_hProfile);
246 free (pSecImpl);
249 sal_Bool SAL_CALL osl_getUserIdent(oslSecurity Security, rtl_uString **strIdent)
251 if (!Security)
252 return false;
254 oslSecurityImpl *pSecImpl = static_cast<oslSecurityImpl*>(Security);
256 HANDLE hAccessToken = pSecImpl->m_hToken;
258 if (hAccessToken == nullptr)
259 OpenProcessToken(GetCurrentProcess(), TOKEN_DUP_QUERY, &hAccessToken);
261 if (hAccessToken)
263 DWORD nInfoBuffer = 512;
264 UCHAR* pInfoBuffer = static_cast<UCHAR *>(malloc(nInfoBuffer));
266 while (!GetTokenInformation(hAccessToken, TokenUser,
267 pInfoBuffer, nInfoBuffer, &nInfoBuffer))
269 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
271 if (auto p = static_cast<UCHAR *>(realloc(pInfoBuffer, nInfoBuffer)))
272 pInfoBuffer = p;
273 else
275 free(pInfoBuffer);
276 pInfoBuffer = nullptr;
277 break;
280 else
282 free(pInfoBuffer);
283 pInfoBuffer = nullptr;
284 break;
288 if (pSecImpl->m_hToken == nullptr)
289 CloseHandle(hAccessToken);
291 if (pInfoBuffer)
293 PSID pSid = reinterpret_cast<PTOKEN_USER>(pInfoBuffer)->User.Sid;
295 LPWSTR pSidStr = nullptr;
296 bool bResult = ConvertSidToStringSidW(pSid, &pSidStr);
297 if (bResult)
299 rtl_uString_newFromStr(strIdent, o3tl::toU(pSidStr));
300 LocalFree(pSidStr);
302 else
304 const DWORD dwError = GetLastError();
305 SAL_WARN(
306 "sal.osl",
307 "ConvertSidToStringSidW failed. GetLastError returned: " << dwError);
310 free(pInfoBuffer);
312 return bResult;
315 else
317 DWORD needed = 0;
319 WNetGetUserW(nullptr, nullptr, &needed);
320 if (needed < 16)
321 needed = 16;
323 if (auto Ident = static_cast<sal_Unicode *>(malloc(needed*sizeof(sal_Unicode))))
325 if (WNetGetUserW(nullptr, o3tl::toW(Ident), &needed) != NO_ERROR)
327 wcscpy(o3tl::toW(Ident), L"unknown");
328 Ident[7] = L'\0';
331 rtl_uString_newFromStr( strIdent, Ident);
332 free(Ident);
333 return true;
336 return false;
339 sal_Bool SAL_CALL osl_getUserName(oslSecurity Security, rtl_uString **strName)
341 return getUserNameImpl(Security, strName, true);
344 sal_Bool SAL_CALL osl_getShortUserName(oslSecurity Security, rtl_uString **strName)
346 return getUserNameImpl(Security, strName, false);
349 sal_Bool SAL_CALL osl_getHomeDir(oslSecurity Security, rtl_uString **pustrDirectory)
351 if (!Security)
352 return false;
354 rtl_uString *ustrSysDir = nullptr;
355 bool bSuccess = false;
357 oslSecurityImpl *pSecImpl = static_cast<oslSecurityImpl*>(Security);
359 if (pSecImpl->m_pNetResource != nullptr)
361 rtl_uString_newFromStr( &ustrSysDir, o3tl::toU(pSecImpl->m_pNetResource->lpRemoteName));
363 bSuccess = osl_File_E_None == osl_getFileURLFromSystemPath( ustrSysDir, pustrDirectory );
365 else
367 bSuccess = GetSpecialFolder(&ustrSysDir, FOLDERID_Documents) &&
368 (osl_File_E_None == osl_getFileURLFromSystemPath(ustrSysDir, pustrDirectory));
371 if ( ustrSysDir )
372 rtl_uString_release( ustrSysDir );
374 return bSuccess;
377 sal_Bool SAL_CALL osl_getConfigDir(oslSecurity Security, rtl_uString **pustrDirectory)
379 if (!Security)
380 return false;
382 bool bSuccess = false;
383 oslSecurityImpl *pSecImpl = static_cast<oslSecurityImpl*>(Security);
385 if (pSecImpl->m_pNetResource != nullptr)
387 rtl_uString *ustrSysDir = nullptr;
389 rtl_uString_newFromStr( &ustrSysDir, o3tl::toU(pSecImpl->m_pNetResource->lpRemoteName));
390 bSuccess = osl_File_E_None == osl_getFileURLFromSystemPath( ustrSysDir, pustrDirectory);
392 if ( ustrSysDir )
393 rtl_uString_release( ustrSysDir );
395 else
397 if (pSecImpl->m_hToken)
399 /* not implemented */
400 OSL_ASSERT(false);
402 else
404 rtl_uString *ustrFile = nullptr;
405 sal_Unicode sFile[_MAX_PATH];
407 if ( !GetSpecialFolder( &ustrFile, FOLDERID_RoamingAppData) )
409 OSL_VERIFY(GetWindowsDirectoryW(o3tl::toW(sFile), _MAX_DIR) > 0);
411 rtl_uString_newFromStr( &ustrFile, sFile);
414 bSuccess = osl_File_E_None == osl_getFileURLFromSystemPath(ustrFile, pustrDirectory);
416 if ( ustrFile )
417 rtl_uString_release( ustrFile );
421 return bSuccess;
424 sal_Bool SAL_CALL osl_loadUserProfile(oslSecurity Security)
426 /* CreateProcessAsUser does not load the specified user's profile
427 into the HKEY_USERS registry key. This means that access to information
428 in the HKEY_CURRENT_USER registry key may not produce results consistent
429 with a normal interactive logon.
430 It is your responsibility to load the user's registry hive into HKEY_USERS
431 with the LoadUserProfile function before calling CreateProcessAsUser.
434 RegCloseKey(HKEY_CURRENT_USER);
436 if (!Privilege(SE_RESTORE_NAME, true))
437 return false;
439 bool bOk = false;
440 HANDLE hAccessToken = static_cast<oslSecurityImpl*>(Security)->m_hToken;
442 /* try to create user profile */
443 if ( !hAccessToken )
445 /* retrieve security handle if not done before e.g. osl_getCurrentSecurity()
447 HANDLE hProcess = GetCurrentProcess();
449 if (hProcess != nullptr)
451 OpenProcessToken(hProcess, TOKEN_IMPERSONATE, &hAccessToken);
452 CloseHandle(hProcess);
456 rtl_uString *buffer = nullptr;
457 PROFILEINFOW pi;
459 getUserNameImpl(Security, &buffer, false);
461 ZeroMemory(&pi, sizeof(pi));
462 pi.dwSize = sizeof(pi);
463 pi.lpUserName = o3tl::toW(rtl_uString_getStr(buffer));
464 pi.dwFlags = PI_NOUI;
466 if (LoadUserProfileW(hAccessToken, &pi))
468 UnloadUserProfile(hAccessToken, pi.hProfile);
470 bOk = true;
473 rtl_uString_release(buffer);
475 if (hAccessToken && (hAccessToken != static_cast<oslSecurityImpl*>(Security)->m_hToken))
476 CloseHandle(hAccessToken);
478 return bOk;
481 void SAL_CALL osl_unloadUserProfile(oslSecurity Security)
483 if ( static_cast<oslSecurityImpl*>(Security)->m_hProfile == nullptr )
484 return;
486 HANDLE hAccessToken = static_cast<oslSecurityImpl*>(Security)->m_hToken;
488 if ( !hAccessToken )
490 /* retrieve security handle if not done before e.g. osl_getCurrentSecurity()
492 HANDLE hProcess = GetCurrentProcess();
494 if (hProcess != nullptr)
496 OpenProcessToken(hProcess, TOKEN_IMPERSONATE, &hAccessToken);
497 CloseHandle(hProcess);
501 /* unloading the user profile */
502 UnloadUserProfile(hAccessToken, static_cast<oslSecurityImpl*>(Security)->m_hProfile);
504 static_cast<oslSecurityImpl*>(Security)->m_hProfile = nullptr;
506 if (hAccessToken && (hAccessToken != static_cast<oslSecurityImpl*>(Security)->m_hToken))
507 CloseHandle(hAccessToken);
510 static bool GetSpecialFolder(rtl_uString **strPath, REFKNOWNFOLDERID rFolder)
512 bool bRet = false;
513 PWSTR PathW;
514 if (SUCCEEDED(SHGetKnownFolderPath(rFolder, KF_FLAG_CREATE, nullptr, &PathW)))
516 rtl_uString_newFromStr(strPath, o3tl::toU(PathW));
517 CoTaskMemFree(PathW);
518 bRet = true;
521 return bRet;
524 // We use LPCTSTR here, because we use it with SE_foo_NAME constants
525 // which are defined in winnt.h as UNICODE-dependent TEXT("PrivilegeName")
526 static bool Privilege(LPCTSTR strPrivilege, bool bEnable)
528 HANDLE hToken;
529 TOKEN_PRIVILEGES tp;
531 // obtain the processes token
532 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_DUP_QUERY, &hToken))
533 return false;
535 // get the luid
536 if (!LookupPrivilegeValue(nullptr, strPrivilege, &tp.Privileges[0].Luid))
537 return false;
539 tp.PrivilegeCount = 1;
541 if (bEnable)
542 tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
543 else
544 tp.Privileges[0].Attributes = 0;
546 // enable or disable the privilege
547 if (!AdjustTokenPrivileges(hToken, FALSE, &tp, 0, nullptr, nullptr))
548 return false;
550 if (!CloseHandle(hToken))
551 return false;
553 return true;
556 static bool getUserNameImpl(oslSecurity Security, rtl_uString **strName, bool bIncludeDomain)
558 if (!Security)
559 return false;
561 oslSecurityImpl *pSecImpl = static_cast<oslSecurityImpl*>(Security);
563 HANDLE hAccessToken = pSecImpl->m_hToken;
565 if (hAccessToken == nullptr)
566 OpenProcessToken(GetCurrentProcess(), TOKEN_DUP_QUERY, &hAccessToken);
568 if (hAccessToken)
570 DWORD nInfoBuffer = 512;
571 UCHAR* pInfoBuffer = static_cast<UCHAR *>(malloc(nInfoBuffer));
573 while (!GetTokenInformation(hAccessToken, TokenUser,
574 pInfoBuffer, nInfoBuffer, &nInfoBuffer))
576 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
578 if (auto p = static_cast<UCHAR *>(realloc(pInfoBuffer, nInfoBuffer)))
579 pInfoBuffer = p;
580 else
582 free(pInfoBuffer);
583 pInfoBuffer = nullptr;
584 break;
587 else
589 free(pInfoBuffer);
590 pInfoBuffer = nullptr;
591 break;
595 if (pSecImpl->m_hToken == nullptr)
596 CloseHandle(hAccessToken);
598 if (pInfoBuffer)
600 sal_Unicode UserName[128];
601 sal_Unicode DomainName[128];
602 sal_Unicode Name[257];
603 DWORD nUserName = SAL_N_ELEMENTS(UserName);
604 DWORD nDomainName = SAL_N_ELEMENTS(DomainName);
605 SID_NAME_USE sUse;
607 if (LookupAccountSidW(nullptr, reinterpret_cast<PTOKEN_USER>(pInfoBuffer)->User.Sid,
608 o3tl::toW(UserName), &nUserName,
609 o3tl::toW(DomainName), &nDomainName, &sUse))
611 if (bIncludeDomain)
613 wcscpy(o3tl::toW(Name), o3tl::toW(DomainName));
614 wcscat(o3tl::toW(Name), L"/");
615 wcscat(o3tl::toW(Name), o3tl::toW(UserName));
617 else
619 wcscpy(o3tl::toW(Name), o3tl::toW(UserName));
622 rtl_uString_newFromStr(strName, Name);
623 free(pInfoBuffer);
624 return true;
628 else
630 DWORD needed=0;
631 sal_Unicode *pNameW=nullptr;
633 WNetGetUserW(nullptr, nullptr, &needed);
634 pNameW = static_cast<sal_Unicode *>(malloc (needed*sizeof(sal_Unicode)));
635 assert(pNameW); // Don't handle OOM conditions
637 if (WNetGetUserW(nullptr, o3tl::toW(pNameW), &needed) == NO_ERROR)
639 rtl_uString_newFromStr( strName, pNameW);
641 if (pNameW)
642 free(pNameW);
643 return true;
645 else if (pSecImpl->m_User[0] != '\0')
647 rtl_uString_newFromStr(strName, o3tl::toU(pSecImpl->m_pNetResource->lpRemoteName));
649 if (pNameW)
650 free(pNameW);
652 return true;
655 if (pNameW)
656 free(pNameW);
659 return false;
662 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */