Solved

how to get whether directory has read/write access

Posted on 2008-10-14
7
795 Views
Last Modified: 2012-05-05
Hi,
I am writing a function which will take a parameter as a path to a folder (remote/local) and if the program has write access to the folder, it wil return true else false.
For this i am using
      LPWSTR lpFilePahtW = strFilePath.GetBuffer(0);
      PSECURITY_DESCRIPTOR psd = NULL;
      DWORD dwReturn;
      dwReturn = GetNamedSecurityInfo(lpFilePahtW, SE_FILE_OBJECT,DACL_SECURITY_INFORMATION, NULL, NULL, NULL ,NULL, &psd);
      if(dwReturn == ERROR_SUCCESS)
      {
            LPBOOL lpbDaclPresent;
            PACL pDacl;
            LPBOOL lpbDaclDefaulted;
            if(GetSecurityDescriptorDacl(psd,lpbDaclPresent, &pDacl,lpbDaclDefaulted)
            {
                  if(lpbDaclPresent == TRUE)
                  {
                        if(pDacl != NULL)
                        {
                                                                                          //donno how to process pDacl
                        }
                  }

            }
      }
      else
      {

      }

first of all is this method correct.
If yes, i am not sure how to do i get the pDacl to read the values.
Also do i need to assign values to psd or somewhere else?
I donno how the memory assignment is done?
0
Comment
Question by:LearningCpp
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 2
7 Comments
 
LVL 6

Expert Comment

by:ChristianWimmer
ID: 22716105
Use the AccessCheck function to check what access is possible to a resource:
http://www.experts-exchange.com/Programming/Languages/CPP/Q_10236213.html?sfQueryTermInfo=1+accesscheck

BTW: Remote files are access checked by the remote client only. Checking access using the local AccessCheck may differ from the remote check because the SIDs can be different.
Short: If local AccessCheck grants access to an resource there is no guarantee that you will get really access to the resource.
0
 

Author Comment

by:LearningCpp
ID: 22716384
I dont understand why do i need to call get the thread and use accesscheck.
If i can get the the ACE with GetAce
cast the LPVoid pAce to ACCESS_ALLOWED_ACE and then read the mask

for(WORD i=0; i < pDacl->AceCount; i++)
{
      LPVOID pAce;
      bSuccess = GetAce(pDacl, i, &pAce);
      ACCESS_ALLOWED_ACE* pAllowed = (ACCESS_ALLOWED_ACE*)pAce;
      DWORD dwmask = pAllowed->Mask;
}

Some pointer in this direction?
0
 

Author Comment

by:LearningCpp
ID: 22717009
I tried the accesscheck method but i get access denied after OpenThreadToken?
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 6

Expert Comment

by:ChristianWimmer
ID: 22718992
AccessCheck is the standard method to check for access to resources. You could do it yourself but it is a little bit complicated because of ACL structure.

You need to retrieve the token of the user who runs your program. A token is always assigned to a process but is optional for a thread. Try OpenProcessToken instead. If this also fails with 5, an already assigned thread token prevents access to your own token (strange!!) you should try RevertToSelf (removes thread tokenn) and try again.
I know that AccessCheck looks complicated but the previous link contains everything you need. I should mention that the generic mask mapping is intended for translating GENERIC_ALL and co to specific access masks like FILE_ALL_ACCESS. You should map the generic rights to their corresponding specific file/folder rights.
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 22719485
I tried the same a few years before and after spending some hours on trying to understand these weird functions (security by obscurity), I ended with code like

   time_t tt = time(NULL);
   std::ostringstream oss;
   oss << folderToTestForWrite << "\\test" << tt << std::endl;
   std::ofstream ofs(oss.str().c_str());
   bool writeAccess = false;
   if (ofs)
   {
       ofs.close();
       writeAccess = true;
       remove(oss.str().c_str());
   }
0
 
LVL 6

Accepted Solution

by:
ChristianWimmer earned 500 total points
ID: 22752598
I've created this code to show how AccessCheck works for files without removing an existing threadtoken (if USE_IMPERSONATESELF is not set).
#include "windows.h"
 
//#define USE_IMPERSONATESELF
 
GENERIC_MAPPING GenericFileMapping = {
    FILE_GENERIC_READ,
    FILE_GENERIC_WRITE,
    FILE_GENERIC_EXECUTE,
    FILE_ALL_ACCESS
};
 
bool CheckAccessToFile(DWORD DesiredAccess, 
					   LPTSTR FileName,
					   bool OpenAsSelf = true)
{
  DWORD LengthNeeded;
  PSECURITY_DESCRIPTOR SecurityDescriptor;
  HANDLE TempToken, 
	     Token;
  DWORD AccessMask;
  PRIVILEGE_SET PrivilegeSet;
  DWORD PrivilegeSetLength,
        GrantedAccess;
  BOOL  AccessStatus;
 
  ::SetLastError(0);
 
  //get size of security descriptor
  //AccessCheck needs owner and group!
  if (!::GetFileSecurity(FileName, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, NULL, 0,
    &LengthNeeded) && (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
    return false;
 
  SecurityDescriptor = (PSECURITY_DESCRIPTOR) ::LocalAlloc(LPTR, LengthNeeded);
 
  __try //try statement http://msdn.microsoft.com/en-us/library/s58ftw19(VS.80).aspx
  {
    if (!::GetFileSecurity(FileName, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
      SecurityDescriptor, LengthNeeded, &LengthNeeded))
	{
        return false;
	}
 
#ifdef USE_IMPERSONATESELF
	// Some examples use this way to impersonate the thread token
	// In this way we can just use OpenThreadToken without a second
	// call to OpenProcessToken if the thread does not have a token.
	// However the one who calls this function may lose his own thread token!
	if (!::ImpersonateSelf(SecurityImpersonation))
		return false;
 
	__try
	{
#endif //USE_IMPERSONATESELF
 
		//first try token assigned to the current thread
		if (!::OpenThreadToken(GetCurrentThread(), TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_DUPLICATE, 
			  OpenAsSelf, &Token)) 
		{
		  //otherwise use process token
		  if ((::GetLastError() == ERROR_NO_TOKEN) &&
			 (!::OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_DUPLICATE, 
				 &Token))) 
			 return false;
 
		  TempToken = INVALID_HANDLE_VALUE;
		  __try {
			//convert to thread token.
			if (!::DuplicateToken(Token, SecurityImpersonation, &TempToken))
			  return false;
		  }
		  __finally  {
			//close process token and switch them for further processing
			::CloseHandle(Token);
		  }
 
		  Token = TempToken;
		}
 
		AccessMask = DesiredAccess;
		::MapGenericMask(&AccessMask, &GenericFileMapping);
		PrivilegeSetLength = sizeof(PrivilegeSet);
 
		
		__try {
		  if (::AccessCheck(SecurityDescriptor, Token, AccessMask,
				&GenericFileMapping, &PrivilegeSet, &PrivilegeSetLength, &GrantedAccess,
				&AccessStatus))
			return (AccessStatus != FALSE);
		  //if AccessStatus is FALSE AccessCheck sets last error to 5 (Access Denied)
		  else
		  {
			  return false;
		  }
		}
		__finally  {
		  ::CloseHandle(Token);
		}
#ifdef USE_IMPERSONATESELF
	}
	__finally {
		::RevertToSelf();
	}
#endif //USE_IMPERSONATESELF
 
	
  }
  __finally
  {
	  ::LocalFree((HLOCAL)SecurityDescriptor);
  }
}
 
int _tmain(int argc, _TCHAR* argv[])
{
 
	if (!CheckAccessToFile(GENERIC_READ, _T("C:\\Windows\\")))
	{
		if (::GetLastError() != 0) //BUG: 1 == TRUE == invalid function
			return ::GetLastError(); //returns 5 (Access denied) if CheckAccessToFile returns false
		else
			return FALSE;
	}
	else
		return TRUE;
}

Open in new window

0
 
LVL 6

Expert Comment

by:ChristianWimmer
ID: 22887331
Could you please point out why you didn't give an A grade? In this way I could improve my answers.
0

Featured Post

Want Experts Exchange at your fingertips?

With Experts Exchange’s latest app release, you can now experience our most recent features, updates, and the same community interface while on-the-go. Download our latest app release at the Android or Apple stores today!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Article by: SunnyDark
This article's goal is to present you with an easy to use XML wrapper for C++ and also present some interesting techniques that you might use with MS C++. The reason I built this class is to ease the pain of using XML files with C++, since there is…
This article shows you how to optimize memory allocations in C++ using placement new. Applicable especially to usecases dealing with creation of large number of objects. A brief on problem: Lets take example problem for simplicity: - I have a G…
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.

623 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question