Is it possible to make file accesible ONLY for certain processes? - c++

So I'm attempting to make file accesible only for certain process, firstly by finding it via this function:
bool GetProcessSid(PSID* pSID)
{
PROCESSENTRY32 entry;
entry.dwSize = sizeof(PROCESSENTRY32);
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (Process32First(snapshot, &entry) == TRUE)
{
while(Process32Next(snapshot, &entry) == TRUE)
{
const char* process_name = "testfileaccess2.exe";
std::string t(process_name);
std::wstring w_process_name(t.begin(), t.end());
if (w_process_name.compare(entry.szExeFile)== 0)
{
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID);
//...
GetSecurityInfo(hProcess,SE_KERNEL_OBJECT, OWNER_SECURITY_INFORMATION,pSID,NULL,NULL,NULL,NULL);
//getsecurityinfo(hprocess,SE_SERVICE) for service
CloseHandle(hProcess);
return TRUE;
}
}
}
return FALSE;
}
Works fine, always finds process if its alive and returns pSID.
Then I create file like this:
PACL pNewDACL = NULL;
PSID process_with_access = NULL;
PSID current_user = NULL;
DWORD sid_size = SECURITY_MAX_SID_SIZE;
SID everyone_sid;
DWORD dwRes;
if (CreateWellKnownSid(WinWorldSid, NULL, &everyone_sid, &sid_size) ==
FALSE) {
throw std::runtime_error("CreateWellKnownSid() failed: " +
std::to_string(GetLastError()));
}
GetProcessSid(&process_with_access);
GetCurrentUserSid(&current_user);
EXPLICIT_ACCESSA ea[2];
ZeroMemory(&ea, 2 * sizeof(EXPLICIT_ACCESSA));
ea[0].grfAccessPermissions = ACCESS_SYSTEM_SECURITY | READ_CONTROL | WRITE_DAC | GENERIC_ALL;
ea[0].grfAccessMode = DENY_ACCESS;
ea[0].grfInheritance = NO_INHERITANCE;
ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea[0].Trustee.ptstrName = reinterpret_cast<char*>(process_with_access);
ea[1].grfAccessPermissions = ACCESS_SYSTEM_SECURITY | READ_CONTROL | WRITE_DAC | GENERIC_ALL;
ea[1].grfAccessMode = GRANT_ACCESS;
ea[1].grfInheritance = NO_INHERITANCE;
ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea[1].Trustee.ptstrName = reinterpret_cast<char*>(current_user);
dwRes = SetEntriesInAclA(2, ea, NULL, &pNewDACL);
if (ERROR_SUCCESS != dwRes) {
printf("SetEntriesInAcl Error %u\n", dwRes);
//TODO: goto Cleanup;
}
PSECURITY_DESCRIPTOR pSD = NULL;
// Initialize a security descriptor.
pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR,
SECURITY_DESCRIPTOR_MIN_LENGTH);
if (NULL == pSD)
{
printf("error");
}
if (!InitializeSecurityDescriptor(pSD,
SECURITY_DESCRIPTOR_REVISION))
{
printf("error");
}
// Add the ACL to the security descriptor.
if (!SetSecurityDescriptorDacl(pSD,
TRUE, // bDaclPresent flag
pNewDACL,
FALSE)) // not a default DACL
{
printf("error");
}
SECURITY_ATTRIBUTES sa;
// Initialize a security attributes structure.
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = pSD;
sa.bInheritHandle = FALSE;
HANDLE hFile = CreateFileA(filename, GENERIC_ALL, 0, &sa, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
CloseHandle(hFile);
And for now it only sets access for parent of a process, not the process itself. So is it even possible what I am trying to achieve?

No, Windows' security is based around user/group access lists. It would be possible to set up a process so that it was running as some particular user and then restrict access to that user, but any program running as Administrator or Local System would be able to bypass that protection.
The best you can do against such programs is to protect against accidental access rather than malicious.

Related

How do I create a file with LPSECURITY_ATTRIBUTES by using CreateFile on Windows?

Here's CreateFile doc.
I want to create a file via CreateFile with SECURITY_ATTRIBUTES, when I create it under a windows account user A, the file shouldn't be accessed by another windows user B.
I found this
Creating a Security Descriptor for a New Object in C++
But still couldn't figure it out how to assgin a certain user.
But still couldn't figure it out how to assgin a certain user.
You need to get the SID of a certain user first.
Here is some steps,
Validate the input parameters.
Create buffers for the SID and the domain name that may be large
enough.
In a loop, call LookupAccountName to retrieve the SID for the
account name supplied. If the buffer for the SID or the buffer for
the domain name is not large enough, the buffer size needed is
returned in cbSid or cchDomainName, respectively, and a new buffer
is allocated before the next call to LookupAccountName. Note that
the information is retrieved on the local system when the
lpSystemName parameter is set to NULL.
Free the memory allocated for the domain name buffer.
Then pass the SID to the SetEntriesInAclA function,
The SetEntriesInAcl function creates a new access control list (ACL)
by merging new access control or audit control information into an
existing ACL structure.
Modified code:
#pragma comment(lib, "advapi32.lib")
#include <windows.h>
#include <stdio.h>
#include <aclapi.h>
#include <tchar.h>
#include <mq.h.>
HRESULT GetSid(
LPCWSTR wszAccName,
PSID* ppSid
)
{
// Validate the input parameters.
if (wszAccName == NULL || ppSid == NULL)
{
return MQ_ERROR_INVALID_PARAMETER;
}
// Create buffers that may be large enough.
// If a buffer is too small, the count parameter will be set to the size needed.
const DWORD INITIAL_SIZE = 32;
DWORD cbSid = 0;
DWORD dwSidBufferSize = INITIAL_SIZE;
DWORD cchDomainName = 0;
DWORD dwDomainBufferSize = INITIAL_SIZE;
WCHAR* wszDomainName = NULL;
SID_NAME_USE eSidType;
DWORD dwErrorCode = 0;
HRESULT hr = MQ_OK;
// Create buffers for the SID and the domain name.
*ppSid = (PSID) new BYTE[dwSidBufferSize];
if (*ppSid == NULL)
{
return MQ_ERROR_INSUFFICIENT_RESOURCES;
}
memset(*ppSid, 0, dwSidBufferSize);
wszDomainName = new WCHAR[dwDomainBufferSize];
if (wszDomainName == NULL)
{
return MQ_ERROR_INSUFFICIENT_RESOURCES;
}
memset(wszDomainName, 0, dwDomainBufferSize * sizeof(WCHAR));
// Obtain the SID for the account name passed.
for (; ; )
{
// Set the count variables to the buffer sizes and retrieve the SID.
cbSid = dwSidBufferSize;
cchDomainName = dwDomainBufferSize;
if (LookupAccountNameW(
NULL, // Computer name. NULL for the local computer
wszAccName,
*ppSid, // Pointer to the SID buffer. Use NULL to get the size needed,
&cbSid, // Size of the SID buffer needed.
wszDomainName, // wszDomainName,
&cchDomainName,
&eSidType
))
{
if (IsValidSid(*ppSid) == FALSE)
{
wprintf(L"The SID for %s is invalid.\n", wszAccName);
dwErrorCode = MQ_ERROR;
}
break;
}
dwErrorCode = GetLastError();
// Check if one of the buffers was too small.
if (dwErrorCode == ERROR_INSUFFICIENT_BUFFER)
{
if (cbSid > dwSidBufferSize)
{
// Reallocate memory for the SID buffer.
wprintf(L"The SID buffer was too small. It will be reallocated.\n");
FreeSid(*ppSid);
*ppSid = (PSID) new BYTE[cbSid];
if (*ppSid == NULL)
{
return MQ_ERROR_INSUFFICIENT_RESOURCES;
}
memset(*ppSid, 0, cbSid);
dwSidBufferSize = cbSid;
}
if (cchDomainName > dwDomainBufferSize)
{
// Reallocate memory for the domain name buffer.
wprintf(L"The domain name buffer was too small. It will be reallocated.\n");
delete[] wszDomainName;
wszDomainName = new WCHAR[cchDomainName];
if (wszDomainName == NULL)
{
return MQ_ERROR_INSUFFICIENT_RESOURCES;
}
memset(wszDomainName, 0, cchDomainName * sizeof(WCHAR));
dwDomainBufferSize = cchDomainName;
}
}
else
{
wprintf(L"LookupAccountNameW failed. GetLastError returned: %d\n", dwErrorCode);
hr = HRESULT_FROM_WIN32(dwErrorCode);
break;
}
}
delete[] wszDomainName;
return hr;
}
void main()
{
PSID sid;
GetSid(L"strives", &sid); // enter a user name
DWORD dwRes, dwDisposition;
PACL pACL = NULL;
PSECURITY_DESCRIPTOR pSD = NULL;
EXPLICIT_ACCESS ea;
SECURITY_ATTRIBUTES sa;
HANDLE lRes = NULL;
// Initialize an EXPLICIT_ACCESS structure for an ACE.
// The ACE will allow Everyone read access to the key.
ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
ea.grfAccessPermissions = GENERIC_ALL;
ea.grfAccessMode = SET_ACCESS;
ea.grfInheritance = NO_INHERITANCE;
ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea.Trustee.TrusteeType = TRUSTEE_IS_USER;
ea.Trustee.ptstrName = (LPTSTR)sid;
// Create a new ACL that contains the new ACEs.
dwRes = SetEntriesInAcl(1, &ea, NULL, &pACL);
if (ERROR_SUCCESS != dwRes)
{
_tprintf(_T("SetEntriesInAcl Error %u\n"), GetLastError());
goto Cleanup;
}
// Initialize a security descriptor.
pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR,
SECURITY_DESCRIPTOR_MIN_LENGTH);
if (NULL == pSD)
{
_tprintf(_T("LocalAlloc Error %u\n"), GetLastError());
goto Cleanup;
}
if (!InitializeSecurityDescriptor(pSD,
SECURITY_DESCRIPTOR_REVISION))
{
_tprintf(_T("InitializeSecurityDescriptor Error %u\n"),
GetLastError());
goto Cleanup;
}
// Add the ACL to the security descriptor.
if (!SetSecurityDescriptorDacl(pSD,
TRUE, // bDaclPresent flag
pACL,
FALSE)) // not a default DACL
{
_tprintf(_T("SetSecurityDescriptorDacl Error %u\n"),
GetLastError());
goto Cleanup;
}
// Initialize a security attributes structure.
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = pSD;
sa.bInheritHandle = FALSE;
// Use the security attributes to set the security descriptor
// when you create a key.
lRes = CreateFile(_T("D:\\File.txt"), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
&sa, OPEN_ALWAYS, 0, NULL);
if (lRes != NULL)
{
_tprintf(_T("Create file success\n"));
}
Cleanup:
if (pACL)
LocalFree(pACL);
if (pSD)
LocalFree(pSD);
if (lRes)
CloseHandle(lRes);
return;
}
You can verify by checking the properties of the file.

Connect to a named pipe in the same network without Administrator rights

I created a named pipe server and granted full access rights to Everyone.
I tried to connect to the named pipe server from different machine on the same network but I get an error says the login failed - ERROR_LOGON_FAILURE.
I read about NullSessionPipes and I compiled the example from MSDN. However, I need an administration right to register the NullSessionPipe in the registry which I'm trying to avoid.
How does CreateFile actually do the login to the remote named pipe? Do I need to run my client in a specific context to make this works? (e.g Guest).
server code:
DWORD dwRes, dwDisposition;
PSID pEveryoneSID = NULL, pAdminSID = NULL;
PACL pACL = NULL;
PSECURITY_DESCRIPTOR pSD = NULL;
EXPLICIT_ACCESS ea[2];
SID_IDENTIFIER_AUTHORITY SIDAuthWorld =
SECURITY_WORLD_SID_AUTHORITY;
SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;
SECURITY_ATTRIBUTES sa;
LONG lRes;
HKEY hkSub = NULL;
// Create a well-known SID for the Everyone group.
if (!AllocateAndInitializeSid(&SIDAuthWorld, 1,
SECURITY_WORLD_RID,
0, 0, 0, 0, 0, 0, 0,
&pEveryoneSID))
{
return false;
}
// Initialize an EXPLICIT_ACCESS structure for an ACE.
// The ACE will allow Everyone read access to the key.
ZeroMemory(&ea, 1 * sizeof(EXPLICIT_ACCESS));
ea[0].grfAccessPermissions = 0xFFFFFFFF;
ea[0].grfAccessMode = SET_ACCESS;
ea[0].grfInheritance = NO_INHERITANCE;
ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
ea[0].Trustee.ptstrName = (LPTSTR)pEveryoneSID;
// Create a new ACL that contains the new ACEs.
dwRes = SetEntriesInAcl(1, ea, NULL, &pACL);
if (ERROR_SUCCESS != dwRes)
{
return false;
}
// Initialize a security descriptor.
pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR,
SECURITY_DESCRIPTOR_MIN_LENGTH);
if (NULL == pSD)
{
return false;
}
if (!InitializeSecurityDescriptor(pSD,
SECURITY_DESCRIPTOR_REVISION))
{
return false;
}
// Add the ACL to the security descriptor.
if (!SetSecurityDescriptorDacl(pSD,
TRUE, // bDaclPresent flag
pACL,
FALSE)) // not a default DACL
{
return false;
}
// Initialize a security attributes structure.
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = pSD;
sa.bInheritHandle = FALSE;
// create named pipe
auto NamedPipe = CreateNamedPipeA(namedPipeName,
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_NOWAIT | PIPE_ACCEPT_REMOTE_CLIENTS,
PIPE_UNLIMITED_INSTANCES,
NAMED_PIPE_SIZE,
NAMED_PIPE_SIZE,
NMPWAIT_USE_DEFAULT_WAIT,
&sa);
how do this task described in How to create an anonymous pipe that gives access to everyone
the error ERROR_LOGON_FAILURE say that client code not makes a connection to a network resource. really need call WNetAddConnection2 (or analog api before call CreateFile on remote pipe)
The client opens the pipe with a call to the CreateFile function. If
an error occurs, the client checks if it is a logon failure error, an
access denied error, or a bad password error. If an error occurs,
perform an anonymous logon by calling the WNetAddConnection2 function
and passing an empty string as user name and password. When the null
session is established, the client calls the CreateFile function
again.
so client code must look like:
NETRESOURCE nr = {};
nr.dwUsage = RESOURCEUSAGE_CONNECTABLE|RESOURCEUSAGE_CONTAINER;
nr.lpRemoteName = L"\\\\server\\IPC$";
WNetAddConnection2W(&nr, L"", L"",0);
HANDLE hFile = CreateFileW(L"\\\\?\\UNC\\server\\PIPE\\MyPipe",
FILE_GENERIC_READ|FILE_GENERIC_WRITE,
0, 0, OPEN_EXISTING, 0, 0);
from server side need not only set 0 in place DACL (this allow any access) or add allowed ACE for WinAnonymousSid (this is != WinWorldSid aka everyone) but also set untrusted mandatory label. this is slipped in code example, because i think code yet pre vista.
SECURITY_DESCRIPTOR sd;
BOOL fOk = InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION) &&
SetSecurityDescriptorDacl(&sd, TRUE, 0, FALSE);
if (fOk)
{
RTL_OSVERSIONINFOW ovi = { sizeof(ovi) };
if (0 > RtlGetVersion(&ovi))
{
fOk = FALSE;
}
else
{
if (ovi.dwMajorVersion > 5)
{
fOk = FALSE;
ULONG cb = GetSidLengthRequired(1);
PSID UntrustedLabelSid = alloca(cb);
if (CreateWellKnownSid(WinUntrustedLabelSid, 0, UntrustedLabelSid, &cb))
{
PACL Sacl = (PACL)alloca(cb += sizeof(ACL) + sizeof(ACE_HEADER) + sizeof(ACCESS_MASK));
fOk = InitializeAcl(Sacl, cb, ACL_REVISION) &&
AddMandatoryAce(Sacl, ACL_REVISION, 0, SYSTEM_MANDATORY_LABEL_NO_WRITE_UP, UntrustedLabelSid) &&
SetSecurityDescriptorSacl(&sd, TRUE, Sacl, FALSE);
}
}
}
}

Win32 API: Creating file public for current user but private for everyone else

I am testing the following code in C using Win32 API, which is intended to create a new file that is accessible for the current user but private (not accessible) for everyone else.
For this this a deny all permissions for everyone SID, then for current's user SID I set up the permissions.
The file is created successfully and the permissions are apparently set up successfully (see screenshots below), however when I try to open the file with notepad, it says "access is denied" (My file explorer is running under the same session), also if I open a command prompt and do "type file_created.txt" the same "access is denied" appear.
I can of course, restore manually the permissions since I am administrator, but the idea is to make it work programmatically.
Image with everyone permissions:
Image with current user permissions:
The code:
#include <windows.h>
#include <AccCtrl.h>
#include <aclapi.h>
#include <stdio.h>
#include <stdexcept>
#include <string>
#undef UNICODE
int GetCurrentUserSid(PSID* pSID)
{
const int MAX_NAME = 256;
DWORD i, dwSize = 0;
HANDLE hToken;
PTOKEN_USER user;
TOKEN_INFORMATION_CLASS TokenClass = TokenUser;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ | TOKEN_QUERY, &hToken))
return GetLastError();
else
wprintf(L"OpenProcessToken() - got the handle to the access token!\n");
if (!GetTokenInformation(hToken, TokenClass, NULL, 0, &dwSize))
{
DWORD dwResult = GetLastError();
if (dwResult != ERROR_INSUFFICIENT_BUFFER)
{
wprintf(L"GetTokenInformation() failed, error %u\n", dwResult);
return FALSE;
}
else
wprintf(L"GetTokenInformation() - have an ample buffer...\n");
}
else
wprintf(L"GetTokenInformation() - buffer for Token group is OK\n");
user = (PTOKEN_USER)LocalAlloc(GPTR, dwSize);
if (!GetTokenInformation(hToken, TokenClass, user, dwSize, &dwSize))
{
wprintf(L"GetTokenInformation() failed, error %u\n", GetLastError());
return FALSE;
}
else
wprintf(L"GetTokenInformation() for getting the TokenGroups is OK\n");
DWORD dw_sid_len = GetLengthSid(user->User.Sid);
*pSID = (SID*)LocalAlloc(GPTR, dw_sid_len);
CopySid(dw_sid_len, *pSID, user->User.Sid);
return 0;
}
DWORD set_file_security(LPSTR filename)
{
PACL pNewDACL = NULL;
PSID current_user = NULL;
DWORD sid_size = SECURITY_MAX_SID_SIZE;
SID everyone_sid;
DWORD dwRes;
if (CreateWellKnownSid(WinWorldSid, NULL, &everyone_sid, &sid_size) ==
FALSE) {
throw std::runtime_error("CreateWellKnownSid() failed: " +
std::to_string(GetLastError()));
}
GetCurrentUserSid(&current_user);
EXPLICIT_ACCESSA ea[2];
ZeroMemory(&ea, 2 * sizeof(EXPLICIT_ACCESSA));
ea[0].grfAccessPermissions = ACCESS_SYSTEM_SECURITY | READ_CONTROL | WRITE_DAC | GENERIC_ALL;
ea[0].grfAccessMode = GRANT_ACCESS;
ea[0].grfInheritance = NO_INHERITANCE;
ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea[0].Trustee.ptstrName = reinterpret_cast<char*>(current_user);
ea[1].grfAccessPermissions = ACCESS_SYSTEM_SECURITY | READ_CONTROL | WRITE_DAC | GENERIC_ALL;
ea[1].grfAccessMode = DENY_ACCESS;
ea[1].grfInheritance = NO_INHERITANCE;
ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea[1].Trustee.ptstrName = reinterpret_cast<char*>(&everyone_sid);
dwRes = SetEntriesInAclA(2, ea, NULL, &pNewDACL);
if (ERROR_SUCCESS != dwRes) {
printf("SetEntriesInAcl Error %u\n", dwRes);
//TODO: goto Cleanup;
}
PSECURITY_DESCRIPTOR pSD = NULL;
// Initialize a security descriptor.
pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR,
SECURITY_DESCRIPTOR_MIN_LENGTH);
if (NULL == pSD)
{
_tprintf(_T("LocalAlloc Error %u\n"), GetLastError());
goto Cleanup;
}
if (!InitializeSecurityDescriptor(pSD,
SECURITY_DESCRIPTOR_REVISION))
{
_tprintf(_T("InitializeSecurityDescriptor Error %u\n"),
GetLastError());
goto Cleanup;
}
// Add the ACL to the security descriptor.
if (!SetSecurityDescriptorDacl(pSD,
TRUE, // bDaclPresent flag
pNewDACL,
FALSE)) // not a default DACL
{
_tprintf(_T("SetSecurityDescriptorDacl Error %u\n"),
GetLastError());
goto Cleanup;
}
SECURITY_ATTRIBUTES sa;
// Initialize a security attributes structure.
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = pSD;
sa.bInheritHandle = FALSE;
HANDLE hFile = CreateFileA(filename, GENERIC_ALL, 0, &sa, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
CloseHandle(hFile);
//dwRes = SetNamedSecurityInfoA(filename, SE_FILE_OBJECT,
// DACL_SECURITY_INFORMATION, NULL, NULL, pNewDACL, NULL);
//if (ERROR_SUCCESS != dwRes) {
// printf("SetNamedSecurityInfo Error %u\n", dwRes);
// //goto Cleanup;
//}
Cleanup:
if (pNewDACL != NULL)
LocalFree((HLOCAL)pNewDACL);
return dwRes;
}
int main()
{
//return 0;
// Create Everyone SID.
DWORD sid_size = SECURITY_MAX_SID_SIZE;
SID everyone_sid;
if (CreateWellKnownSid(WinWorldSid, NULL, &everyone_sid, &sid_size) ==
FALSE) {
throw std::runtime_error("CreateWellKnownSid() failed: " +
std::to_string(GetLastError()));
}
LPSTR filename = "created_file.txt";
set_file_security(filename);
return 0;
}
NOTE: I realized the code has memory leaks and other issues, I was just quickly hacking to test the idea.
In the Windows OS explicit deny permissions have a precedence over explicit allow permissions. So since "Everyone" group includes your account, access to the file is denied, even if you enabled it for yourself. In fact you don't need deny rule altogether, if access rights are not set in the object ACL for some user, access will be denied by default.

Giving Folder access to only LocalAccount & denying from Everyone

I have to create a folder or modify security attributes if folder already exist. I need to set permissions to folder so that only LocalAccount has full access and other user accounts should not have any access to this folder.
As of now, I'm trying the below code,but couldn't achieve.
Updated: I guess, any existing ACEs causing problem(if folder exist) or Any ACEs which are inherited from parent directory causing problem?
DWORD dwRes;
PSID pEveryoneSID = NULL, pLocalSystemSID = NULL;
PACL pACL = NULL;
PSECURITY_DESCRIPTOR pSD = NULL;
EXPLICIT_ACCESS ea[2];
SID_IDENTIFIER_AUTHORITY SIDAuthWorld =
SECURITY_WORLD_SID_AUTHORITY;
SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;
SECURITY_ATTRIBUTES sa;
// Create a well-known SID for the Everyone group.
if (!AllocateAndInitializeSid(&SIDAuthWorld, 1,
SECURITY_WORLD_RID,
0, 0, 0, 0, 0, 0, 0,
&pEveryoneSID))
{
LOGERROR(_T("AllocateAndInitializeSid Error %u\n"), GetLastError());
goto Cleanup;
}
// Initialize an EXPLICIT_ACCESS structure for an ACE.
// The ACE will deny Everyone GENERIC_ALL to the folder.
ZeroMemory(&ea, 2 * sizeof(EXPLICIT_ACCESS));
ea[0].grfAccessPermissions = GENERIC_ALL;
ea[0].grfAccessMode = DENY_ACCESS;
ea[0].grfInheritance = NO_INHERITANCE;
ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
ea[0].Trustee.ptstrName = (LPTSTR)pEveryoneSID;
// Create a SID for the LocalSystem account(A special account used by the operating system) group.
if (!AllocateAndInitializeSid(&SIDAuthNT, 1,
SECURITY_LOCAL_SYSTEM_RID,
0, 0, 0, 0, 0, 0, 0,
&pLocalSystemSID))
{
LOGERROR(_T("AllocateAndInitializeSid Error %u\n"), GetLastError());
goto Cleanup;
}
// Initialize an EXPLICIT_ACCESS structure for an ACE.
// The ACE will allow the LocalSystem full access to the folder
ea[1].grfAccessPermissions = GENERIC_ALL;
ea[1].grfAccessMode = GRANT_ACCESS; // or SET_ACCESS ?
ea[1].grfInheritance = NO_INHERITANCE;
ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea[1].Trustee.TrusteeType = TRUSTEE_IS_GROUP; //not sure what to use here for localAccount
ea[1].Trustee.ptstrName = (LPTSTR)pLocalSystemSID;
// Create a new ACL that contains the new ACEs.
dwRes = SetEntriesInAcl(2, ea, NULL, &pACL);
if (ERROR_SUCCESS != dwRes)
{
LOGERROR(_T("SetEntriesInAcl Error %u\n"), GetLastError());
goto Cleanup;
}
// Initialize a security descriptor.
pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR,
SECURITY_DESCRIPTOR_MIN_LENGTH);
if (NULL == pSD)
{
LOGERROR(_T("LocalAlloc Error %u\n"), GetLastError());
goto Cleanup;
}
if (!InitializeSecurityDescriptor(pSD,
SECURITY_DESCRIPTOR_REVISION))
{
LOGERROR(_T("InitializeSecurityDescriptor Error %u\n"),
GetLastError());
goto Cleanup;
}
// Add the ACL to the security descriptor.
if (!SetSecurityDescriptorDacl(pSD,
TRUE, // bDaclPresent flag
pACL,
FALSE)) // not a default DACL
{
LOGERROR(_T("SetSecurityDescriptorDacl Error %u\n"),
GetLastError());
goto Cleanup;
}
// Initialize a security attributes structure.
sa.nLength = sizeof (SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = pSD;
sa.bInheritHandle = FALSE;
int rVal = SHCreateDirectoryExW(NULL, m_tcProxyData, &sa);

Do I need SE_SHUTDOWN_NAME privilege to log off a user?

I need to log off a user from a C++ program. I use ExitWindowsEx API for that, but I'm not sure from the documentation if I need any special privileges for that?
You do. Here's an example
bool ShutdownWindows(void)
{
HANDLE hToken = NULL;
TOKEN_PRIVILEGES tkp = {0};
bool bRet = false;
// Get a token for this process.
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
if (LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid)) {
tkp.PrivilegeCount = 1; // one privilege to set
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
// Get the shutdown privilege for this process.
if (AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, NULL, 0)) {
::CloseHandle(hToken);
if (ERROR_SUCCESS == GetLastError()) {
DWORD dwFlags = EWX_POWEROFF;
DWORD dwReason = SHTDN_REASON_MAJOR_SYSTEM;
if (ExitWindowsEx(dwFlags, dwReason)) {
bRet = true;
}
}
}
}
}
return bRet;
} // ShutdownWindows