1390 lines
45 KiB
C
1390 lines
45 KiB
C
/********************************************************************/
|
||
/** Copyright(c) 1989 Microsoft Corporation. **/
|
||
/********************************************************************/
|
||
|
||
//***
|
||
//
|
||
// Filename: dir.c
|
||
//
|
||
// Description: This module contains support routines for the diretory
|
||
// category API's for the AFP server service. These routines
|
||
// are called by the RPC runtime.
|
||
//
|
||
// History:
|
||
// June 11,1992. NarenG Created original version.
|
||
//
|
||
#include <nt.h>
|
||
#include <ntrtl.h>
|
||
#include <ntlsa.h>
|
||
#include <nturtl.h> // needed for winbase.h
|
||
#include "afpsvcp.h"
|
||
|
||
//**
|
||
//
|
||
// Call: AfpDirConvertSidsToNames
|
||
//
|
||
// Returns: NO_ERROR
|
||
// error return codes from LsaOpenPolicy and LsaLookupSids
|
||
//
|
||
// Description: Will convert the directory structure returned by the FSD
|
||
// which contains pointers to owner and groups SIDS to their
|
||
// respective names. The caller is responsible for freeing up
|
||
// the memory allocated to hold the converted dir structure.
|
||
//
|
||
DWORD
|
||
AfpDirConvertSidsToNames(
|
||
IN PAFP_DIRECTORY_INFO pAfpDirInfo,
|
||
OUT PAFP_DIRECTORY_INFO* ppAfpConvertedDirInfo
|
||
)
|
||
{
|
||
LSA_HANDLE hLsa = NULL;
|
||
NTSTATUS ntStatus;
|
||
PLSA_REFERENCED_DOMAIN_LIST pDomainList = NULL;
|
||
PLSA_TRANSLATED_NAME pNames = NULL;
|
||
PSID pSidArray[2];
|
||
SECURITY_QUALITY_OF_SERVICE QOS;
|
||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||
DWORD dwRetCode = NO_ERROR;
|
||
PAFP_DIRECTORY_INFO pOutputBuf = NULL;
|
||
DWORD cbOutputBuf;
|
||
LPBYTE pbVariableData;
|
||
DWORD dwIndex;
|
||
WCHAR * pWchar;
|
||
BOOL fUseUnknownAccount = FALSE;
|
||
DWORD dwUse, dwCount = 0;
|
||
SID AfpBuiltInSid = { 1, 1, SECURITY_NT_AUTHORITY,
|
||
SECURITY_BUILTIN_DOMAIN_RID };
|
||
|
||
// First open the LSA and obtain a handle to it.
|
||
//
|
||
QOS.Length = sizeof( QOS );
|
||
QOS.ImpersonationLevel = SecurityImpersonation;
|
||
QOS.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
|
||
QOS.EffectiveOnly = FALSE;
|
||
|
||
InitializeObjectAttributes( &ObjectAttributes,
|
||
NULL,
|
||
0L,
|
||
NULL,
|
||
NULL );
|
||
|
||
ObjectAttributes.SecurityQualityOfService = &QOS;
|
||
|
||
ntStatus = LsaOpenPolicy( NULL,
|
||
&ObjectAttributes,
|
||
POLICY_LOOKUP_NAMES,
|
||
&hLsa );
|
||
|
||
if ( !NT_SUCCESS( ntStatus ))
|
||
return( RtlNtStatusToDosError( ntStatus ) );
|
||
|
||
// This is not a loop
|
||
//
|
||
do {
|
||
|
||
|
||
// Set up the owner and group sid into the array.
|
||
//
|
||
if ((PSID)(pAfpDirInfo->afpdir_owner) != NULL)
|
||
{
|
||
pSidArray[dwCount++] = (PSID)(pAfpDirInfo->afpdir_owner);
|
||
}
|
||
if ((PSID)(pAfpDirInfo->afpdir_group) != NULL)
|
||
{
|
||
pSidArray[dwCount++] = (PSID)(pAfpDirInfo->afpdir_group);
|
||
}
|
||
|
||
// Try to get the names of the owner and primary group.
|
||
//
|
||
if (dwCount > 0)
|
||
{
|
||
ntStatus = LsaLookupSids( hLsa, dwCount, pSidArray, &pDomainList, &pNames );
|
||
|
||
if ( !NT_SUCCESS( ntStatus ) ) {
|
||
|
||
if ( ntStatus == STATUS_NONE_MAPPED ) {
|
||
|
||
fUseUnknownAccount = TRUE;
|
||
|
||
dwRetCode = NO_ERROR;
|
||
|
||
}
|
||
else {
|
||
|
||
dwRetCode = RtlNtStatusToDosError( ntStatus );
|
||
|
||
AFP_PRINT(( "SFMSVC: AfpDirConvertSidsToNames, LsaLookupSids failed with error (%ld)\n", dwRetCode));
|
||
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
// We need to calculate the length of the buffer we need to allocate.
|
||
//
|
||
for( dwIndex = 0,
|
||
dwRetCode = NO_ERROR,
|
||
cbOutputBuf = sizeof( AFP_DIRECTORY_INFO );
|
||
|
||
dwIndex < dwCount;
|
||
|
||
dwIndex++ ) {
|
||
|
||
if ( fUseUnknownAccount )
|
||
dwUse = SidTypeUnknown;
|
||
else
|
||
dwUse = pNames[dwIndex].Use;
|
||
|
||
switch( dwUse ) {
|
||
|
||
case SidTypeInvalid:
|
||
cbOutputBuf += ((wcslen((LPWSTR)(AfpGlobals.wchInvalid))+1)
|
||
* sizeof(WCHAR));
|
||
break;
|
||
|
||
case SidTypeDeletedAccount:
|
||
cbOutputBuf += ((wcslen((LPWSTR)(AfpGlobals.wchDeleted))+1)
|
||
* sizeof(WCHAR));
|
||
break;
|
||
|
||
case SidTypeUnknown:
|
||
cbOutputBuf += ((wcslen((LPWSTR)(AfpGlobals.wchUnknown))+1)
|
||
* sizeof(WCHAR));
|
||
break;
|
||
|
||
case SidTypeWellKnownGroup:
|
||
cbOutputBuf += (pNames[dwIndex].Name.Length+sizeof(WCHAR));
|
||
break;
|
||
|
||
case SidTypeDomain:
|
||
cbOutputBuf +=
|
||
((pDomainList->Domains[pNames[dwIndex].DomainIndex]).Name.Length + sizeof(WCHAR) );
|
||
break;
|
||
|
||
default:
|
||
if ( ( pNames[dwIndex].DomainIndex != -1 ) &&
|
||
( pNames[dwIndex].Name.Buffer != NULL ) ) {
|
||
|
||
PSID pDomainSid;
|
||
PUNICODE_STRING pDomain;
|
||
|
||
pDomain =
|
||
&((pDomainList->Domains[pNames[dwIndex].DomainIndex]).Name);
|
||
|
||
pDomainSid =
|
||
(pDomainList->Domains[pNames[dwIndex].DomainIndex]).Sid;
|
||
|
||
if ( !RtlEqualSid( &AfpBuiltInSid, pDomainSid ))
|
||
cbOutputBuf += ( pDomain->Length + sizeof( TEXT('\\')));
|
||
|
||
cbOutputBuf += (pNames[dwIndex].Name.Length+sizeof(WCHAR));
|
||
}
|
||
else
|
||
dwRetCode = ERROR_NONE_MAPPED;
|
||
break;
|
||
}
|
||
}
|
||
|
||
pOutputBuf = (PAFP_DIRECTORY_INFO)MIDL_user_allocate( cbOutputBuf );
|
||
|
||
if ( pOutputBuf == NULL ) {
|
||
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
||
AFP_PRINT(( "SFMSVC: AfpDirConvertSidsToNames, MIDL_user_allocate 1 failed with error (%ld)\n", dwRetCode));
|
||
break;
|
||
}
|
||
|
||
ZeroMemory( (LPBYTE)pOutputBuf, cbOutputBuf );
|
||
|
||
// Copy the fixed part of the structure.
|
||
//
|
||
CopyMemory( (LPBYTE)pOutputBuf,
|
||
(LPBYTE)pAfpDirInfo,
|
||
sizeof(AFP_DIRECTORY_INFO) );
|
||
|
||
// Now we need to copy the names
|
||
//
|
||
for( dwIndex = 0,
|
||
pbVariableData = (LPBYTE)((ULONG_PTR)pOutputBuf + cbOutputBuf);
|
||
|
||
dwIndex < dwCount;
|
||
|
||
dwIndex++ ) {
|
||
|
||
if ( fUseUnknownAccount )
|
||
dwUse = SidTypeUnknown;
|
||
else
|
||
dwUse = pNames[dwIndex].Use;
|
||
|
||
switch( dwUse ) {
|
||
|
||
case SidTypeInvalid:
|
||
pbVariableData -= ((wcslen(AfpGlobals.wchInvalid)+1)
|
||
* sizeof(WCHAR));
|
||
wcscpy( (LPWSTR)pbVariableData, AfpGlobals.wchInvalid );
|
||
break;
|
||
|
||
case SidTypeDeletedAccount:
|
||
pbVariableData -= ((wcslen(AfpGlobals.wchDeleted)+1)
|
||
* sizeof(WCHAR));
|
||
wcscpy( (LPWSTR)pbVariableData, AfpGlobals.wchDeleted );
|
||
break;
|
||
|
||
case SidTypeUnknown:
|
||
pbVariableData -= ((wcslen(AfpGlobals.wchUnknown)+1)
|
||
* sizeof(WCHAR));
|
||
wcscpy( (LPWSTR)pbVariableData, AfpGlobals.wchUnknown );
|
||
break;
|
||
|
||
case SidTypeWellKnownGroup:
|
||
pbVariableData -= (pNames[dwIndex].Name.Length+sizeof(WCHAR));
|
||
CopyMemory( pbVariableData,
|
||
pNames[dwIndex].Name.Buffer,
|
||
pNames[dwIndex].Name.Length );
|
||
break;
|
||
|
||
case SidTypeDomain:
|
||
cbOutputBuf +=
|
||
((pDomainList->Domains[pNames[dwIndex].DomainIndex]).Name.Length);
|
||
CopyMemory( pbVariableData,
|
||
((pDomainList->Domains[pNames[dwIndex].DomainIndex]).Name.Buffer),
|
||
((pDomainList->Domains[pNames[dwIndex].DomainIndex]).Name.Length));
|
||
break;
|
||
|
||
default:
|
||
|
||
{
|
||
|
||
PSID pDomainSid;
|
||
|
||
PUNICODE_STRING pDomain;
|
||
|
||
pDomain =
|
||
&((pDomainList->Domains[pNames[dwIndex].DomainIndex]).Name);
|
||
|
||
pDomainSid =
|
||
(pDomainList->Domains[pNames[dwIndex].DomainIndex]).Sid;
|
||
|
||
pbVariableData -= ((pNames[dwIndex].Name.Length+sizeof(WCHAR)));
|
||
|
||
pWchar = (WCHAR*)pbVariableData;
|
||
|
||
// Copy the domain name if it is not BUILTIN
|
||
//
|
||
if ( !RtlEqualSid( &AfpBuiltInSid, pDomainSid ) ) {
|
||
|
||
pbVariableData -= ( pDomain->Length + sizeof( TEXT('\\')));
|
||
|
||
CopyMemory(pbVariableData,pDomain->Buffer,pDomain->Length);
|
||
|
||
wcscat((LPWSTR)pbVariableData, (LPWSTR)TEXT("\\"));
|
||
|
||
pWchar = (WCHAR*)pbVariableData;
|
||
|
||
pWchar += wcslen( (LPWSTR)pbVariableData );
|
||
|
||
}
|
||
|
||
CopyMemory( pWchar,
|
||
pNames[dwIndex].Name.Buffer,
|
||
pNames[dwIndex].Name.Length );
|
||
}
|
||
|
||
}
|
||
|
||
// If this is the first time this loop executes then set the
|
||
// owner.
|
||
//
|
||
if ( (dwIndex == 0) && (pAfpDirInfo->afpdir_owner != NULL) )
|
||
pOutputBuf->afpdir_owner = (LPWSTR)pbVariableData;
|
||
else
|
||
pOutputBuf->afpdir_group = (LPWSTR)pbVariableData;
|
||
}
|
||
|
||
} while( FALSE );
|
||
|
||
if ( pNames != NULL )
|
||
LsaFreeMemory( pNames );
|
||
|
||
if ( pDomainList != NULL )
|
||
LsaFreeMemory( pDomainList );
|
||
|
||
if ( hLsa != NULL )
|
||
LsaClose( hLsa );
|
||
|
||
if ( dwRetCode != NO_ERROR ) {
|
||
|
||
AFP_PRINT(( "SFMSVC: AfpDirConvertSidsToNames, failed, error = (%ld)\n"
|
||
, dwRetCode));
|
||
|
||
if ( pOutputBuf != NULL )
|
||
MIDL_user_free( pOutputBuf );
|
||
}
|
||
else
|
||
{
|
||
*ppAfpConvertedDirInfo = pOutputBuf;
|
||
}
|
||
|
||
return( dwRetCode );
|
||
}
|
||
|
||
//**
|
||
//
|
||
// Call: AfpGetDirInfo
|
||
//
|
||
// Returns: NO_ERROR - success
|
||
// ERROR_NOT_ENOUGH_MEMORY
|
||
// Non-zero returns from NtOpenFile, NtQuerySecurityObject,
|
||
// NtQueryInformationFile.
|
||
//
|
||
// Description: Read the security descriptor for this directory and obtain the
|
||
// SIDs for Owner and Primary group. Finally obtain Owner, Group
|
||
// and World permissions.
|
||
DWORD
|
||
AfpGetDirInfo(
|
||
LPWSTR lpwsDirPath,
|
||
PAFP_DIRECTORY_INFO * lppDirInfo
|
||
)
|
||
{
|
||
NTSTATUS ntStatus;
|
||
DWORD dwSizeNeeded;
|
||
PBYTE pBuffer = NULL;
|
||
PBYTE pAbsBuffer = NULL;
|
||
PISECURITY_DESCRIPTOR pSecDesc;
|
||
PBYTE pAbsSecDesc = NULL; // Used in conversion of
|
||
// sec descriptor to
|
||
// absolute format
|
||
BOOL fSawOwnerAce = FALSE;
|
||
BOOL fSawGroupAce = FALSE;
|
||
BYTE bOwnerRights = 0;
|
||
BYTE bGroupRights = 0;
|
||
BYTE bWorldRights = 0;
|
||
FILE_BASIC_INFORMATION FileBasicInfo;
|
||
IO_STATUS_BLOCK IOStatusBlock;
|
||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||
UNICODE_STRING DirectoryName;
|
||
HANDLE hDirectory;
|
||
PAFP_DIRECTORY_INFO pAfpDir;
|
||
DWORD dwAlignedSizeAfpDirInfo = sizeof (AFP_DIRECTORY_INFO);
|
||
LPWSTR pDirPath;
|
||
SID AfpSidNull = { 1, 1, SECURITY_NULL_SID_AUTHORITY,
|
||
SECURITY_NULL_RID };
|
||
SID AfpSidWorld = { 1, 1, SECURITY_WORLD_SID_AUTHORITY,
|
||
SECURITY_WORLD_RID };
|
||
|
||
pDirPath = (LPWSTR)LocalAlloc( LPTR,
|
||
( STRLEN(lpwsDirPath) +
|
||
STRLEN(TEXT("\\DOSDEVICES\\"))+1)
|
||
* sizeof( WCHAR ) );
|
||
if ( pDirPath == NULL )
|
||
return( ERROR_NOT_ENOUGH_MEMORY );
|
||
|
||
STRCPY( pDirPath, TEXT("\\DOSDEVICES\\") );
|
||
STRCAT( pDirPath, lpwsDirPath );
|
||
|
||
RtlInitUnicodeString( &DirectoryName, pDirPath );
|
||
|
||
InitializeObjectAttributes( &ObjectAttributes,
|
||
&DirectoryName,
|
||
OBJ_CASE_INSENSITIVE,
|
||
NULL,
|
||
NULL );
|
||
|
||
ntStatus = NtOpenFile( &hDirectory,
|
||
GENERIC_READ | READ_CONTROL | SYNCHRONIZE,
|
||
&ObjectAttributes,
|
||
&IOStatusBlock,
|
||
FILE_SHARE_READ |
|
||
FILE_SHARE_WRITE |
|
||
FILE_SHARE_DELETE,
|
||
FILE_DIRECTORY_FILE |
|
||
FILE_SYNCHRONOUS_IO_NONALERT );
|
||
|
||
LocalFree( pDirPath );
|
||
|
||
if ( !NT_SUCCESS( ntStatus ) )
|
||
return( RtlNtStatusToDosError( ntStatus ) );
|
||
|
||
// Read the security descriptor for this directory. First get the owner
|
||
// and group security descriptors. We want to optimize on how much memory
|
||
// we need to read this in. Its a pain to make a call just to get that.
|
||
// So just make a guess. If that turns out to be short then do the exact
|
||
// allocation.
|
||
//
|
||
dwSizeNeeded = 2048;
|
||
|
||
do {
|
||
|
||
if ( pBuffer != NULL )
|
||
MIDL_user_free( pBuffer );
|
||
|
||
if ((pBuffer = MIDL_user_allocate( dwSizeNeeded +
|
||
dwAlignedSizeAfpDirInfo ))==NULL)
|
||
return( ERROR_NOT_ENOUGH_MEMORY );
|
||
|
||
ZeroMemory( pBuffer, dwSizeNeeded + dwAlignedSizeAfpDirInfo );
|
||
|
||
pSecDesc = (PSECURITY_DESCRIPTOR)(pBuffer + dwAlignedSizeAfpDirInfo);
|
||
|
||
ntStatus = NtQuerySecurityObject( hDirectory,
|
||
OWNER_SECURITY_INFORMATION |
|
||
GROUP_SECURITY_INFORMATION |
|
||
DACL_SECURITY_INFORMATION,
|
||
pSecDesc,
|
||
dwSizeNeeded,
|
||
&dwSizeNeeded);
|
||
|
||
} while ((ntStatus != STATUS_SUCCESS) &&
|
||
((ntStatus == STATUS_BUFFER_OVERFLOW) ||
|
||
(ntStatus == STATUS_BUFFER_TOO_SMALL) ||
|
||
(ntStatus == STATUS_MORE_ENTRIES)));
|
||
|
||
if (!NT_SUCCESS(ntStatus)) {
|
||
NtClose( hDirectory );
|
||
MIDL_user_free( pBuffer );
|
||
return( RtlNtStatusToDosError( ntStatus ) );
|
||
}
|
||
|
||
pSecDesc = (PISECURITY_DESCRIPTOR)((PBYTE)pSecDesc);
|
||
|
||
// If the security descriptor is in self-relative form, convert to absolute
|
||
//
|
||
if (pSecDesc->Control & SE_SELF_RELATIVE)
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
DWORD dwAbsoluteSizeNeeded;
|
||
|
||
AFP_PRINT (("AfpGetDirInfo: SE_SELF_RELATIVE security desc\n"));
|
||
|
||
// An absolute SD is not necessarily the same size as a relative
|
||
// SD, so an in-place conversion may not be possible.
|
||
|
||
dwAbsoluteSizeNeeded = dwSizeNeeded;
|
||
Status = RtlSelfRelativeToAbsoluteSD2(pSecDesc, &dwAbsoluteSizeNeeded);
|
||
// Buffer will be small only for 64-bit
|
||
|
||
if (Status == STATUS_BUFFER_TOO_SMALL)
|
||
{
|
||
// Allocate a new buffer in which to store the absolute
|
||
// security descriptor, copy the contents of the relative
|
||
// descriptor in and try again
|
||
|
||
if ((pAbsBuffer = MIDL_user_allocate( dwAbsoluteSizeNeeded +
|
||
dwAlignedSizeAfpDirInfo ))==NULL)
|
||
{
|
||
Status = STATUS_NO_MEMORY;
|
||
AFP_PRINT (("AfpGetDirInfo: MIDL_user_allocate failed for pAbsBuffer\n"));
|
||
}
|
||
else
|
||
{
|
||
|
||
ZeroMemory( pAbsBuffer, dwAbsoluteSizeNeeded + dwAlignedSizeAfpDirInfo );
|
||
|
||
memcpy (pAbsBuffer, pBuffer, sizeof(AFP_DIRECTORY_INFO));
|
||
|
||
pAbsSecDesc = (PSECURITY_DESCRIPTOR)(pAbsBuffer + dwAlignedSizeAfpDirInfo);
|
||
|
||
RtlCopyMemory((VOID *)pAbsSecDesc, (VOID *)pSecDesc, dwSizeNeeded);
|
||
|
||
// All operations hereon will be performed on
|
||
// pAbsBuffer. Free earlier memory
|
||
|
||
MIDL_user_free(pBuffer);
|
||
pBuffer = NULL;
|
||
pBuffer = pAbsBuffer;
|
||
|
||
Status = RtlSelfRelativeToAbsoluteSD2 (pAbsSecDesc,
|
||
&dwAbsoluteSizeNeeded);
|
||
if (NT_SUCCESS(Status))
|
||
{
|
||
// We don't need relative form anymore,
|
||
// we will work with the Absolute form
|
||
pSecDesc = (PISECURITY_DESCRIPTOR)pAbsSecDesc;
|
||
}
|
||
else
|
||
{
|
||
AFP_PRINT (("AfpGetDirInfo: RtlSelfRelativeToAbsoluteSD2 2 failed with error %ld\n", Status));
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
AFP_PRINT (("AfpGetDirInfo: RtlSelfRelativeToAbsoluteSD2 failed with error %ld\n", Status));
|
||
}
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
AFP_PRINT (("AfpGetDirInfo: RtlSelfRelativeToAbsoluteSD2: returned error %lx\n", Status));
|
||
if (pBuffer != NULL)
|
||
{
|
||
MIDL_user_free( pBuffer );
|
||
pBuffer = NULL;
|
||
}
|
||
NtClose( hDirectory );
|
||
return( RtlNtStatusToDosError( ntStatus ));
|
||
}
|
||
}
|
||
|
||
pAfpDir = (PAFP_DIRECTORY_INFO)pBuffer;
|
||
|
||
|
||
// Walk through the ACL list and determine Owner/Group and World
|
||
// permissions. For Owner and Group, if the specific ace's are not
|
||
// present then they inherit the world permissions.
|
||
//
|
||
// A NULL Acl => All rights to everyone. An empty Acl on the other
|
||
// hand => no access for anyone.
|
||
//
|
||
// Should we be checking for creater owner/creater group well-defined
|
||
// sids or the Owner and Group fields in the security descriptor ?
|
||
//
|
||
bWorldRights = DIR_ACCESS_ALL;
|
||
if (pSecDesc->Control & SE_DACL_PRESENT)
|
||
bWorldRights = 0;
|
||
|
||
|
||
if (pSecDesc->Dacl != NULL ) {
|
||
|
||
DWORD dwCount;
|
||
PSID pSid;
|
||
PACL pAcl;
|
||
PACCESS_ALLOWED_ACE pAce;
|
||
|
||
bWorldRights = 0;
|
||
pAcl = pSecDesc->Dacl;
|
||
pAce = (PACCESS_ALLOWED_ACE)((PBYTE)pAcl + sizeof(ACL));
|
||
|
||
for ( dwCount = 0; dwCount < pSecDesc->Dacl->AceCount; dwCount++) {
|
||
|
||
pSid = (PSID)(&pAce->SidStart);
|
||
|
||
if ( (pSecDesc->Owner != NULL) &&
|
||
RtlEqualSid(pSid, pSecDesc->Owner ) ){
|
||
|
||
AfpAccessMaskToAfpPermissions( bOwnerRights,
|
||
pAce->Mask,
|
||
pAce->Header.AceType);
|
||
|
||
fSawOwnerAce = TRUE;
|
||
}
|
||
|
||
if ( ( pSecDesc->Group != NULL ) &&
|
||
RtlEqualSid(pSid, pSecDesc->Group)){
|
||
|
||
AfpAccessMaskToAfpPermissions( bGroupRights,
|
||
pAce->Mask,
|
||
pAce->Header.AceType);
|
||
fSawGroupAce = TRUE;
|
||
}
|
||
|
||
if (RtlEqualSid(pSid, (PSID)&AfpSidWorld)) {
|
||
|
||
AfpAccessMaskToAfpPermissions( bWorldRights,
|
||
pAce->Mask,
|
||
pAce->Header.AceType);
|
||
}
|
||
|
||
pAce = (PACCESS_ALLOWED_ACE)((PBYTE)pAce + pAce->Header.AceSize);
|
||
}
|
||
|
||
}
|
||
|
||
if (!fSawOwnerAce)
|
||
bOwnerRights = bWorldRights;
|
||
|
||
if (!fSawGroupAce)
|
||
bGroupRights = bWorldRights;
|
||
|
||
if (RtlEqualSid(pSecDesc->Group, &AfpSidNull) ||
|
||
((AfpGlobals.NtProductType != NtProductLanManNt) &&
|
||
RtlEqualSid(pSecDesc->Group, AfpGlobals.pSidNone)))
|
||
{
|
||
bGroupRights = 0;
|
||
pSecDesc->Group = NULL;
|
||
}
|
||
|
||
ntStatus = NtQueryInformationFile( hDirectory,
|
||
&IOStatusBlock,
|
||
&FileBasicInfo,
|
||
sizeof( FileBasicInfo ),
|
||
FileBasicInformation );
|
||
|
||
|
||
NtClose( hDirectory );
|
||
|
||
if ( !NT_SUCCESS( ntStatus ) ) {
|
||
MIDL_user_free( pBuffer );
|
||
return( RtlNtStatusToDosError( ntStatus ) );
|
||
}
|
||
|
||
pAfpDir->afpdir_perms = (bOwnerRights << OWNER_RIGHTS_SHIFT) +
|
||
(bGroupRights << GROUP_RIGHTS_SHIFT) +
|
||
(bWorldRights << WORLD_RIGHTS_SHIFT);
|
||
|
||
if ( FileBasicInfo.FileAttributes & FILE_ATTRIBUTE_READONLY )
|
||
pAfpDir->afpdir_perms |= AFP_PERM_INHIBIT_MOVE_DELETE;
|
||
|
||
|
||
pAfpDir->afpdir_owner = pSecDesc->Owner;
|
||
pAfpDir->afpdir_group = pSecDesc->Group;
|
||
|
||
|
||
*lppDirInfo = pAfpDir;
|
||
|
||
return( NO_ERROR );
|
||
}
|
||
|
||
//**
|
||
//
|
||
// Call: AfpValidatePartition
|
||
//
|
||
// Returns: NO_ERROR
|
||
// non-zero returns from GetVolumeInformation.
|
||
// AFPERR_UnsupportedFS
|
||
//
|
||
//
|
||
// Description: Will check to see if the directory is in an NTFS/CDFS
|
||
// partition not.
|
||
//
|
||
DWORD
|
||
AfpValidatePartition(
|
||
IN LPWSTR lpwsPath
|
||
)
|
||
{
|
||
WCHAR wchDrive[5];
|
||
DWORD dwMaxCompSize;
|
||
DWORD dwFlags;
|
||
WCHAR wchFileSystem[10];
|
||
|
||
// Get the drive letter, : and backslash
|
||
//
|
||
ZeroMemory( wchDrive, sizeof( wchDrive ) );
|
||
|
||
STRNCPY( wchDrive, lpwsPath, 3 );
|
||
|
||
if ( !( GetVolumeInformation( (LPWSTR)wchDrive,
|
||
NULL,
|
||
0,
|
||
NULL,
|
||
&dwMaxCompSize,
|
||
&dwFlags,
|
||
(LPWSTR)wchFileSystem,
|
||
sizeof( wchFileSystem ) ) ) ){
|
||
return GetLastError();
|
||
}
|
||
|
||
if ( STRICMP( wchFileSystem, TEXT("CDFS") ) == 0 )
|
||
return( (DWORD)AFPERR_SecurityNotSupported );
|
||
|
||
if ( STRICMP( wchFileSystem, TEXT("NTFS") ) == 0 )
|
||
return( NO_ERROR );
|
||
else
|
||
return( (DWORD)AFPERR_UnsupportedFS );
|
||
|
||
}
|
||
|
||
//**
|
||
//
|
||
// Call: AfpAdminrDirectoryGetInfo
|
||
//
|
||
// Returns: NO_ERROR
|
||
// ERROR_ACCESS_DENIED
|
||
// non-zero retunrs from I_DirectoryGetInfo
|
||
//
|
||
// Description: This routine communicates with the AFP FSD to implement
|
||
// the AfpAdminDirectoryGetInfo function. The real work is done
|
||
// by I_DirectoryGetInfo
|
||
//
|
||
DWORD
|
||
AfpAdminrDirectoryGetInfo(
|
||
IN AFP_SERVER_HANDLE hServer,
|
||
IN LPWSTR lpwsPath,
|
||
OUT PAFP_DIRECTORY_INFO* ppAfpDirectoryInfo
|
||
)
|
||
{
|
||
DWORD dwRetCode=0;
|
||
DWORD dwAccessStatus=0;
|
||
|
||
// Check if caller has access
|
||
//
|
||
if ( dwRetCode = AfpSecObjAccessCheck( AFPSVC_ALL_ACCESS, &dwAccessStatus))
|
||
{
|
||
AFP_PRINT(( "SFMSVC: AfpAdminrDirectoryGetInfo, AfpSecObjAccessCheck failed %ld\n",dwRetCode));
|
||
AfpLogEvent( AFPLOG_CANT_CHECK_ACCESS, 0, NULL,
|
||
dwRetCode, EVENTLOG_ERROR_TYPE );
|
||
return( ERROR_ACCESS_DENIED );
|
||
}
|
||
|
||
if ( dwAccessStatus )
|
||
{
|
||
AFP_PRINT(( "SFMSVC: AfpAdminrDirectoryGetInfo, AfpSecObjAccessCheck returned error (%ld)\n",dwAccessStatus));
|
||
return( ERROR_ACCESS_DENIED );
|
||
}
|
||
|
||
dwRetCode = I_DirectoryGetInfo( lpwsPath, ppAfpDirectoryInfo );
|
||
|
||
return( dwRetCode );
|
||
}
|
||
|
||
//**
|
||
//
|
||
// Call: I_DirectoryGetInfo
|
||
//
|
||
// Returns: NO_ERROR
|
||
//
|
||
// Description: This does the real work to get the directory information.
|
||
// The reason for this worker routine is so that it may be
|
||
// called without the RPC handle and access checking by
|
||
// AfpAdminVolumeAdd API.
|
||
//
|
||
DWORD
|
||
I_DirectoryGetInfo(
|
||
IN LPWSTR lpwsPath,
|
||
OUT PAFP_DIRECTORY_INFO * ppAfpDirectoryInfo
|
||
)
|
||
{
|
||
DWORD dwRetCode;
|
||
AFP_REQUEST_PACKET AfpSrp;
|
||
AFP_DIRECTORY_INFO AfpDirInfo;
|
||
PAFP_DIRECTORY_INFO pAfpDirInfoSR;
|
||
PAFP_DIRECTORY_INFO pAfpDirInfo;
|
||
DWORD cbAfpDirInfoSRSize;
|
||
|
||
// The FSD expects AFP_VOLUME_INFO structure with only the dir path field
|
||
// filled in.
|
||
//
|
||
AfpDirInfo.afpdir_path = lpwsPath;
|
||
AfpDirInfo.afpdir_owner = NULL;
|
||
AfpDirInfo.afpdir_group = NULL;
|
||
|
||
// Make buffer self relative.
|
||
//
|
||
if ( dwRetCode = AfpBufMakeFSDRequest( (LPBYTE)&AfpDirInfo,
|
||
0,
|
||
AFP_DIRECTORY_STRUCT,
|
||
(LPBYTE*)&pAfpDirInfoSR,
|
||
&cbAfpDirInfoSRSize ) )
|
||
return( dwRetCode );
|
||
|
||
// Make IOCTL to get info
|
||
//
|
||
AfpSrp.dwRequestCode = OP_DIRECTORY_GET_INFO;
|
||
AfpSrp.dwApiType = AFP_API_TYPE_GETINFO;
|
||
AfpSrp.Type.GetInfo.pInputBuf = pAfpDirInfoSR;
|
||
AfpSrp.Type.GetInfo.cbInputBufSize = cbAfpDirInfoSRSize;
|
||
|
||
dwRetCode = AfpServerIOCtrlGetInfo( &AfpSrp );
|
||
|
||
LocalFree( pAfpDirInfoSR );
|
||
|
||
if ( ( dwRetCode != ERROR_MORE_DATA ) &&
|
||
( dwRetCode != NO_ERROR ) &&
|
||
( dwRetCode != AFPERR_DirectoryNotInVolume ) )
|
||
return( dwRetCode );
|
||
|
||
// If the directory is not part of a volume, then there server does not
|
||
// return any information back. So we have to do the work here.
|
||
//
|
||
if ( dwRetCode == AFPERR_DirectoryNotInVolume ) {
|
||
|
||
// First check to see if the directory is in an NTFS/CDFS partition
|
||
//
|
||
if ( ( dwRetCode = AfpValidatePartition( AfpDirInfo.afpdir_path ))
|
||
!= NO_ERROR )
|
||
return( dwRetCode );
|
||
|
||
if ( ( dwRetCode = AfpGetDirInfo( AfpDirInfo.afpdir_path,
|
||
&pAfpDirInfo ) ) != NO_ERROR )
|
||
return( dwRetCode );
|
||
|
||
pAfpDirInfo->afpdir_in_volume = FALSE;
|
||
}
|
||
else {
|
||
|
||
pAfpDirInfo = AfpSrp.Type.GetInfo.pOutputBuf;
|
||
|
||
// Convert all offsets to pointers
|
||
//
|
||
AfpBufOffsetToPointer( (LPBYTE)pAfpDirInfo, 1, AFP_DIRECTORY_STRUCT );
|
||
|
||
pAfpDirInfo->afpdir_in_volume = TRUE;
|
||
}
|
||
|
||
// Now convert the owner and group SIDs to names
|
||
//
|
||
dwRetCode = AfpDirConvertSidsToNames( pAfpDirInfo, ppAfpDirectoryInfo );
|
||
|
||
MIDL_user_free( pAfpDirInfo );
|
||
|
||
return( dwRetCode );
|
||
}
|
||
|
||
//**
|
||
//
|
||
// Call: AfpDirMakeFSDRequest
|
||
//
|
||
// Returns: NO_ERROR
|
||
// non-zero returnd from LsaLookupNames
|
||
// ERROR_NOT_ENOUGH_MEMORY
|
||
//
|
||
// Description: Given a AFP_DIRECTORY_INFO structure, will create a
|
||
// self-relative buffer that is used to IOCTL the directory
|
||
// information down to the FSD. If there are any SIDs names
|
||
// (owner or group) they will be converted to their
|
||
// SIDs.
|
||
//
|
||
DWORD
|
||
AfpDirMakeFSDRequest(
|
||
IN PAFP_DIRECTORY_INFO pAfpDirectoryInfo,
|
||
IN DWORD dwParmNum,
|
||
IN OUT PAFP_DIRECTORY_INFO * ppAfpDirInfoSR,
|
||
OUT LPDWORD pcbAfpDirInfoSRSize )
|
||
{
|
||
UNICODE_STRING Names[2];
|
||
DWORD dwIndex = 0;
|
||
DWORD dwCount = 0;
|
||
PLSA_REFERENCED_DOMAIN_LIST pDomainList = NULL;
|
||
PLSA_TRANSLATED_SID pSids = NULL;
|
||
LPBYTE pbVariableData;
|
||
NTSTATUS ntStatus;
|
||
LSA_HANDLE hLsa = NULL;
|
||
SECURITY_QUALITY_OF_SERVICE QOS;
|
||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||
PSID pDomainSid;
|
||
DWORD AuthCount;
|
||
PAFP_DIRECTORY_INFO pAfpDirInfo;
|
||
|
||
*pcbAfpDirInfoSRSize = (DWORD)(sizeof( SETINFOREQPKT ) +
|
||
sizeof( AFP_DIRECTORY_INFO ) +
|
||
(( wcslen( pAfpDirectoryInfo->afpdir_path ) + 1 )
|
||
* sizeof(WCHAR)));
|
||
|
||
// If the client wants to set the owner or the group
|
||
// then we need to translate the names to sids
|
||
//
|
||
if ( ( dwParmNum & AFP_DIR_PARMNUM_OWNER ) ||
|
||
( dwParmNum & AFP_DIR_PARMNUM_GROUP ) )
|
||
{
|
||
|
||
// First open the LSA and obtain a handle to it.
|
||
//
|
||
QOS.Length = sizeof( QOS );
|
||
QOS.ImpersonationLevel = SecurityImpersonation;
|
||
QOS.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
|
||
QOS.EffectiveOnly = FALSE;
|
||
|
||
InitializeObjectAttributes( &ObjectAttributes,
|
||
NULL,
|
||
0L,
|
||
NULL,
|
||
NULL );
|
||
|
||
ObjectAttributes.SecurityQualityOfService = &QOS;
|
||
|
||
ntStatus = LsaOpenPolicy( NULL,
|
||
&ObjectAttributes,
|
||
POLICY_LOOKUP_NAMES,
|
||
&hLsa );
|
||
|
||
if ( !NT_SUCCESS( ntStatus ))
|
||
{
|
||
return( RtlNtStatusToDosError( ntStatus ) );
|
||
}
|
||
|
||
//
|
||
// Translate the owner
|
||
//
|
||
if ( dwParmNum & AFP_DIR_PARMNUM_OWNER )
|
||
{
|
||
RtlInitUnicodeString( &(Names[dwCount++]),
|
||
pAfpDirectoryInfo->afpdir_owner );
|
||
}
|
||
|
||
//
|
||
// Translate the group
|
||
//
|
||
if ( dwParmNum & AFP_DIR_PARMNUM_GROUP )
|
||
{
|
||
RtlInitUnicodeString( &(Names[dwCount++]),
|
||
pAfpDirectoryInfo->afpdir_group );
|
||
}
|
||
|
||
ntStatus = LsaLookupNames(hLsa, dwCount, Names, &pDomainList, &pSids);
|
||
|
||
if ( !NT_SUCCESS( ntStatus ) )
|
||
{
|
||
LsaClose( hLsa );
|
||
|
||
if ( ntStatus == STATUS_NONE_MAPPED )
|
||
{
|
||
return( (DWORD)AFPERR_NoSuchUserGroup );
|
||
}
|
||
else
|
||
{
|
||
return( RtlNtStatusToDosError( ntStatus ) );
|
||
}
|
||
}
|
||
|
||
for ( dwIndex = 0; dwIndex < dwCount; dwIndex++ )
|
||
{
|
||
|
||
if ( ( pSids[dwIndex].Use == SidTypeInvalid ) ||
|
||
( pSids[dwIndex].Use == SidTypeUnknown ) ||
|
||
( pSids[dwIndex].Use == SidTypeDomain ) ||
|
||
( pSids[dwIndex].DomainIndex == -1 ) )
|
||
{
|
||
|
||
LsaFreeMemory( pDomainList );
|
||
LsaClose( hLsa );
|
||
|
||
if ( ( pSids[dwIndex].Use == SidTypeUnknown ) ||
|
||
( pSids[dwIndex].Use == SidTypeInvalid ) )
|
||
{
|
||
|
||
LsaFreeMemory( pSids );
|
||
|
||
if ((dwParmNum & AFP_DIR_PARMNUM_OWNER)&&(dwIndex == 0 ))
|
||
{
|
||
return( (DWORD)AFPERR_NoSuchUser );
|
||
}
|
||
else
|
||
{
|
||
return( (DWORD)AFPERR_NoSuchGroup );
|
||
}
|
||
}
|
||
else
|
||
{
|
||
|
||
LsaFreeMemory( pSids );
|
||
|
||
return( (DWORD)AFPERR_NoSuchUserGroup );
|
||
}
|
||
}
|
||
|
||
pDomainSid = pDomainList->Domains[pSids[dwIndex].DomainIndex].Sid;
|
||
|
||
AuthCount = *RtlSubAuthorityCountSid( pDomainSid ) + 1;
|
||
|
||
*pcbAfpDirInfoSRSize += RtlLengthRequiredSid(AuthCount);
|
||
}
|
||
}
|
||
|
||
*ppAfpDirInfoSR=(PAFP_DIRECTORY_INFO)LocalAlloc(LPTR,*pcbAfpDirInfoSRSize);
|
||
|
||
if ( *ppAfpDirInfoSR == NULL )
|
||
{
|
||
LsaFreeMemory( pDomainList );
|
||
LsaFreeMemory( pSids );
|
||
LsaClose( hLsa );
|
||
return( ERROR_NOT_ENOUGH_MEMORY );
|
||
}
|
||
|
||
pbVariableData = (LPBYTE)((ULONG_PTR)(*ppAfpDirInfoSR) + *pcbAfpDirInfoSRSize);
|
||
|
||
pAfpDirInfo = (PAFP_DIRECTORY_INFO)((ULONG_PTR)( *ppAfpDirInfoSR) +
|
||
sizeof( SETINFOREQPKT ));
|
||
// First copy the fixed part
|
||
//
|
||
CopyMemory( pAfpDirInfo, pAfpDirectoryInfo, sizeof(AFP_DIRECTORY_INFO) );
|
||
|
||
// Now copy the path
|
||
//
|
||
pbVariableData-=((wcslen(pAfpDirectoryInfo->afpdir_path)+1)*sizeof(WCHAR));
|
||
|
||
wcscpy( (LPWSTR)pbVariableData, pAfpDirectoryInfo->afpdir_path );
|
||
|
||
pAfpDirInfo->afpdir_path = (LPWSTR)pbVariableData;
|
||
|
||
POINTER_TO_OFFSET( pAfpDirInfo->afpdir_path, pAfpDirInfo );
|
||
|
||
// Now copy the SIDs if there are any to be copied
|
||
//
|
||
dwCount = 0;
|
||
|
||
if ( dwParmNum & AFP_DIR_PARMNUM_OWNER )
|
||
{
|
||
|
||
pDomainSid = pDomainList->Domains[pSids[dwCount].DomainIndex].Sid;
|
||
|
||
AuthCount = *RtlSubAuthorityCountSid( pDomainSid ) + 1;
|
||
|
||
pbVariableData -= RtlLengthRequiredSid(AuthCount);
|
||
|
||
// Copy the Domain Sid.
|
||
//
|
||
RtlCopySid( RtlLengthRequiredSid(AuthCount),
|
||
(PSID)pbVariableData,
|
||
pDomainSid );
|
||
|
||
|
||
// Append the Relative Id.
|
||
//
|
||
*RtlSubAuthorityCountSid( (PSID)pbVariableData ) += 1;
|
||
*RtlSubAuthoritySid( (PSID)(pbVariableData), AuthCount - 1) =
|
||
pSids[dwCount].RelativeId;
|
||
|
||
pAfpDirInfo->afpdir_owner = (LPWSTR)pbVariableData;
|
||
|
||
POINTER_TO_OFFSET( pAfpDirInfo->afpdir_owner, pAfpDirInfo );
|
||
|
||
dwCount++;
|
||
}
|
||
|
||
if ( dwParmNum & AFP_DIR_PARMNUM_GROUP )
|
||
{
|
||
pDomainSid = pDomainList->Domains[pSids[dwCount].DomainIndex].Sid;
|
||
|
||
AuthCount = *RtlSubAuthorityCountSid( pDomainSid ) + 1;
|
||
|
||
pbVariableData -= RtlLengthRequiredSid(AuthCount);
|
||
|
||
// Copy the Domain Sid.
|
||
//
|
||
RtlCopySid( RtlLengthRequiredSid(AuthCount),
|
||
(PSID)pbVariableData,
|
||
pDomainSid );
|
||
|
||
// Append the Relative Id.
|
||
//
|
||
*RtlSubAuthorityCountSid( (PSID)pbVariableData ) += 1;
|
||
*RtlSubAuthoritySid( (PSID)(pbVariableData), AuthCount - 1) =
|
||
pSids[dwCount].RelativeId;
|
||
|
||
pAfpDirInfo->afpdir_group = (LPWSTR)pbVariableData;
|
||
|
||
POINTER_TO_OFFSET( pAfpDirInfo->afpdir_group, pAfpDirInfo );
|
||
}
|
||
|
||
LsaFreeMemory( pDomainList );
|
||
LsaFreeMemory( pSids );
|
||
LsaClose( hLsa );
|
||
|
||
return( NO_ERROR );
|
||
}
|
||
|
||
//**
|
||
//
|
||
// Call: AfpSetDirPermission
|
||
//
|
||
// Returns: NO_ERROR
|
||
// non-zero returns from AfpserverIOCtrl.
|
||
//
|
||
// Description: Given a directory path, will try to set permissions on it
|
||
//
|
||
DWORD
|
||
AfpSetDirPermission(
|
||
IN LPWSTR lpwsDirPath,
|
||
IN PAFP_DIRECTORY_INFO pAfpDirInfo,
|
||
IN DWORD dwParmNum
|
||
)
|
||
{
|
||
AFP_REQUEST_PACKET AfpSrp;
|
||
PAFP_DIRECTORY_INFO pAfpDirInfoSR;
|
||
DWORD cbAfpDirInfoSRSize;
|
||
DWORD dwRetCode;
|
||
|
||
|
||
pAfpDirInfo->afpdir_path = lpwsDirPath;
|
||
|
||
// Make a self relative buffer and translate any names to SIDs
|
||
//
|
||
if ( dwRetCode = AfpDirMakeFSDRequest( pAfpDirInfo,
|
||
dwParmNum,
|
||
&pAfpDirInfoSR,
|
||
&cbAfpDirInfoSRSize ) )
|
||
return( dwRetCode );
|
||
|
||
// Make IOCTL to set info
|
||
//
|
||
AfpSrp.dwRequestCode = OP_DIRECTORY_SET_INFO;
|
||
AfpSrp.dwApiType = AFP_API_TYPE_SETINFO;
|
||
AfpSrp.Type.SetInfo.pInputBuf = pAfpDirInfoSR;
|
||
AfpSrp.Type.SetInfo.cbInputBufSize = cbAfpDirInfoSRSize;
|
||
AfpSrp.Type.SetInfo.dwParmNum = dwParmNum;
|
||
|
||
dwRetCode = AfpServerIOCtrl( &AfpSrp );
|
||
|
||
LocalFree( pAfpDirInfoSR );
|
||
|
||
return( dwRetCode );
|
||
|
||
}
|
||
|
||
//**
|
||
//
|
||
// Call: AfpRecursePermissions
|
||
//
|
||
// Returns: NO_ERROR
|
||
// non-zero returns from FindFirstFile and FindNextFile.
|
||
// non-zero returns from AfpSetDirPermissions
|
||
// ERROR_NOT_ENOUGH_MEMORY.
|
||
//
|
||
// Description: Will recursively set permissions on a given directory.
|
||
//
|
||
DWORD
|
||
AfpRecursePermissions(
|
||
IN HANDLE hFile,
|
||
IN LPWSTR lpwsDirPath,
|
||
IN PAFP_DIRECTORY_INFO pAfpDirInfo,
|
||
IN DWORD dwParmNum
|
||
)
|
||
{
|
||
WIN32_FIND_DATA FileInfo;
|
||
DWORD dwRetCode = NO_ERROR;
|
||
LPWSTR lpwsPath;
|
||
WCHAR * pwchPath;
|
||
DWORD dwRetryCount;
|
||
|
||
|
||
do {
|
||
|
||
lpwsPath = LocalAlloc(LPTR,
|
||
(STRLEN(lpwsDirPath)+MAX_PATH)*sizeof(WCHAR));
|
||
|
||
if ( lpwsPath == NULL ) {
|
||
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
|
||
break;
|
||
}
|
||
|
||
STRCPY( lpwsPath, lpwsDirPath );
|
||
|
||
if ( hFile != INVALID_HANDLE_VALUE ) {
|
||
|
||
// Search for the next sub-directory
|
||
//
|
||
do {
|
||
|
||
if ( !FindNextFile( hFile, &FileInfo ) ) {
|
||
dwRetCode = GetLastError();
|
||
AFP_PRINT( ( "AFPSVC_dir: Closing handle %x\n", hFile ) );
|
||
FindClose( hFile );
|
||
break;
|
||
}
|
||
|
||
if ( ( FileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) &&
|
||
(!( FileInfo.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM )) &&
|
||
(!( FileInfo.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN )) &&
|
||
( STRCMP( FileInfo.cFileName, TEXT(".") ) != 0 ) &&
|
||
( STRCMP( FileInfo.cFileName, TEXT("..") ) != 0 ) )
|
||
break;
|
||
|
||
} while( TRUE );
|
||
|
||
if ( dwRetCode != NO_ERROR )
|
||
break;
|
||
|
||
pwchPath = wcsrchr( lpwsPath, TEXT('\\') );
|
||
|
||
STRCPY( pwchPath+1, FileInfo.cFileName );
|
||
|
||
}else{
|
||
|
||
STRCAT( lpwsPath, TEXT("\\*") );
|
||
|
||
hFile = FindFirstFile( lpwsPath, &FileInfo );
|
||
|
||
// If there are no more files, we return to the previous
|
||
// level in the recursion.
|
||
//
|
||
if ( hFile == INVALID_HANDLE_VALUE ){
|
||
|
||
dwRetCode = GetLastError();
|
||
break;
|
||
}
|
||
|
||
|
||
// Search for the first sub-directory
|
||
//
|
||
do {
|
||
|
||
if ( ( FileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) &&
|
||
(!( FileInfo.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM )) &&
|
||
(!( FileInfo.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN )) &&
|
||
( STRCMP( FileInfo.cFileName, TEXT(".") ) != 0 ) &&
|
||
( STRCMP( FileInfo.cFileName, TEXT("..") ) != 0 ) )
|
||
break;
|
||
|
||
if ( !FindNextFile( hFile, &FileInfo ) ) {
|
||
dwRetCode = GetLastError();
|
||
|
||
AFP_PRINT( ( "AFPSVC_dir: Closing handle %x\n", hFile ) );
|
||
FindClose( hFile );
|
||
|
||
break;
|
||
}
|
||
|
||
} while( TRUE );
|
||
|
||
if ( dwRetCode != NO_ERROR )
|
||
break;
|
||
|
||
pwchPath = lpwsPath + STRLEN(lpwsDirPath) + 1;
|
||
|
||
STRCPY( pwchPath, FileInfo.cFileName );
|
||
}
|
||
|
||
|
||
// Don't send the \\?\ down to the server
|
||
pwchPath = lpwsPath + 4;
|
||
|
||
// Set the information
|
||
//
|
||
dwRetryCount = 0;
|
||
|
||
do
|
||
{
|
||
dwRetCode = AfpSetDirPermission( pwchPath, pAfpDirInfo, dwParmNum );
|
||
|
||
if ( dwRetCode != ERROR_PATH_NOT_FOUND )
|
||
break;
|
||
|
||
Sleep( 1000 );
|
||
|
||
} while( ++dwRetryCount < 4 );
|
||
|
||
if ( dwRetCode != NO_ERROR )
|
||
break;
|
||
|
||
// Recurse on the directory
|
||
//
|
||
dwRetCode = AfpRecursePermissions( hFile,
|
||
lpwsPath,
|
||
pAfpDirInfo,
|
||
dwParmNum );
|
||
|
||
|
||
if ( dwRetCode != NO_ERROR )
|
||
break;
|
||
|
||
// Recurse on the sub-directory
|
||
//
|
||
dwRetCode = AfpRecursePermissions( INVALID_HANDLE_VALUE,
|
||
lpwsPath,
|
||
pAfpDirInfo,
|
||
dwParmNum );
|
||
break;
|
||
|
||
if ( dwRetCode != NO_ERROR )
|
||
break;
|
||
|
||
|
||
} while( FALSE );
|
||
|
||
if ( lpwsPath != (LPWSTR)NULL )
|
||
{
|
||
LocalFree( lpwsPath );
|
||
}
|
||
|
||
if ( dwRetCode == ERROR_NO_MORE_FILES )
|
||
{
|
||
dwRetCode = NO_ERROR;
|
||
}
|
||
|
||
return( dwRetCode );
|
||
}
|
||
|
||
//**
|
||
//
|
||
// Call: AfpAdminrDirectorySetInfo
|
||
//
|
||
// Returns: NO_ERROR
|
||
// ERROR_ACCESS_DENIED
|
||
// non-zero retunrs from I_DirectorySetInfo.
|
||
//
|
||
// Description: This routine communicates with the AFP FSD to implement
|
||
// the AfpAdminDirectorySetInfo function. The real work is done
|
||
// by I_DirectorySetInfo
|
||
//
|
||
DWORD
|
||
AfpAdminrDirectorySetInfo(
|
||
IN AFP_SERVER_HANDLE hServer,
|
||
IN PAFP_DIRECTORY_INFO pAfpDirectoryInfo,
|
||
IN DWORD dwParmNum
|
||
)
|
||
{
|
||
DWORD dwRetCode=0;
|
||
DWORD dwAccessStatus=0;
|
||
|
||
|
||
// Check if caller has access
|
||
//
|
||
if ( dwRetCode = AfpSecObjAccessCheck( AFPSVC_ALL_ACCESS, &dwAccessStatus))
|
||
{
|
||
AFP_PRINT(( "SFMSVC: AfpAdminrDirectorySetInfo, AfpSecObjAccessCheck failed %ld\n",dwRetCode));
|
||
AfpLogEvent( AFPLOG_CANT_CHECK_ACCESS, 0, NULL,
|
||
dwRetCode, EVENTLOG_ERROR_TYPE );
|
||
return( ERROR_ACCESS_DENIED );
|
||
}
|
||
|
||
if ( dwAccessStatus )
|
||
{
|
||
AFP_PRINT(( "SFMSVC: AfpAdminrDirectorySetInfo, AfpSecObjAccessCheck returned %ld\n",dwAccessStatus));
|
||
return( ERROR_ACCESS_DENIED );
|
||
}
|
||
|
||
dwRetCode = I_DirectorySetInfo( pAfpDirectoryInfo, dwParmNum );
|
||
|
||
return( dwRetCode );
|
||
}
|
||
|
||
//**
|
||
//
|
||
// Call: I_DirectorySetInfo
|
||
//
|
||
// Returns: NO_ERROR
|
||
//
|
||
//
|
||
// Description: This routine does the real work. The existance of this
|
||
// worker is so that it may be called from the AfpAfdminVolmeAdd
|
||
// API without the RPC handle and access checking.
|
||
//
|
||
DWORD
|
||
I_DirectorySetInfo(
|
||
IN PAFP_DIRECTORY_INFO pAfpDirectoryInfo,
|
||
IN DWORD dwParmNum
|
||
)
|
||
{
|
||
DWORD dwRetCode;
|
||
|
||
if (pAfpDirectoryInfo->afpdir_path == NULL)
|
||
{
|
||
AFP_PRINT(( "SFMSVC: I_DirectorySetInfo, pAfpDirectoryInfo->afpdir_path == NULL\n"));
|
||
return ERROR_INVALID_DATA;
|
||
}
|
||
|
||
// Set the permissions on the directory
|
||
//
|
||
if ( ( dwRetCode = AfpSetDirPermission( pAfpDirectoryInfo->afpdir_path,
|
||
pAfpDirectoryInfo,
|
||
dwParmNum ) ) != NO_ERROR )
|
||
return( dwRetCode );
|
||
|
||
// If the user wants to set these permissions recursively
|
||
//
|
||
if ( pAfpDirectoryInfo->afpdir_perms & AFP_PERM_SET_SUBDIRS )
|
||
{
|
||
LPWSTR NTDirName;
|
||
|
||
// We must use the \\?\ notation for the path in order to bypass
|
||
// the Win32 path length limitation of 260 chars
|
||
NTDirName = LocalAlloc( LPTR,
|
||
(STRLEN(pAfpDirectoryInfo->afpdir_path) + 4 + 1)
|
||
* sizeof(WCHAR));
|
||
|
||
if (NTDirName == NULL)
|
||
return( ERROR_NOT_ENOUGH_MEMORY );
|
||
|
||
STRCPY( NTDirName, TEXT("\\\\?\\"));
|
||
STRCAT( NTDirName, pAfpDirectoryInfo->afpdir_path);
|
||
|
||
dwRetCode = AfpRecursePermissions( INVALID_HANDLE_VALUE,
|
||
NTDirName,
|
||
pAfpDirectoryInfo,
|
||
dwParmNum );
|
||
LocalFree( NTDirName );
|
||
|
||
}
|
||
|
||
return( dwRetCode );
|
||
}
|