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
)
179 if (Security
!= nullptr)
181 HANDLE hImpersonationToken
= nullptr;
182 PSID psidAdministrators
;
183 SID_IDENTIFIER_AUTHORITY siaNtAuthority
= { SECURITY_NT_AUTHORITY
};
184 bool bSuccess
= false;
186 /* If Security contains an access token we need to duplicate it to an impersonation
187 access token. NULL works with CheckTokenMembership() as the current effective
191 if ( static_cast<oslSecurityImpl
*>(Security
)->m_hToken
)
193 if ( !DuplicateToken (static_cast<oslSecurityImpl
*>(Security
)->m_hToken
, SecurityImpersonation
, &hImpersonationToken
) )
197 /* CheckTokenMembership() can be used on W2K and higher (NT4 no longer supported by OOo)
198 and also works on Vista to retrieve the effective user rights. Just checking for
199 membership of Administrators group is not enough on Vista this would require additional
200 complicated checks as described in KB article Q118626: http://support.microsoft.com/kb/118626/en-us
203 if (AllocateAndInitializeSid(&siaNtAuthority
,
205 SECURITY_BUILTIN_DOMAIN_RID
,
206 DOMAIN_ALIAS_RID_ADMINS
,
208 &psidAdministrators
))
210 BOOL fSuccess
= FALSE
;
212 if (CheckTokenMembership(hImpersonationToken
, psidAdministrators
, &fSuccess
) && fSuccess
)
215 FreeSid(psidAdministrators
);
218 if (hImpersonationToken
)
219 CloseHandle(hImpersonationToken
);
229 void SAL_CALL
osl_freeSecurityHandle(oslSecurity Security
)
233 oslSecurityImpl
*pSecImpl
= static_cast<oslSecurityImpl
*>(Security
);
235 if (pSecImpl
->m_pNetResource
!= nullptr)
237 WNetCancelConnection2W(pSecImpl
->m_pNetResource
->lpRemoteName
, 0, true);
239 free(pSecImpl
->m_pNetResource
->lpRemoteName
);
240 free(pSecImpl
->m_pNetResource
);
243 if (pSecImpl
->m_hToken
)
244 CloseHandle(pSecImpl
->m_hToken
);
246 if ( pSecImpl
->m_hProfile
)
247 CloseHandle(pSecImpl
->m_hProfile
);
253 sal_Bool SAL_CALL
osl_getUserIdent(oslSecurity Security
, rtl_uString
**strIdent
)
255 if (Security
!= nullptr)
257 oslSecurityImpl
*pSecImpl
= static_cast<oslSecurityImpl
*>(Security
);
259 HANDLE hAccessToken
= pSecImpl
->m_hToken
;
261 if (hAccessToken
== nullptr)
262 OpenProcessToken(GetCurrentProcess(), TOKEN_DUP_QUERY
, &hAccessToken
);
266 DWORD nInfoBuffer
= 512;
267 UCHAR
* pInfoBuffer
= static_cast<UCHAR
*>(malloc(nInfoBuffer
));
269 while (!GetTokenInformation(hAccessToken
, TokenUser
,
270 pInfoBuffer
, nInfoBuffer
, &nInfoBuffer
))
272 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
274 if (auto p
= static_cast<UCHAR
*>(realloc(pInfoBuffer
, nInfoBuffer
)))
279 pInfoBuffer
= nullptr;
286 pInfoBuffer
= nullptr;
291 if (pSecImpl
->m_hToken
== nullptr)
292 CloseHandle(hAccessToken
);
296 PSID pSid
= reinterpret_cast<PTOKEN_USER
>(pInfoBuffer
)->User
.Sid
;
298 LPWSTR pSidStr
= nullptr;
299 BOOL bResult
= ConvertSidToStringSidW(pSid
, &pSidStr
);
302 rtl_uString_newFromStr(strIdent
, o3tl::toU(pSidStr
));
307 const DWORD dwError
= GetLastError();
310 "ConvertSidToStringSidW failed. GetLastError returned: " << dwError
);
315 return bResult
!= FALSE
;
322 WNetGetUserW(nullptr, nullptr, &needed
);
326 if (auto Ident
= static_cast<sal_Unicode
*>(malloc(needed
*sizeof(sal_Unicode
))))
328 if (WNetGetUserW(nullptr, o3tl::toW(Ident
), &needed
) != NO_ERROR
)
330 wcscpy(o3tl::toW(Ident
), L
"unknown");
334 rtl_uString_newFromStr( strIdent
, Ident
);
344 sal_Bool SAL_CALL
osl_getUserName(oslSecurity Security
, rtl_uString
**strName
)
346 return getUserNameImpl(Security
, strName
, true);
349 sal_Bool SAL_CALL
osl_getShortUserName(oslSecurity Security
, rtl_uString
**strName
)
351 return getUserNameImpl(Security
, strName
, false);
354 sal_Bool SAL_CALL
osl_getHomeDir(oslSecurity Security
, rtl_uString
**pustrDirectory
)
356 rtl_uString
*ustrSysDir
= nullptr;
357 bool bSuccess
= false;
359 if (Security
!= nullptr)
361 oslSecurityImpl
*pSecImpl
= static_cast<oslSecurityImpl
*>(Security
);
363 if (pSecImpl
->m_pNetResource
!= nullptr)
365 rtl_uString_newFromStr( &ustrSysDir
, o3tl::toU(pSecImpl
->m_pNetResource
->lpRemoteName
));
367 bSuccess
= osl_File_E_None
== osl_getFileURLFromSystemPath( ustrSysDir
, pustrDirectory
);
371 bSuccess
= GetSpecialFolder(&ustrSysDir
, FOLDERID_Documents
) &&
372 (osl_File_E_None
== osl_getFileURLFromSystemPath(ustrSysDir
, pustrDirectory
));
377 rtl_uString_release( ustrSysDir
);
382 sal_Bool SAL_CALL
osl_getConfigDir(oslSecurity Security
, rtl_uString
**pustrDirectory
)
384 bool bSuccess
= false;
386 if (Security
!= nullptr)
388 oslSecurityImpl
*pSecImpl
= static_cast<oslSecurityImpl
*>(Security
);
390 if (pSecImpl
->m_pNetResource
!= nullptr)
392 rtl_uString
*ustrSysDir
= nullptr;
394 rtl_uString_newFromStr( &ustrSysDir
, o3tl::toU(pSecImpl
->m_pNetResource
->lpRemoteName
));
395 bSuccess
= osl_File_E_None
== osl_getFileURLFromSystemPath( ustrSysDir
, pustrDirectory
);
398 rtl_uString_release( ustrSysDir
);
402 if (pSecImpl
->m_hToken
)
404 /* not implemented */
409 rtl_uString
*ustrFile
= nullptr;
410 sal_Unicode sFile
[_MAX_PATH
];
412 if ( !GetSpecialFolder( &ustrFile
, FOLDERID_RoamingAppData
) )
414 OSL_VERIFY(GetWindowsDirectoryW(o3tl::toW(sFile
), _MAX_DIR
) > 0);
416 rtl_uString_newFromStr( &ustrFile
, sFile
);
419 bSuccess
= osl_File_E_None
== osl_getFileURLFromSystemPath(ustrFile
, pustrDirectory
);
422 rtl_uString_release( ustrFile
);
430 sal_Bool SAL_CALL
osl_loadUserProfile(oslSecurity Security
)
432 /* CreateProcessAsUser does not load the specified user's profile
433 into the HKEY_USERS registry key. This means that access to information
434 in the HKEY_CURRENT_USER registry key may not produce results consistent
435 with a normal interactive logon.
436 It is your responsibility to load the user's registry hive into HKEY_USERS
437 with the LoadUserProfile function before calling CreateProcessAsUser.
441 RegCloseKey(HKEY_CURRENT_USER
);
443 if (Privilege(SE_RESTORE_NAME
, TRUE
))
445 HANDLE hAccessToken
= static_cast<oslSecurityImpl
*>(Security
)->m_hToken
;
447 /* try to create user profile */
450 /* retrieve security handle if not done before e.g. osl_getCurrentSecurity()
452 HANDLE hProcess
= GetCurrentProcess();
454 if (hProcess
!= nullptr)
456 OpenProcessToken(hProcess
, TOKEN_IMPERSONATE
, &hAccessToken
);
457 CloseHandle(hProcess
);
461 rtl_uString
*buffer
= nullptr;
464 getUserNameImpl(Security
, &buffer
, false);
466 ZeroMemory(&pi
, sizeof(pi
));
467 pi
.dwSize
= sizeof(pi
);
468 pi
.lpUserName
= o3tl::toW(rtl_uString_getStr(buffer
));
469 pi
.dwFlags
= PI_NOUI
;
471 if (LoadUserProfileW(hAccessToken
, &pi
))
473 UnloadUserProfile(hAccessToken
, pi
.hProfile
);
478 rtl_uString_release(buffer
);
480 if (hAccessToken
&& (hAccessToken
!= static_cast<oslSecurityImpl
*>(Security
)->m_hToken
))
481 CloseHandle(hAccessToken
);
487 void SAL_CALL
osl_unloadUserProfile(oslSecurity Security
)
489 if ( static_cast<oslSecurityImpl
*>(Security
)->m_hProfile
!= nullptr )
491 HANDLE hAccessToken
= static_cast<oslSecurityImpl
*>(Security
)->m_hToken
;
495 /* retrieve security handle if not done before e.g. osl_getCurrentSecurity()
497 HANDLE hProcess
= GetCurrentProcess();
499 if (hProcess
!= nullptr)
501 OpenProcessToken(hProcess
, TOKEN_IMPERSONATE
, &hAccessToken
);
502 CloseHandle(hProcess
);
506 /* unloading the user profile */
507 UnloadUserProfile(hAccessToken
, static_cast<oslSecurityImpl
*>(Security
)->m_hProfile
);
509 static_cast<oslSecurityImpl
*>(Security
)->m_hProfile
= nullptr;
511 if (hAccessToken
&& (hAccessToken
!= static_cast<oslSecurityImpl
*>(Security
)->m_hToken
))
512 CloseHandle(hAccessToken
);
516 static bool GetSpecialFolder(rtl_uString
**strPath
, REFKNOWNFOLDERID rFolder
)
520 if (SUCCEEDED(SHGetKnownFolderPath(rFolder
, KF_FLAG_CREATE
, nullptr, &PathW
)))
522 rtl_uString_newFromStr(strPath
, o3tl::toU(PathW
));
523 CoTaskMemFree(PathW
);
530 // We use LPCTSTR here, because we use it with SE_foo_NAME constants
531 // which are defined in winnt.h as UNICODE-dependent TEXT("PrivilegeName")
532 static BOOL
Privilege(LPCTSTR strPrivilege
, BOOL bEnable
)
537 // obtain the processes token
538 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES
| TOKEN_DUP_QUERY
, &hToken
))
542 if (!LookupPrivilegeValue(nullptr, strPrivilege
, &tp
.Privileges
[0].Luid
))
545 tp
.PrivilegeCount
= 1;
548 tp
.Privileges
[0].Attributes
= SE_PRIVILEGE_ENABLED
;
550 tp
.Privileges
[0].Attributes
= 0;
552 // enable or disable the privilege
553 if (!AdjustTokenPrivileges(hToken
, FALSE
, &tp
, 0, nullptr, nullptr))
556 if (!CloseHandle(hToken
))
562 static bool getUserNameImpl(oslSecurity Security
, rtl_uString
**strName
, bool bIncludeDomain
)
564 if (Security
!= nullptr)
566 oslSecurityImpl
*pSecImpl
= static_cast<oslSecurityImpl
*>(Security
);
568 HANDLE hAccessToken
= pSecImpl
->m_hToken
;
570 if (hAccessToken
== nullptr)
571 OpenProcessToken(GetCurrentProcess(), TOKEN_DUP_QUERY
, &hAccessToken
);
575 DWORD nInfoBuffer
= 512;
576 UCHAR
* pInfoBuffer
= static_cast<UCHAR
*>(malloc(nInfoBuffer
));
578 while (!GetTokenInformation(hAccessToken
, TokenUser
,
579 pInfoBuffer
, nInfoBuffer
, &nInfoBuffer
))
581 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
583 if (auto p
= static_cast<UCHAR
*>(realloc(pInfoBuffer
, nInfoBuffer
)))
588 pInfoBuffer
= nullptr;
595 pInfoBuffer
= nullptr;
600 if (pSecImpl
->m_hToken
== nullptr)
601 CloseHandle(hAccessToken
);
605 sal_Unicode UserName
[128];
606 sal_Unicode DomainName
[128];
607 sal_Unicode Name
[257];
608 DWORD nUserName
= SAL_N_ELEMENTS(UserName
);
609 DWORD nDomainName
= SAL_N_ELEMENTS(DomainName
);
612 if (LookupAccountSidW(nullptr, reinterpret_cast<PTOKEN_USER
>(pInfoBuffer
)->User
.Sid
,
613 o3tl::toW(UserName
), &nUserName
,
614 o3tl::toW(DomainName
), &nDomainName
, &sUse
))
618 wcscpy(o3tl::toW(Name
), o3tl::toW(DomainName
));
619 wcscat(o3tl::toW(Name
), L
"/");
620 wcscat(o3tl::toW(Name
), o3tl::toW(UserName
));
624 wcscpy(o3tl::toW(Name
), o3tl::toW(UserName
));
627 rtl_uString_newFromStr(strName
, Name
);
636 sal_Unicode
*pNameW
=nullptr;
638 WNetGetUserW(nullptr, nullptr, &needed
);
639 pNameW
= static_cast<sal_Unicode
*>(malloc (needed
*sizeof(sal_Unicode
)));
640 assert(pNameW
); // Don't handle OOM conditions
642 if (WNetGetUserW(nullptr, o3tl::toW(pNameW
), &needed
) == NO_ERROR
)
644 rtl_uString_newFromStr( strName
, pNameW
);
650 else if (pSecImpl
->m_User
[0] != '\0')
652 rtl_uString_newFromStr(strName
, o3tl::toU(pSecImpl
->m_pNetResource
->lpRemoteName
));
668 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */