I have C++ code that change SACL of a folder as it is expected. The things become strange when I want to change SACL of an exsiting Named Pipe, the code executes successful but when I check it via Get-Acl -Path \\.\pipe\lsass -Audit | fl it returns error number 87 which is ERROR_INVALID_PARAMETER and SACL does not work. The error may be caused by setting not zero to OVERLAPPED structure according to MS Support Site but it barely helping in setting SACL.
StackOverFlow wants me to add some details, so I will write some water here
Maybe I messed up with some of the rights to provide to SetSecurityInfo and it is specifical to Named Pipes or I need to suspend it before change SACL?
using namespace std;
int main()
{
SetSecurityPrivilage(TRUE); // Got SeSecurityPrivilage
//HANDLE hPipe = CreateFile(L"C\:\\Users\\simp\\Desktop\\test", ACCESS_SYSTEM_SECURITY, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); // Folder SACL testing
HANDLE hPipe = CreateFile(L"\\\\.\\pipe\\lsass", ACCESS_SYSTEM_SECURITY, 0, NULL, OPEN_EXISTING, NULL, NULL);
if (hPipe != INVALID_HANDLE_VALUE)
{
PACL pOldSACL = NULL;
if (GetSecurityInfo(hPipe, SE_KERNEL_OBJECT, SACL_SECURITY_INFORMATION, NULL, NULL, NULL, &pOldSACL, NULL) == ERROR_SUCCESS)
{
// SACL
TRUSTEE trusteeSACL[1];
trusteeSACL[0].TrusteeForm = TRUSTEE_IS_NAME;
trusteeSACL[0].TrusteeType = TRUSTEE_IS_GROUP;
trusteeSACL[0].ptstrName = (LPWCH)(L"Everyone");
trusteeSACL[0].MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
trusteeSACL[0].pMultipleTrustee = NULL;
EXPLICIT_ACCESS explicit_access_listSACL[1];
ZeroMemory(&explicit_access_listSACL[0], sizeof(EXPLICIT_ACCESS));
explicit_access_listSACL[0].grfAccessMode = SET_AUDIT_SUCCESS;
//explicit_access_listSACL[0].grfAccessMode = SET_AUDIT_FAILURE;
explicit_access_listSACL[0].grfAccessPermissions = ACCESS_SYSTEM_SECURITY;
explicit_access_listSACL[0].grfInheritance = NO_INHERITANCE;
explicit_access_listSACL[0].Trustee = trusteeSACL[0];
PACL pNewSACL = NULL;
if (SetEntriesInAcl(1, explicit_access_listSACL, pOldSACL, &pNewSACL) == ERROR_SUCCESS)
{
if (SetSecurityInfo(hPipe, SE_KERNEL_OBJECT, SACL_SECURITY_INFORMATION, NULL, NULL, NULL, pNewSACL) == ERROR_SUCCESS)
{
printf("%s\n", "SACL SetSecurityInfo IS WORKS");
}
else
{
//Error handling
printf("%s%d\n", "SetSecurityInfo SACL", GetLastError());
}
LocalFree(pNewSACL);
}
else
{
//Error handling
printf("%s%d\n", "SetEntriesInAcl", GetLastError());
}
LocalFree(pOldSACL);
}
else
{
//Error
printf("%s%d\n", "GetSecurityInfo SACL", GetLastError());
}
}
else
{
//Error handling
printf("%s%d", "Incorrect handle", GetLastError());
}
CloseHandle(hPipe);
Actually, the code is doing it's job. Then you compile and run this, you will change SACL of a pipe as well as a file. My mistake was in this part:
explicit_access_listSACL[0].grfAccessPermissions = ACCESS_SYSTEM_SECURITY;
Which means that logs will be generate only when user will request ACCESS_SYSTEM_SECURITY rights to a pipe, so change it to your needs. However, the reason behind 87 error is still unknown.
Related
Recently I posted this question and now I am trying to set a reparse point after a file modification with WordPad app. Currently I checked that the reparse point is a Microsoft tag and I can save the reparse point data in a REPARSE_DATA_BUFFER pointer before the file lose the reparse point. But when I try to set the reparse point to the file, after a file modification, I always get the 395 error with the GetLastError function after call to DeviceIoControl function using the control code FSCTL_SET_REPARSE_POINT. The error 395 doesn't appear in this System Error Codes although I found this error here that has sense. I also removed the discretionary access control list (DACL) from the file, to grants full access to the file by everyone, before try to set the reparse point but I got the same error. Here I put two fragments of my code to get and set the reparse point. I will appreciate any help.
Code to get the reparse point
HANDLE hDevice = CreateFile(
filePath.c_str(), // File path in the computer
0,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
NULL);
if (hDevice != INVALID_HANDLE_VALUE)
{
size_t maxReparse = MAXIMUM_REPARSE_DATA_BUFFER_SIZE;
rdb = (REPARSE_DATA_BUFFER*)malloc(maxReparse); // rdb was declared as: REPARSE_DATA_BUFFER* rdb;
DWORD outBufferSize = maxReparse;
DWORD bytesReturned = 0;
if (DeviceIoControl(hDevice, FSCTL_GET_REPARSE_POINT, NULL, 0, rdb, outBufferSize, &bytesReturned, NULL))
{
if (rdb != NULL)
{
if (IsReparseTagMicrosoft(rdb->ReparseTag))
{
wprintf(L"Is a Microsoft tag.\n");
}
Code to set the reparse point
LPTSTR pszObjName = const_cast<wchar_t*>(filePath.c_str()); // File path in the computer
PACL newDACL = NULL; // NULL discretionary access control list to grant full access to everyone
DWORD secInfo = SetNamedSecurityInfo(pszObjName, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, newDACL, NULL);
if (secInfo == ERROR_SUCCESS)
{
HANDLE hDevice = CreateFile(filePath.c_str(),
GENERIC_ALL, //GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
if (hDevice != INVALID_HANDLE_VALUE)
{
size_t maxReparse = MAXIMUM_REPARSE_DATA_BUFFER_SIZE;
DWORD inBufferSize = maxReparse;
if (rdb != NULL)
{
DWORD bytesReturned = 0;
if (!DeviceIoControl(hDevice, FSCTL_SET_REPARSE_POINT, rdb, inBufferSize, NULL, 0, &bytesReturned, NULL))
{
DWORD error = GetLastError(); // Error 395
unsigned long errorUL = error;
wprintf(L"Error %lu in DeviceIoControl method.\n", errorUL);
}
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);
}
}
}
}
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(¤t_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.
I'm trying to change audit settings of a folder.As i was testing my code on different machines i found that SetNamedSecurityInfo call restarts the system.This happened with some machines.A pop up generates which says "Windows has encountered a security issue and will restart in one minute".I'm not able to figure out the reason.Any help will be appreciated!
HANDLE hProcess = GetCurrentProcess();
HANDLE hToken;
DWORD val;
BOOL result;
result = OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES, &hToken);
if (result == 0)
{
printf("\nBreak After open process");
return 0;
}
else{
printf("\ncontinue after open process");
}
// Used for reading SACL's
result = SetPrivilege(hToken, SE_SECURITY_NAME, TRUE);
if (result == 0)
{
printf("\nBreak After setprivilege");
return 0;
}
else{
printf("\ncontinue after open process");
}
CloseHandle(hToken);
retval = GetNamedSecurityInfo(file, SE_FILE_OBJECT, SACL_SECURITY_INFORMATION, &owner, NULL, NULL, &sacl, &psd);
if(retval != 0)
{
wcout << "GetNamedSecurityInfo failed with error: " << retval << endl;
return -1;
}
printf("\nBuilt trust successfully before");
BuildTrusteeWithSid(ptrust,psd);
printf("\nBuilt trust successfully");
printf("\ntrying to modify ...");
EXPLICIT_ACCESS ea;
PACL pNewSACL = NULL;
ACCESS_MODE AccessMode = SET_AUDIT_SUCCESS; //SET_AUDIT_SUCCESS, SET_AUDIT_FAILURE
DWORD dwAccessRights = 0X410D0060;
DWORD dwInheritance = CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE;
ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
ea.grfAccessPermissions = dwAccessRights;
ea.grfAccessMode = SET_AUDIT_SUCCESS;
ea.grfInheritance = dwInheritance;
ea.Trustee = *(ptrust);
DWORD dwRes = SetEntriesInAcl(1, &ea, sacl, &pNewSACL);
if(dwRes != ERROR_SUCCESS)
{
printf("SetEntriesInAcl() error %u\n", dwRes);
}
else
{
printf("SetEntriesInAcl() is OK\n");
}
dwRes = SetNamedSecurityInfo(file, SE_FILE_OBJECT, SACL_SECURITY_INFORMATION, NULL, NULL, NULL, pNewSACL);
if(dwRes != ERROR_SUCCESS)
{
printf("SetNamedSecurityInfo() error %u\n", dwRes);
}
else
printf("SetNamedSecurityInfo() is OK\n\n");
LocalFree(psd);
There is an global policy entry that controls the shutdown if the system was unable to log security audits.
See:
"Computer Configuration\Windows Settings\Local Policies\Security Options"
"Audit: Shut down system immediately if unable to log security audits"
This could happen in combination with:
"Computer Configuration\Windows Settings\Local Policies\Security Options"
"Audit: Audit the accesss of global system objects"
I'm trying to shrink my partition to the last used LCN. Has anybody used this control code?
I'm getting System Error code 87 every time in the following code:
HANDLE hDiskHandle = NULL;
DISK_GROW_PARTITION dgp;
DWORD dwBytesReturned = 0;
dgp.PartitionNumber = 2;
dgp.BytesToGrow.QuadPart = -1;
hDiskHandle = CreateFile(_T("\\.\PhysicalDrive0"), GENERIC_ALL, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, NULL, NULL);
if (hDiskHandle == INVALID_HANDLE_VALUE) {
int err = GetLastError();
printf("Unable to get handle on Volume, error : %d", err);
}
if (!DeviceIoControl(
hDiskHandle,
IOCTL_DISK_GROW_PARTITION,
&dgp,
sizeof dgp,
NULL,
0,
&dwBytesReturned,
NULL
)) {
int err = GetLastError();
printf("DeviceIoControl Failed, error : %d", err);;
}
My hard drive has 3 partitions (C, D, E). The E: drive is practically empty.
[OP's solution converted to answer below]
It turns out my program was fine. It started working after changing access from
GENERIC_ALL
to
GENERIC_READ | GENERIC_WRITE