Solved

how to get whether directory has read/write access

Posted on 2008-10-14
7
746 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
  • 4
  • 2
7 Comments
 
LVL 6

Expert Comment

by:ChristianWimmer
Comment Utility
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
Comment Utility
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
Comment Utility
I tried the accesscheck method but i get access denied after OpenThreadToken?
0
Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

 
LVL 6

Expert Comment

by:ChristianWimmer
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
Could you please point out why you didn't give an A grade? In this way I could improve my answers.
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Templates For Beginners Or How To Encourage The Compiler To Work For You Introduction This tutorial is targeted at the reader who is, perhaps, familiar with the basics of C++ but would prefer a little slower introduction to the more ad…
  Included as part of the C++ Standard Template Library (STL) is a collection of generic containers. Each of these containers serves a different purpose and has different pros and cons. It is often difficult to decide which container to use and …
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…

762 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

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now