1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
24 #include <osl/security.h>
25 #include <osl/diagnose.h>
26 #include <osl/thread.h>
28 #include <systools/win32/uwinapi.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
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
)));
52 pSecImpl
->m_pNetResource
= nullptr;
53 pSecImpl
->m_User
[0] = '\0';
54 pSecImpl
->m_hToken
= nullptr;
55 pSecImpl
->m_hProfile
= nullptr;
60 oslSecurityError SAL_CALL
osl_loginUser( rtl_uString
*strUserName
, rtl_uString
*strPasswd
, oslSecurity
*pSecurity
)
65 sal_Unicode
* strDomain
= o3tl::toU(_wcsdup(o3tl::toW(rtl_uString_getStr(strUserName
))));
69 if (nullptr != (strUser
= o3tl::toU(wcschr(o3tl::toW(strDomain
), L
'/'))))
77 // this process must have the right: 'act as a part of operatingsystem'
78 OSL_ASSERT(LookupPrivilegeValue(nullptr, SE_TCB_NAME
, &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
,
85 oslSecurityImpl
* pSecImpl
= static_cast<oslSecurityImpl
*>(malloc(sizeof(oslSecurityImpl
)));
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
;
98 ret
= osl_Security_E_UserUnknown
;
109 oslSecurityError SAL_CALL
osl_loginUserOnFileServer(rtl_uString
*strUserName
,
110 rtl_uString
*strPasswd
,
111 rtl_uString
*strFileServer
,
112 oslSecurity
*pSecurity
)
114 oslSecurityError ret
;
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
)));
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
)));
162 *pSecurity
= pSecImpl
;
164 ret
= pSecImpl
? osl_Security_E_None
: osl_Security_E_Unknown
;
168 ret
= osl_Security_E_UserUnknown
;
177 sal_Bool SAL_CALL
osl_isAdministrator(oslSecurity Security
)
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
192 if ( static_cast<oslSecurityImpl
*>(Security
)->m_hToken
)
194 if ( !DuplicateToken (static_cast<oslSecurityImpl
*>(Security
)->m_hToken
, SecurityImpersonation
, &hImpersonationToken
) )
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
,
209 &psidAdministrators
))
211 BOOL fSuccess
= FALSE
;
213 if (CheckTokenMembership(hImpersonationToken
, psidAdministrators
, &fSuccess
) && fSuccess
)
216 FreeSid(psidAdministrators
);
219 if (hImpersonationToken
)
220 CloseHandle(hImpersonationToken
);
225 void SAL_CALL
osl_freeSecurityHandle(oslSecurity Security
)
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
);
249 sal_Bool SAL_CALL
osl_getUserIdent(oslSecurity Security
, rtl_uString
**strIdent
)
254 oslSecurityImpl
*pSecImpl
= static_cast<oslSecurityImpl
*>(Security
);
256 HANDLE hAccessToken
= pSecImpl
->m_hToken
;
258 if (hAccessToken
== nullptr)
259 OpenProcessToken(GetCurrentProcess(), TOKEN_DUP_QUERY
, &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
)))
276 pInfoBuffer
= nullptr;
283 pInfoBuffer
= nullptr;
288 if (pSecImpl
->m_hToken
== nullptr)
289 CloseHandle(hAccessToken
);
293 PSID pSid
= reinterpret_cast<PTOKEN_USER
>(pInfoBuffer
)->User
.Sid
;
295 LPWSTR pSidStr
= nullptr;
296 bool bResult
= ConvertSidToStringSidW(pSid
, &pSidStr
);
299 rtl_uString_newFromStr(strIdent
, o3tl::toU(pSidStr
));
304 const DWORD dwError
= GetLastError();
307 "ConvertSidToStringSidW failed. GetLastError returned: " << dwError
);
319 WNetGetUserW(nullptr, nullptr, &needed
);
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");
331 rtl_uString_newFromStr( strIdent
, Ident
);
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
)
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
);
367 bSuccess
= GetSpecialFolder(&ustrSysDir
, FOLDERID_Documents
) &&
368 (osl_File_E_None
== osl_getFileURLFromSystemPath(ustrSysDir
, pustrDirectory
));
372 rtl_uString_release( ustrSysDir
);
377 sal_Bool SAL_CALL
osl_getConfigDir(oslSecurity Security
, rtl_uString
**pustrDirectory
)
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
);
393 rtl_uString_release( ustrSysDir
);
397 if (pSecImpl
->m_hToken
)
399 /* not implemented */
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
);
417 rtl_uString_release( ustrFile
);
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))
440 HANDLE hAccessToken
= static_cast<oslSecurityImpl
*>(Security
)->m_hToken
;
442 /* try to create user profile */
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;
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
);
473 rtl_uString_release(buffer
);
475 if (hAccessToken
&& (hAccessToken
!= static_cast<oslSecurityImpl
*>(Security
)->m_hToken
))
476 CloseHandle(hAccessToken
);
481 void SAL_CALL
osl_unloadUserProfile(oslSecurity Security
)
483 if ( static_cast<oslSecurityImpl
*>(Security
)->m_hProfile
== nullptr )
486 HANDLE hAccessToken
= static_cast<oslSecurityImpl
*>(Security
)->m_hToken
;
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
)
514 if (SUCCEEDED(SHGetKnownFolderPath(rFolder
, KF_FLAG_CREATE
, nullptr, &PathW
)))
516 rtl_uString_newFromStr(strPath
, o3tl::toU(PathW
));
517 CoTaskMemFree(PathW
);
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
)
531 // obtain the processes token
532 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES
| TOKEN_DUP_QUERY
, &hToken
))
536 if (!LookupPrivilegeValue(nullptr, strPrivilege
, &tp
.Privileges
[0].Luid
))
539 tp
.PrivilegeCount
= 1;
542 tp
.Privileges
[0].Attributes
= SE_PRIVILEGE_ENABLED
;
544 tp
.Privileges
[0].Attributes
= 0;
546 // enable or disable the privilege
547 if (!AdjustTokenPrivileges(hToken
, FALSE
, &tp
, 0, nullptr, nullptr))
550 if (!CloseHandle(hToken
))
556 static bool getUserNameImpl(oslSecurity Security
, rtl_uString
**strName
, bool bIncludeDomain
)
561 oslSecurityImpl
*pSecImpl
= static_cast<oslSecurityImpl
*>(Security
);
563 HANDLE hAccessToken
= pSecImpl
->m_hToken
;
565 if (hAccessToken
== nullptr)
566 OpenProcessToken(GetCurrentProcess(), TOKEN_DUP_QUERY
, &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
)))
583 pInfoBuffer
= nullptr;
590 pInfoBuffer
= nullptr;
595 if (pSecImpl
->m_hToken
== nullptr)
596 CloseHandle(hAccessToken
);
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
);
607 if (LookupAccountSidW(nullptr, reinterpret_cast<PTOKEN_USER
>(pInfoBuffer
)->User
.Sid
,
608 o3tl::toW(UserName
), &nUserName
,
609 o3tl::toW(DomainName
), &nDomainName
, &sUse
))
613 wcscpy(o3tl::toW(Name
), o3tl::toW(DomainName
));
614 wcscat(o3tl::toW(Name
), L
"/");
615 wcscat(o3tl::toW(Name
), o3tl::toW(UserName
));
619 wcscpy(o3tl::toW(Name
), o3tl::toW(UserName
));
622 rtl_uString_newFromStr(strName
, Name
);
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
);
645 else if (pSecImpl
->m_User
[0] != '\0')
647 rtl_uString_newFromStr(strName
, o3tl::toU(pSecImpl
->m_pNetResource
->lpRemoteName
));
662 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */