mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1389 lines
45 KiB
1389 lines
45 KiB
/********************************************************************/
|
|
/** 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 );
|
|
}
|