コード例 #1
0
ファイル: ncbi_os_mswin.cpp プロジェクト: DmitrySigaev/ncbi
static PSECURITY_DESCRIPTOR s_GetFileSecurityDescriptor(const string& path)
{
    if ( path.empty() ) {
        CNcbiError::Set(CNcbiError::eInvalidArgument);
        return NULL;
    }
    PSECURITY_DESCRIPTOR sd = NULL;
    DWORD size              = 0;
    DWORD size_need         = 0;

    if ( !GetFileSecurity(_T_XCSTRING(path), FILE_SECURITY_INFO, sd, size, &size_need) ) {
        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
            CNcbiError::SetFromWindowsError();
            return NULL;
        }
        // Allocate memory for the buffer
        sd = (PSECURITY_DESCRIPTOR) LocalAlloc(LMEM_FIXED, size_need);
        if ( !sd ) {
            CNcbiError::SetFromWindowsError();
            return NULL;
        }
        size = size_need;
        if ( !GetFileSecurity(_T_XCSTRING(path), FILE_SECURITY_INFO,
                              sd, size, &size_need) ) {
            CNcbiError::SetFromWindowsError();
            LocalFree((HLOCAL) sd);
            return NULL;
        }
    }
    return sd;
}
コード例 #2
0
ファイル: wincache_fcache.c プロジェクト: juokaz/wincache
/* Private methods */
static int read_file_security(fcache_context * pfcache, const char * filename, unsigned char ** ppsec)
{
    int                  result      = NONFATAL;
    SECURITY_INFORMATION sec_info    = 0;
    unsigned int         desc_length = 0;
    unsigned char *      psec_desc   = NULL;

    dprintverbose("start read_file_security");

    _ASSERT(pfcache  != NULL);
    _ASSERT(filename != NULL);
    _ASSERT(ppsec    != NULL);

    *ppsec = NULL;

    sec_info |= OWNER_SECURITY_INFORMATION;
    sec_info |= GROUP_SECURITY_INFORMATION;
    sec_info |= DACL_SECURITY_INFORMATION;

    /* Get size of security buffer. Call is expected to fail */
    if(GetFileSecurity(filename, sec_info, NULL, 0, &desc_length))
    {
        goto Finished;
    }

    psec_desc = (unsigned char *)alloc_smalloc(pfcache->palloc, desc_length);
    if(psec_desc == NULL)
    {
        result = FATAL_OUT_OF_SMEMORY;
        goto Finished;
    }

    if(!GetFileSecurity(filename, sec_info, (PSECURITY_DESCRIPTOR)psec_desc, desc_length, &desc_length))
    {
        goto Finished;
    }

    *ppsec = psec_desc;
    _ASSERT(SUCCEEDED(result));

Finished:

    if(FAILED(result))
    {
        dprintimportant("failure %d in read_file_security", result);
        _ASSERT(result > WARNING_COMMON_BASE);

        if(psec_desc != NULL)
        {
            alloc_sfree(pfcache->palloc, psec_desc);
            psec_desc = NULL;
        }
    }

    dprintverbose("end read_file_security");

    return result;
}
コード例 #3
0
ファイル: access.cpp プロジェクト: KagamiChan/Aegisub
/*
This function is still a proof of concept, it's probably rife with bugs, below
is a short (and incomplete) todo
 * "Basic" checks (Read/Write/File/Dir) checks for FAT32 filesystems which
   requires detecting the filesystem being used.
*/
void Check(fs::path const& file, acs::Type type) {
	DWORD file_attr = GetFileAttributes(file.c_str());
	if ((file_attr & INVALID_FILE_ATTRIBUTES) == INVALID_FILE_ATTRIBUTES) {
		switch (GetLastError()) {
			case ERROR_FILE_NOT_FOUND:
			case ERROR_PATH_NOT_FOUND:
				throw fs::FileNotFound(file);
			case ERROR_ACCESS_DENIED:
				throw fs::ReadDenied(file);
			default:
				throw fs::FileSystemUnknownError(str(boost::format("Unexpected error when getting attributes for \"%s\": %s") % file % util::ErrorString(GetLastError())));
		}
	}

	switch (type) {
		case FileRead:
		case FileWrite:
			if ((file_attr & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)
				throw fs::NotAFile(file);
			break;
		case DirRead:
		case DirWrite:
			if ((file_attr & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY)
				throw fs::NotADirectory(file);
			break;
	}

	SECURITY_INFORMATION info = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
	DWORD len = 0;
	GetFileSecurity(file.c_str(), info, nullptr, 0, &len);
	if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
		LOG_W("acs/check") << "GetFileSecurity: fatal: " << util::ErrorString(GetLastError());

	std::vector<uint8_t> sd_buff(len);
	SECURITY_DESCRIPTOR *sd = (SECURITY_DESCRIPTOR *)&sd_buff[0];

	if (!GetFileSecurity(file.c_str(), info, sd, len, &len))
		LOG_W("acs/check") << "GetFileSecurity failed: " << util::ErrorString(GetLastError());

	ImpersonateSelf(SecurityImpersonation);
	HANDLE client_token;
	if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &client_token))
		LOG_W("acs/check") << "OpenThreadToken failed: " << util::ErrorString(GetLastError());

	if (!check_permission(true, sd, client_token))
		throw fs::ReadDenied(file);
	if ((type == DirWrite || type == FileWrite) && !check_permission(false, sd, client_token))
		throw fs::WriteDenied(file);
}
コード例 #4
0
bool GetFileOwner(const string& Computer,const string& Name, string &strOwner)
{
	bool Result=false;

	strOwner.clear();
	SECURITY_INFORMATION si=OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION;;
	DWORD LengthNeeded=0;
	NTPath strName(Name);
	static char sddata[64 * 1024];
	PSECURITY_DESCRIPTOR sd = reinterpret_cast<PSECURITY_DESCRIPTOR>(sddata);

	if (GetFileSecurity(strName.data(),si,sd,sizeof(sddata),&LengthNeeded) && LengthNeeded<=sizeof(sddata))
	{
		PSID pOwner;
		BOOL OwnerDefaulted;
		if (GetSecurityDescriptorOwner(sd,&pOwner,&OwnerDefaulted))
		{
			if (IsValidSid(pOwner))
			{
				Result = SidToNameCached(pOwner, strOwner, Computer);
			}
		}
	}
	return Result;
}
コード例 #5
0
static int
iwin32_file_get_group (const char *file, group_id_t *gid)
{
  char file_sd_buf [256];
  DWORD sd_size = 256;
  PSECURITY_DESCRIPTOR file_sd = (PSECURITY_DESCRIPTOR) &file_sd_buf;
  PSID sid;
  BOOL dummy;

  assert (file != NULL);
  assert (gid  != NULL);

  if (!InitializeSecurityDescriptor (file_sd, SECURITY_DESCRIPTOR_REVISION))
    return 0;
  if (!GetFileSecurity (file, (SECURITY_INFORMATION)(GROUP_SECURITY_INFORMATION),
    file_sd, sizeof (file_sd_buf), &sd_size)) return 0;
  if (!GetSecurityDescriptorGroup (file_sd, &sid, &dummy)) return 0;
  if (!IsValidSid (sid)) return 0;

  gid->value = malloc (sd_size);
  if (!gid->value) return 0;
  if (!CopySid (sd_size, gid->value, sid)) return 0;

  return 1;
}
コード例 #6
0
int GetFileOwner (const char *Computer, const char *Name, char *Owner)
{
    SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION;
    SECURITY_DESCRIPTOR *sd;
    char sddata[500];
    *Owner=0;
    sd=(SECURITY_DESCRIPTOR *)sddata;

    char AnsiName[NM];
    OemToChar(Name,AnsiName);
    SetFileApisToANSI();
    DWORD Needed;
    int GetCode=GetFileSecurity(AnsiName,si,sd,sizeof(sddata),&Needed);
    SetFileApisToOEM();

    if (!GetCode || (Needed>sizeof(sddata)))
        return(FALSE);
    PSID pOwner;
    BOOL OwnerDefaulted;
    if (!GetSecurityDescriptorOwner(sd,&pOwner,&OwnerDefaulted))
        return(FALSE);
    char AccountName[200],DomainName[200];
    DWORD AccountLength=sizeof(AccountName),DomainLength=sizeof(DomainName);
    SID_NAME_USE snu;
    if (!LookupAccountSid(Computer,pOwner,AccountName,&AccountLength,DomainName,&DomainLength,&snu))
        return(FALSE);
    CharToOem(AccountName,Owner);
    return(TRUE);
}
コード例 #7
0
int main(int argc,char* argv[])
{
    SECURITY_INFORMATION secInfo = DACL_SECURITY_INFORMATION;
    // 和文件相关的安全描述符 SD 的变量
    PSECURITY_DESCRIPTOR pFileSD  = NULL;     // 结构变量
    DWORD          cbFileSD       = 0;        // SD的size
    char lpszFileName[MAX_PATH];
    strncpy(lpszFileName,argv[1],MAX_PATH);
    BOOL fAPISuccess=0;
    fAPISuccess = GetFileSecurity(lpszFileName,secInfo, pFileSD, 0, &cbFileSD);
    return 0;
}
コード例 #8
0
ファイル: fileowner.cpp プロジェクト: CyberShadow/FAR
bool GetFileOwner(const wchar_t *Computer,const wchar_t *Name, string &strOwner)
{
	bool Result=false;
	/*
	if(!Owner)
	{
		SIDCacheFlush();
		return TRUE;
	}
	*/
	strOwner.Clear();
	SECURITY_INFORMATION si=OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION;;
	DWORD LengthNeeded=0;
	NTPath strName(Name);
	PSECURITY_DESCRIPTOR sd=reinterpret_cast<PSECURITY_DESCRIPTOR>(sddata);

	if (GetFileSecurity(strName,si,sd,sizeof(sddata),&LengthNeeded) && LengthNeeded<=sizeof(sddata))
	{
		PSID pOwner;
		BOOL OwnerDefaulted;
		if (GetSecurityDescriptorOwner(sd,&pOwner,&OwnerDefaulted))
		{
			if (IsValidSid(pOwner))
			{
				const wchar_t *Owner=GetNameFromSIDCache(pOwner);
				if (!Owner)
				{
					Owner=AddSIDToCache(Computer,pOwner);
				}
				if (Owner)
				{
					strOwner=Owner;
					Result=true;
				}
			}
		}
	}
	return Result;
}
コード例 #9
0
ファイル: perm.WINDOWS.cpp プロジェクト: AmesianX/htcondor
//
// get_permissions:  1 = yes, 0 = no, -1 = unknown/error
//
int perm::get_permissions( const char *file_name, ACCESS_MASK &AccessRights ) {
	DWORD retVal;
	PACL pacl;
	
	PSECURITY_DESCRIPTOR pSD;
	DWORD pSD_length = 0;
	DWORD pSD_length_needed = 0;
	BOOL acl_present = FALSE;
	BOOL acl_defaulted = FALSE;
	
	// Do the call first to find out how much space is needed.
	
	pSD = NULL;
	
	GetFileSecurity(
		file_name,					// address of string for file name
		DACL_SECURITY_INFORMATION,	// requested information
		pSD,						// address of security descriptor
		pSD_length, 				// size of security descriptor buffer
		&pSD_length_needed			// address of required size of buffer
		);
	
	if( pSD_length_needed <= 0 ) {					// Find out how much space is needed, if <=0 then error
		if ( (GetLastError() == ERROR_FILE_NOT_FOUND) || 
			(GetLastError() == ERROR_PATH_NOT_FOUND) ) {
			
			// Here we have the tricky part of walking up the directory path
			// Typically it works like this:  If the filename exists, great, we'll
			//	 get the permissions on that.  If the filename does not exist, then
			//	 we pop the filename part off the file_name and look at the
			//	 directory.  If that directory should be (for some odd reason) non-
			//	 existant, then we just pop that off, until either we find something
			//	 thats will give us a permissions bitmask, or we run out of places
			//	 to look (which shouldn't happen since c:\ should always give us
			//	 SOMETHING...
			int i = strlen( file_name ) - 1;
			while ( i >= 0 && ( file_name[i] != '\\' && file_name[i] != '/' ) ) {
				i--;
			}
			if ( i < 0 ) {	// We've nowhere else to look, and this is bad.
				return -1;	// Its not a no, its an unknown
			}
			char *new_file_name = new char[i+1];
			strncpy(new_file_name, file_name, i);
			new_file_name[i]= '\0';
			
			// Now that we've chopped off more of the filename, call get_permissions
			// again...
			retVal = get_permissions( new_file_name, AccessRights );
			delete[] new_file_name;
			
			// ... and return what it returns. (after deleting the string that was
			// allocated.
			
			return retVal;
		}
		dprintf(D_ALWAYS, "perm::GetFileSecurity failed (err=%d)\n", GetLastError());
		return -1;
	}
	
	pSD_length = pSD_length_needed + 2; 	// Add 2 for safety.
	pSD_length_needed = 0;
	pSD = new BYTE[pSD_length];
	
	// Okay, now that we've found something, and know how large of an SD we need,
	// call the thing for real and lets get ON WITH IT ALREADY...
	
	if( !GetFileSecurity(
		file_name,					// address of string for file name
		DACL_SECURITY_INFORMATION,	// requested information
		pSD,						// address of security descriptor
		pSD_length, 				// size of security descriptor buffer
		&pSD_length_needed			// address of required size of buffer
		) ) {
		dprintf(D_ALWAYS, "perm::GetFileSecurity(%s) failed (err=%d)\n", file_name, GetLastError());
		delete[] pSD;
		return -1;
	}
	
	// Now, get the ACL from the security descriptor
	if( !GetSecurityDescriptorDacl(
		pSD,							// address of security descriptor
		&acl_present,					// address of flag for presence of disc. ACL
		&pacl,							// address of pointer to ACL
		&acl_defaulted					// address of flag for default disc. ACL
		) ) {
		dprintf(D_ALWAYS, "perm::GetSecurityDescriptorDacl failed (file=%s err=%d)\n", file_name, GetLastError());
		delete[] pSD;
		return -1;
	}
	
	// This is the workaround for the broken API GetEffectiveRightsFromAcl().
	// It should be guaranteed to work on all versions of NT and 2000 but be aware
	// that nested global group permissions are not supported.
	// C. Stolley - June 2001

	ACL_SIZE_INFORMATION acl_info;
		// Structure contains the following members:
		//  DWORD   AceCount; 
		//  DWORD   AclBytesInUse; 
		//  DWORD   AclBytesFree; 



	// first get the number of ACEs in the ACL
		if (! GetAclInformation( pacl,		// acl to get info from
								&acl_info,	// buffer to receive info
								sizeof(acl_info),  // size in bytes of buffer
								AclSizeInformation // class of info to retrieve
								) ) {
			dprintf(D_ALWAYS, "Perm::GetAclInformation failed with error %d\n", GetLastError() );
			return -1;
		}

		ACCESS_MASK allow = 0x0;
		ACCESS_MASK deny = 0x0;

		unsigned int aceCount = acl_info.AceCount;
		
		int result;
		
		// now look at each ACE in the ACL and see if it contains the user we're looking for
		for (unsigned int i=0; i < aceCount; i++) {
			LPVOID current_ace;

			if (! GetAce(	pacl,	// pointer to ACL 
							i,		// index of ACE we want
							&current_ace	// pointer to ACE
							) ) {
				dprintf(D_ALWAYS, "Perm::GetAce() failed! Error code %d\n", GetLastError() );
				return -1;
			}

			dprintf(D_FULLDEBUG, "Calling Perm::userInAce() for %s\\%s\n",
				   (Domain_name) ? Domain_name : "NULL",
				   (Account_name) ? Account_name : "NULL" );
			result = userInAce ( current_ace, Account_name, Domain_name );		
			
			if (result == 1) {
				switch ( ( (PACE_HEADER) current_ace)->AceType ) {				
				case ACCESS_ALLOWED_ACE_TYPE:
				case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
					allow |= ( (ACCESS_ALLOWED_ACE*) current_ace)->Mask;
					break;
				case ACCESS_DENIED_ACE_TYPE:
				case ACCESS_DENIED_OBJECT_ACE_TYPE:
					deny |= ( (ACCESS_DENIED_ACE*) current_ace)->Mask;
					break;
				}
			}
		}
		
		AccessRights = allow;
		AccessRights &= ~deny;

	// and now if we've made this far everything's happy so return true
	return 1;
}
コード例 #10
0
ファイル: tsrm_win32.c プロジェクト: Distrotech/php-src
TSRM_API int tsrm_win32_access(const char *pathname, int mode)
{
	time_t t;
	HANDLE thread_token = NULL;
	PSID token_sid;
	SECURITY_INFORMATION sec_info = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
	GENERIC_MAPPING gen_map = { FILE_GENERIC_READ, FILE_GENERIC_WRITE, FILE_GENERIC_EXECUTE, FILE_ALL_ACCESS };
	DWORD priv_set_length = sizeof(PRIVILEGE_SET);

	PRIVILEGE_SET privilege_set = {0};
	DWORD sec_desc_length = 0, desired_access = 0, granted_access = 0;
	BYTE * psec_desc = NULL;
	BOOL fAccess = FALSE;

	realpath_cache_bucket * bucket = NULL;
	char * real_path = NULL;

	if (mode == 1 /*X_OK*/) {
		DWORD type;
		return GetBinaryType(pathname, &type) ? 0 : -1;
	} else {
		if(!IS_ABSOLUTE_PATH(pathname, strlen(pathname)+1)) {
			real_path = (char *)malloc(MAX_PATH);
			if(tsrm_realpath(pathname, real_path) == NULL) {
				goto Finished;
			}
			pathname = real_path;
 		}

		if(access(pathname, mode)) {
			free(real_path);
			return errno;
		}

 		/* If only existence check is made, return now */
 		if (mode == 0) {
			free(real_path);
			return 0;
		}

/* Only in NTS when impersonate==1 (aka FastCGI) */

		/*
		 AccessCheck() requires an impersonation token.  We first get a primary
		 token and then create a duplicate impersonation token.  The
		 impersonation token is not actually assigned to the thread, but is
		 used in the call to AccessCheck.  Thus, this function itself never
		 impersonates, but does use the identity of the thread.  If the thread
		 was impersonating already, this function uses that impersonation context.
		*/
		if(!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &thread_token)) {
			if (GetLastError() == ERROR_NO_TOKEN) {
				if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &thread_token)) {
					 TWG(impersonation_token) = NULL;
					 goto Finished;
				 }
			}
		}

		/* token_sid will be freed in tsrmwin32_dtor */
		token_sid = tsrm_win32_get_token_sid(thread_token);
		if (!token_sid) {
			if (TWG(impersonation_token_sid)) {
				free(TWG(impersonation_token_sid));
			}
			TWG(impersonation_token_sid) = NULL;
			goto Finished;
		}

		/* Different identity, we need a new impersontated token as well */
		if (!TWG(impersonation_token_sid) || !EqualSid(token_sid, TWG(impersonation_token_sid))) {
			if (TWG(impersonation_token_sid)) {
				free(TWG(impersonation_token_sid));
			}
			TWG(impersonation_token_sid) = token_sid;

			/* Duplicate the token as impersonated token */
			if (!DuplicateToken(thread_token, SecurityImpersonation, &TWG(impersonation_token))) {
				goto Finished;
			}
		} else {
			/* we already have it, free it then */
			free(token_sid);
		}

		if (CWDG(realpath_cache_size_limit)) {
			t = time(0);
			bucket = realpath_cache_lookup(pathname, (int)strlen(pathname), t);
			if(bucket == NULL && real_path == NULL) {
				/* We used the pathname directly. Call tsrm_realpath */
				/* so that entry is created in realpath cache */
				real_path = (char *)malloc(MAX_PATH);
				if(tsrm_realpath(pathname, real_path) != NULL) {
					pathname = real_path;
					bucket = realpath_cache_lookup(pathname, (int)strlen(pathname), t);
				}
			}
 		}

 		/* Do a full access check because access() will only check read-only attribute */
 		if(mode == 0 || mode > 6) {
			if(bucket != NULL && bucket->is_rvalid) {
				fAccess = bucket->is_readable;
				goto Finished;
			}
 			desired_access = FILE_GENERIC_READ;
 		} else if(mode <= 2) {
			if(bucket != NULL && bucket->is_wvalid) {
				fAccess = bucket->is_writable;
				goto Finished;
			}
			desired_access = FILE_GENERIC_WRITE;
 		} else if(mode <= 4) {
			if(bucket != NULL && bucket->is_rvalid) {
				fAccess = bucket->is_readable;
				goto Finished;
			}
			desired_access = FILE_GENERIC_READ|FILE_FLAG_BACKUP_SEMANTICS;
 		} else { // if(mode <= 6)
			if(bucket != NULL && bucket->is_rvalid && bucket->is_wvalid) {
				fAccess = bucket->is_readable & bucket->is_writable;
				goto Finished;
			}
			desired_access = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
 		}

		if(TWG(impersonation_token) == NULL) {
			goto Finished;
		}

		/* Get size of security buffer. Call is expected to fail */
		if(GetFileSecurity(pathname, sec_info, NULL, 0, &sec_desc_length)) {
			goto Finished;
		}

		psec_desc = (BYTE *)malloc(sec_desc_length);
		if(psec_desc == NULL ||
			 !GetFileSecurity(pathname, sec_info, (PSECURITY_DESCRIPTOR)psec_desc, sec_desc_length, &sec_desc_length)) {
			goto Finished;
		}

		MapGenericMask(&desired_access, &gen_map);

		if(!AccessCheck((PSECURITY_DESCRIPTOR)psec_desc, TWG(impersonation_token), desired_access, &gen_map, &privilege_set, &priv_set_length, &granted_access, &fAccess)) {
			goto Finished_Impersonate;
		}

		/* Keep the result in realpath_cache */
		if(bucket != NULL) {
			if(desired_access == (FILE_GENERIC_READ|FILE_FLAG_BACKUP_SEMANTICS)) {
				bucket->is_rvalid = 1;
				bucket->is_readable = fAccess;
			}
			else if(desired_access == FILE_GENERIC_WRITE) {
				bucket->is_wvalid = 1;
				bucket->is_writable = fAccess;
			} else if (desired_access == (FILE_GENERIC_READ | FILE_GENERIC_WRITE)) {
				bucket->is_rvalid = 1;
				bucket->is_readable = fAccess;
				bucket->is_wvalid = 1;
				bucket->is_writable = fAccess;
			}
		}

Finished_Impersonate:
		if(psec_desc != NULL) {
			free(psec_desc);
			psec_desc = NULL;
		}

Finished:
		if(thread_token != NULL) {
			CloseHandle(thread_token);
		}
		if(real_path != NULL) {
			free(real_path);
			real_path = NULL;
		}

		if(fAccess == FALSE) {
			errno = EACCES;
			return errno;
		} else {
			return 0;
		}
	}
}
コード例 #11
-1
ファイル: Acls.cpp プロジェクト: killvxk/WebbrowserLock
BOOL CAcls::AddAccessRights(LPCTSTR lpszFileName,LPCTSTR lpszAccountName,DWORD dwAccessMask) {

	// 声明SID变量
	SID_NAME_USE   snuType;

	// 声明和LookupAccountName相关的变量(注意,全为0,要在程序中动态分配)
	TCHAR *        szDomain       = NULL;
	DWORD          cbDomain       = 0;
	LPVOID         pUserSID       = NULL;
	DWORD          cbUserSID      = 0;

	// 和文件相关的安全描述符 SD 的变量
	PSECURITY_DESCRIPTOR pFileSD  = NULL;     // 结构变量
	DWORD          cbFileSD       = 0;        // SD的size

	// 一个新的SD的变量,用于构造新的ACL(把已有的ACL和需要新加的ACL整合起来)
	SECURITY_DESCRIPTOR  newSD;

	// 和ACL 相关的变量
	PACL           pACL           = NULL;
	BOOL           fDaclPresent;
	BOOL           fDaclDefaulted;
	ACL_SIZE_INFORMATION AclInfo;

	// 一个新的 ACL 变量
	PACL           pNewACL        = NULL;  //结构指针变量
	DWORD          cbNewACL       = 0;     //ACL的size

	// 一个临时使用的 ACE 变量
	LPVOID         pTempAce       = NULL;
	UINT           CurrentAceIndex = 0;  //ACE在ACL中的位置

	UINT           newAceIndex = 0;  //新添的ACE在ACL中的位置

	//API函数的返回值,假设所有的函数都返回失败。
	BOOL           fResult;
	BOOL           fAPISuccess;

	SECURITY_INFORMATION secInfo = DACL_SECURITY_INFORMATION;

	// 下面的两个函数是新的API函数,仅在Windows 2000以上版本的操作系统支持。 
	// 在此将从Advapi32.dll文件中动态载入。如果你使用VC++ 6.0编译程序,而且你想
	// 使用这两个函数的静态链接。则请为你的编译加上:/D_WIN32_WINNT=0x0500
	// 的编译参数。并且确保你的SDK的头文件和lib文件是最新的。
	SetSecurityDescriptorControlFnPtr _SetSecurityDescriptorControl = NULL;
	AddAccessAllowedAceExFnPtr _AddAccessAllowedAceEx = NULL; 

	__try {

		// 
		// STEP 1: 通过用户名取得SID
		//     在这一步中LookupAccountName函数被调用了两次,第一次是取出所需要
		// 的内存的大小,然后,进行内存分配。第二次调用才是取得了用户的帐户信息。
		// LookupAccountName同样可以取得域用户或是用户组的信息。(请参看MSDN)
		//

		fAPISuccess = LookupAccountName(NULL, lpszAccountName,
			pUserSID, &cbUserSID, szDomain, &cbDomain, &snuType);

		// 以上调用API会失败,失败原因是内存不足。并把所需要的内存大小传出。
		// 下面是处理非内存不足的错误。

		if (fAPISuccess)
			__leave;
		else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
			//          _tprintf(TEXT("LookupAccountName() failed. Error %d\n"), 
			//                GetLastError());
			__leave;
		}

		pUserSID = myheapalloc(cbUserSID);
		if (!pUserSID) {
			//         _tprintf(TEXT("HeapAlloc() failed. Error %d\n"), GetLastError());
			__leave;
		}

		szDomain = (TCHAR *) myheapalloc(cbDomain * sizeof(TCHAR));
		if (!szDomain) {
			//        _tprintf(TEXT("HeapAlloc() failed. Error %d\n"), GetLastError());
			__leave;
		}

		fAPISuccess = LookupAccountName(NULL, lpszAccountName,
			pUserSID, &cbUserSID, szDomain, &cbDomain, &snuType);
		if (!fAPISuccess) {
			//       _tprintf(TEXT("LookupAccountName() failed. Error %d\n"), 
			//       GetLastError());
			__leave;
		}

		// 
		// STEP 2: 取得文件(目录)相关的安全描述符SD
		//     使用GetFileSecurity函数取得一份文件SD的拷贝,同样,这个函数也
		// 是被调用两次,第一次同样是取SD的内存长度。注意,SD有两种格式:自相关的
		// (self-relative)和 完全的(absolute),GetFileSecurity只能取到“自
		// 相关的”,而SetFileSecurity则需要完全的。这就是为什么需要一个新的SD,
		// 而不是直接在GetFileSecurity返回的SD上进行修改。因为“自相关的”信息
		// 是不完整的。

		fAPISuccess = GetFileSecurity(lpszFileName, 
			secInfo, pFileSD, 0, &cbFileSD);

		// 以上调用API会失败,失败原因是内存不足。并把所需要的内存大小传出。
		// 下面是处理非内存不足的错误。
		if (fAPISuccess)
			__leave;
		else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
			//       _tprintf(TEXT("GetFileSecurity() failed. Error %d\n"), 
			//        GetLastError());
			__leave;
		}

		pFileSD = myheapalloc(cbFileSD);
		if (!pFileSD) {
			//        _tprintf(TEXT("HeapAlloc() failed. Error %d\n"), GetLastError());
			__leave;
		}

		fAPISuccess = GetFileSecurity(lpszFileName, 
			secInfo, pFileSD, cbFileSD, &cbFileSD);
		if (!fAPISuccess) {
			//     _tprintf(TEXT("GetFileSecurity() failed. Error %d\n"), 
			//          GetLastError());
			__leave;
		}

		// 
		// STEP 3: 初始化一个新的SD
		// 
		if (!InitializeSecurityDescriptor(&newSD, 
			SECURITY_DESCRIPTOR_REVISION)) {
				//    _tprintf(TEXT("InitializeSecurityDescriptor() failed.")
				//     TEXT("Error %d\n"), GetLastError());
				__leave;
		}

		// 
		// STEP 4: 从GetFileSecurity 返回的SD中取DACL
		// 
		if (!GetSecurityDescriptorDacl(pFileSD, &fDaclPresent, &pACL,
			&fDaclDefaulted)) {
				//  _tprintf(TEXT("GetSecurityDescriptorDacl() failed. Error %d\n"),
				//        GetLastError());
				__leave;
		}

		// 
		// STEP 5: 取 DACL的内存size
		//     GetAclInformation可以提供DACL的内存大小。只传入一个类型为
		// ACL_SIZE_INFORMATION的structure的参数,需DACL的信息,是为了
		// 方便我们遍历其中的ACE。
		AclInfo.AceCount = 0; // Assume NULL DACL.
		AclInfo.AclBytesFree = 0;
		AclInfo.AclBytesInUse = sizeof(ACL);

		if (pACL == NULL)
			fDaclPresent = FALSE;

		// 如果DACL不为空,则取其信息。(大多数情况下“自关联”的DACL为空)
		if (fDaclPresent) {            
			if (!GetAclInformation(pACL, &AclInfo, 
				sizeof(ACL_SIZE_INFORMATION), AclSizeInformation)) {
					//  _tprintf(TEXT("GetAclInformation() failed. Error %d\n"),
					//        GetLastError());
					__leave;
			}
		}

		// 
		// STEP 6: 计算新的ACL的size
		//    计算的公式是:原有的DACL的size加上需要添加的一个ACE的size,以
		// 及加上一个和ACE相关的SID的size,最后减去两个字节以获得精确的大小。
		cbNewACL = AclInfo.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE) 
			+ GetLengthSid(pUserSID) - sizeof(DWORD);


		// 
		// STEP 7: 为新的ACL分配内存
		// 
		pNewACL = (PACL) myheapalloc(cbNewACL);
		if (!pNewACL) {
			// _tprintf(TEXT("HeapAlloc() failed. Error %d\n"), GetLastError());
			//  __leave;
		}

		// 
		// STEP 8: 初始化新的ACL结构
		// 
		if (!InitializeAcl(pNewACL, cbNewACL, ACL_REVISION2)) {
			// _tprintf(TEXT("InitializeAcl() failed. Error %d\n"), 
			//       GetLastError());
			__leave;
		}

		// 
		// STEP 9  如果文件(目录) DACL 有数据,拷贝其中的ACE到新的DACL中
		// 
		//     下面的代码假设首先检查指定文件(目录)是否存在的DACL,如果有的话,
		// 那么就拷贝所有的ACE到新的DACL结构中,我们可以看到其遍历的方法是采用
		// ACL_SIZE_INFORMATION结构中的AceCount成员来完成的。在这个循环中,
		// 会按照默认的ACE的顺序来进行拷贝(ACE在ACL中的顺序是很关键的),在拷
		// 贝过程中,先拷贝非继承的ACE(我们知道ACE会从上层目录中继承下来)
		// 

		newAceIndex = 0;

		if (fDaclPresent && AclInfo.AceCount) {

			for (CurrentAceIndex = 0; 
				CurrentAceIndex < AclInfo.AceCount;
				CurrentAceIndex++) {

					// 
					// STEP 10: 从DACL中取ACE
					// 
					if (!GetAce(pACL, CurrentAceIndex, &pTempAce)) {
						// _tprintf(TEXT("GetAce() failed. Error %d\n"), 
						//       GetLastError());
						__leave;
					}

					// 
					// STEP 11: 检查是否是非继承的ACE
					//     如果当前的ACE是一个从父目录继承来的ACE,那么就退出循环。
					// 因为,继承的ACE总是在非继承的ACE之后,而我们所要添加的ACE
					// 应该在已有的非继承的ACE之后,所有的继承的ACE之前。退出循环
					// 正是为了要添加一个新的ACE到新的DACL中,这后,我们再把继承的
					// ACE拷贝到新的DACL中。
					//
					if (((ACCESS_ALLOWED_ACE *)pTempAce)->Header.AceFlags
						& INHERITED_ACE)
						break;

					// 
					// STEP 12: 检查要拷贝的ACE的SID是否和需要加入的ACE的SID一样,
					// 如果一样,那么就应该废掉已存在的ACE,也就是说,同一个用户的存取
					// 权限的设置的ACE,在DACL中应该唯一。这在里,跳过对同一用户已设置
					// 了的ACE,仅是拷贝其它用户的ACE。
					// 
					if (EqualSid(pUserSID,
						&(((ACCESS_ALLOWED_ACE *)pTempAce)->SidStart)))
						continue;

					// 
					// STEP 13: 把ACE加入到新的DACL中
					//    下面的代码中,注意 AddAce 函数的第三个参数,这个参数的意思是 
					// ACL中的索引值,意为要把ACE加到某索引位置之后,参数MAXDWORD的
					// 意思是确保当前的ACE是被加入到最后的位置。
					//
					if (!AddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce,
						((PACE_HEADER) pTempAce)->AceSize)) {
							// _tprintf(TEXT("AddAce() failed. Error %d\n"), 
							//      GetLastError());
							__leave;
					}

					newAceIndex++;
			}
		}

		// 
		// STEP 14: 把一个 access-allowed 的ACE 加入到新的DACL中
		//     前面的循环拷贝了所有的非继承且SID为其它用户的ACE,退出循环的第一件事
		// 就是加入我们指定的ACE。请注意首先先动态装载了一个AddAccessAllowedAceEx
		// 的API函数,如果装载不成功,就调用AddAccessAllowedAce函数。前一个函数仅
		// 在Windows 2000以后的版本支持,NT则没有,我们为了使用新版本的函数,我们首
		// 先先检查一下当前系统中可不可以装载这个函数,如果可以则就使用。使用动态链接
		// 比使用静态链接的好处是,程序运行时不会因为没有这个API函数而报错。
		// 
		// Ex版的函数多出了一个参数AceFlag(第三人参数),用这个参数我们可以来设置一
		// 个叫ACE_HEADER的结构,以便让我们所设置的ACE可以被其子目录所继承下去,而 
		// AddAccessAllowedAce函数不能定制这个参数,在AddAccessAllowedAce函数
		// 中,其会把ACE_HEADER这个结构设置成非继承的。
		// 
		_AddAccessAllowedAceEx = (AddAccessAllowedAceExFnPtr)
			GetProcAddress(GetModuleHandle(TEXT("advapi32.dll")),
			"AddAccessAllowedAceEx");

		if (_AddAccessAllowedAceEx) {
			if (!_AddAccessAllowedAceEx(pNewACL, ACL_REVISION2,
				CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE ,
				dwAccessMask, pUserSID)) {
					// _tprintf(TEXT("AddAccessAllowedAceEx() failed. Error %d\n"),
					//       GetLastError());
					__leave;
			}
		}else{
			if (!AddAccessAllowedAce(pNewACL, ACL_REVISION2, 
				dwAccessMask, pUserSID)) {
					//              _tprintf(TEXT("AddAccessAllowedAce() failed. Error %d\n"),
					//                    GetLastError());
					__leave;
			}
		}

		// 
		// STEP 15: 按照已存在的ACE的顺序拷贝从父目录继承而来的ACE
		// 
		if (fDaclPresent && AclInfo.AceCount) {

			for (; 
				CurrentAceIndex < AclInfo.AceCount;
				CurrentAceIndex++) {

					// 
					// STEP 16: 从文件(目录)的DACL中继续取ACE
					// 
					if (!GetAce(pACL, CurrentAceIndex, &pTempAce)) {
						//                _tprintf(TEXT("GetAce() failed. Error %d\n"), 
						//                      GetLastError());
						__leave;
					}

					// 
					// STEP 17: 把ACE加入到新的DACL中
					// 
					if (!AddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce,
						((PACE_HEADER) pTempAce)->AceSize)) {
							//                _tprintf(TEXT("AddAce() failed. Error %d\n"), 
							//                      GetLastError());
							__leave;
					}
			}
		}

		// 
		// STEP 18: 把新的ACL设置到新的SD中
		// 
		if (!SetSecurityDescriptorDacl(&newSD, TRUE, pNewACL, 
			FALSE)) {
				//          _tprintf(TEXT("SetSecurityDescriptorDacl() failed. Error %d\n"),
				//                GetLastError());
				__leave;
		}

		// 
		// STEP 19: 把老的SD中的控制标记再拷贝到新的SD中,我们使用的是一个叫 
		// SetSecurityDescriptorControl() 的API函数,这个函数同样只存在于
		// Windows 2000以后的版本中,所以我们还是要动态地把其从advapi32.dll 
		// 中载入,如果系统不支持这个函数,那就不拷贝老的SD的控制标记了。
		// 
		_SetSecurityDescriptorControl =(SetSecurityDescriptorControlFnPtr)
			GetProcAddress(GetModuleHandle(TEXT("advapi32.dll")),
			"SetSecurityDescriptorControl");
		if (_SetSecurityDescriptorControl) {

			SECURITY_DESCRIPTOR_CONTROL controlBitsOfInterest = 0;
			SECURITY_DESCRIPTOR_CONTROL controlBitsToSet = 0;
			SECURITY_DESCRIPTOR_CONTROL oldControlBits = 0;
			DWORD dwRevision = 0;

			if (!GetSecurityDescriptorControl(pFileSD, &oldControlBits,
				&dwRevision)) {
					//             _tprintf(TEXT("GetSecurityDescriptorControl() failed.")
					//                   TEXT("Error %d\n"), GetLastError());
					__leave;
			}

			if (oldControlBits & SE_DACL_AUTO_INHERITED) {
				controlBitsOfInterest =
					SE_DACL_AUTO_INHERIT_REQ |
					SE_DACL_AUTO_INHERITED ;
				controlBitsToSet = controlBitsOfInterest;
			}
			else if (oldControlBits & SE_DACL_PROTECTED) {
				controlBitsOfInterest = SE_DACL_PROTECTED;
				controlBitsToSet = controlBitsOfInterest;
			}        

			if (controlBitsOfInterest) {
				if (!_SetSecurityDescriptorControl(&newSD,
					controlBitsOfInterest,
					controlBitsToSet)) {
						//                _tprintf(TEXT("SetSecurityDescriptorControl() failed.")
						//                      TEXT("Error %d\n"), GetLastError());
						__leave;
				}
			}
		}

		// 
		// STEP 20: 把新的SD设置设置到文件的安全属性中(千山万水啊,终于到了)
		// 
		if (!SetFileSecurity(lpszFileName, secInfo,
			&newSD)) {
				//          _tprintf(TEXT("SetFileSecurity() failed. Error %d\n"), 
				//                GetLastError());
				__leave;
		}

		fResult = TRUE;

	} __finally {

		// 
		// STEP 21: 释放已分配的内存,以免Memory Leak
		// 
		if (pUserSID)  myheapfree(pUserSID);
		if (szDomain)  myheapfree(szDomain);
		if (pFileSD) myheapfree(pFileSD);
		if (pNewACL) myheapfree(pNewACL);
	}

	return fResult;
}