From: falco on
Hi all!

Hoping that someone might be able to give me a hint or two here. I'm
trying to check that the current user has permission to write to or
delete a file on disk. Using pretty bare C++, no COM etc. I've looked
everywhere for an example, but just couldn't find anything. So in the
end I hacked something together, which seems to work 95% of the time,
but the remaining 5% eludes me. So, the question is - if I want to find
out if the current user can write to or delete a file pointed to by a
string path, how do I go about it? My current code is pasted below, but
as I say, it's a bit on the faulty side. For anyone looking at the
code, it's worth paying attention to the code directly after "//Note -
these below are never hit." - these are what I would have expected to
provide the info required, but as the comment says, those bits are
never set. The only one that seemed to be doing what was expected was
the delete permission flag, which is what I tried to use, but that's
obviously insufficient.

The specific failure: On one machine (Windows 2000 Professional, Dutch
language), this code reports that the user doesn't have permission to
delete a file, when the file is obviously modifiable, and in fact can
be deleted manually from within Explorer without problems.

What have I messed up? Am I close to the answer, or completely
misguided? Hints, suggestions etc gladly accepted!


//Example:
//Does the current user have permission to update a given file?
//Cobbled together from various examples and functions,
//needs tidy-up.


ace_list* m_sAceList = NULL; // list of Access Control Entries
BOOL bSuccess = TRUE;
BYTE* pSecDescriptorBuf;
DWORD dwSizeNeeded = 0;

// Find out size of needed buffer for security descriptor with DACL
// DACL = Discretionary Access Control List
bSuccess = GetFileSecurityW((BSTR)sPath,
DACL_SECURITY_INFORMATION,
NULL,
0,
&dwSizeNeeded);

if (0 == dwSizeNeeded)
{
return failure;
}
pSecDescriptorBuf = new BYTE[dwSizeNeeded];

// Retrieve security descriptor with DACL information
bSuccess = GetFileSecurityW((BSTR)sPath,
DACL_SECURITY_INFORMATION,
pSecDescriptorBuf,
dwSizeNeeded,
&dwSizeNeeded);

// Check if we successfully retrieved security descriptor with DACL
information
if (!bSuccess)
{
DWORD dwError = GetLastError();
return failure;
}

// Getting DACL from Security Descriptor
PACL pacl;
BOOL bDaclPresent, bDaclDefaulted;
bSuccess =
GetSecurityDescriptorDacl((SECURITY_DESCRIPTOR*)pSecDescriptorBuf,
&bDaclPresent, &pacl, &bDaclDefaulted);

// Check if we successfully retrieved DACL
if (!bSuccess)
{
DWORD dwError = GetLastError();
//cout << "Failed to retrieve DACL from security descriptor (" <<
dwError << ")\n";
return failure;
}

// Check if DACL present in security descriptor
if (!bDaclPresent)
{
//cout << "DACL was not found.\n";
return failure;
}

//Check to see if the current user has access.
wchar_t wszAccName[100] = L"";
DWORD accNameSize = sizeof(wszAccName);
PSID ppSid;
DWORD cbSid = 0;
DWORD cchDomainName = 0;
//DWORD dwDomainBufferSize = INITIAL_SIZE;
wchar_t * wszDomainName = NULL;
SID_NAME_USE eSidType;


//Allocate SID buffer.
ppSid = (PSID) new BYTE[1024];
cbSid = 1024;
wszDomainName = new wchar_t[1024];
cchDomainName = 1024;


if (!GetUserName( wszAccName, &accNameSize ) ){
//fail
}
if (LookupAccountName( 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)
{
gMessageBox("Error: Invalid SID for %s.", wszAccName);
return failure;
} else {

TRUSTEE trustee;
BuildTrusteeWithSid(&trustee, ppSid);

ACCESS_MASK mask = 0;
DWORD dwRetVal = GetEffectiveRightsFromAcl(pacl,
&trustee,
&mask);


if (!(mask & 65536)){
Assert(false);
return failure;
}
//Note - these below are never hit. This is the first sign that things
are going wrong...
if (mask & GENERIC_READ) DebugOut("I can read!");
if (mask & GENERIC_WRITE) DebugOut("I can write!");
if (mask & GENERIC_EXECUTE) DebugOut("I can exe!");
if (mask & GENERIC_ALL) DebugOut("I can everything!");
}
} else {
DWORD lErrorCode = GetLastError(); // Check if one of the buffers was
too small.
if (lErrorCode == ERROR_INSUFFICIENT_BUFFER){
}
}

From: Alexander Grigoriev on
This function may not map specific access rights to generic. Check specific
rights mask, such as FILE_READ_DATA, etc.

<falco(a)fenz.net> wrote in message
news:1159709758.931222.151860(a)k70g2000cwa.googlegroups.com...
> Hi all!
>
> Hoping that someone might be able to give me a hint or two here. I'm
> trying to check that the current user has permission to write to or
> delete a file on disk. Using pretty bare C++, no COM etc. I've looked
> everywhere for an example, but just couldn't find anything. So in the
> end I hacked something together, which seems to work 95% of the time,
> but the remaining 5% eludes me. So, the question is - if I want to find
> out if the current user can write to or delete a file pointed to by a
> string path, how do I go about it? My current code is pasted below, but
> as I say, it's a bit on the faulty side. For anyone looking at the
> code, it's worth paying attention to the code directly after "//Note -
> these below are never hit." - these are what I would have expected to
> provide the info required, but as the comment says, those bits are
> never set. The only one that seemed to be doing what was expected was
> the delete permission flag, which is what I tried to use, but that's
> obviously insufficient.
>
> The specific failure: On one machine (Windows 2000 Professional, Dutch
> language), this code reports that the user doesn't have permission to
> delete a file, when the file is obviously modifiable, and in fact can
> be deleted manually from within Explorer without problems.
>
> What have I messed up? Am I close to the answer, or completely
> misguided? Hints, suggestions etc gladly accepted!
>
>
> //Example:
> //Does the current user have permission to update a given file?
> //Cobbled together from various examples and functions,
> //needs tidy-up.
>
>
> ace_list* m_sAceList = NULL; // list of Access Control Entries
> BOOL bSuccess = TRUE;
> BYTE* pSecDescriptorBuf;
> DWORD dwSizeNeeded = 0;
>
> // Find out size of needed buffer for security descriptor with DACL
> // DACL = Discretionary Access Control List
> bSuccess = GetFileSecurityW((BSTR)sPath,
> DACL_SECURITY_INFORMATION,
> NULL,
> 0,
> &dwSizeNeeded);
>
> if (0 == dwSizeNeeded)
> {
> return failure;
> }
> pSecDescriptorBuf = new BYTE[dwSizeNeeded];
>
> // Retrieve security descriptor with DACL information
> bSuccess = GetFileSecurityW((BSTR)sPath,
> DACL_SECURITY_INFORMATION,
> pSecDescriptorBuf,
> dwSizeNeeded,
> &dwSizeNeeded);
>
> // Check if we successfully retrieved security descriptor with DACL
> information
> if (!bSuccess)
> {
> DWORD dwError = GetLastError();
> return failure;
> }
>
> // Getting DACL from Security Descriptor
> PACL pacl;
> BOOL bDaclPresent, bDaclDefaulted;
> bSuccess =
> GetSecurityDescriptorDacl((SECURITY_DESCRIPTOR*)pSecDescriptorBuf,
> &bDaclPresent, &pacl, &bDaclDefaulted);
>
> // Check if we successfully retrieved DACL
> if (!bSuccess)
> {
> DWORD dwError = GetLastError();
> //cout << "Failed to retrieve DACL from security descriptor (" <<
> dwError << ")\n";
> return failure;
> }
>
> // Check if DACL present in security descriptor
> if (!bDaclPresent)
> {
> //cout << "DACL was not found.\n";
> return failure;
> }
>
> //Check to see if the current user has access.
> wchar_t wszAccName[100] = L"";
> DWORD accNameSize = sizeof(wszAccName);
> PSID ppSid;
> DWORD cbSid = 0;
> DWORD cchDomainName = 0;
> //DWORD dwDomainBufferSize = INITIAL_SIZE;
> wchar_t * wszDomainName = NULL;
> SID_NAME_USE eSidType;
>
>
> //Allocate SID buffer.
> ppSid = (PSID) new BYTE[1024];
> cbSid = 1024;
> wszDomainName = new wchar_t[1024];
> cchDomainName = 1024;
>
>
> if (!GetUserName( wszAccName, &accNameSize ) ){
> //fail
> }
> if (LookupAccountName( 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)
> {
> gMessageBox("Error: Invalid SID for %s.", wszAccName);
> return failure;
> } else {
>
> TRUSTEE trustee;
> BuildTrusteeWithSid(&trustee, ppSid);
>
> ACCESS_MASK mask = 0;
> DWORD dwRetVal = GetEffectiveRightsFromAcl(pacl,
> &trustee,
> &mask);
>
>
> if (!(mask & 65536)){
> Assert(false);
> return failure;
> }
> //Note - these below are never hit. This is the first sign that things
> are going wrong...
> if (mask & GENERIC_READ) DebugOut("I can read!");
> if (mask & GENERIC_WRITE) DebugOut("I can write!");
> if (mask & GENERIC_EXECUTE) DebugOut("I can exe!");
> if (mask & GENERIC_ALL) DebugOut("I can everything!");
> }
> } else {
> DWORD lErrorCode = GetLastError(); // Check if one of the buffers was
> too small.
> if (lErrorCode == ERROR_INSUFFICIENT_BUFFER){
> }
> }
>


From: falco on
Hi Alexander,

Thanks very much for that hint - looking at my notes it should have
been obvious! Oh well - I've changed that and sent a new version to the
guy who was having trouble, hopefully it'll fix it. If not I'll post a
note here!

Thanks,

Mike.


Alexander Grigoriev wrote:
> This function may not map specific access rights to generic. Check specific
> rights mask, such as FILE_READ_DATA, etc.