461 lines
12 KiB
C
461 lines
12 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1993 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
adtsrv.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
AdminTools Server functions.
|
|||
|
|
|||
|
This file contains the remote interface for NetpGetFileSecurity and
|
|||
|
NetpSetFileSecurity API.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Dan Lafferty (danl) 25-Mar-1993
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
User Mode - Win32
|
|||
|
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
27-Oct-1994 IsaacHe
|
|||
|
Make sure the share permissions allow these operations.
|
|||
|
05-Sep-1994 Danl
|
|||
|
Free memory and NULL the pointer to the SecurityDescriptor if
|
|||
|
a failure occurs. Also free the buffer returned from
|
|||
|
NetShareGetInfo.
|
|||
|
25-Mar-1993 danl
|
|||
|
Created
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
//
|
|||
|
// Includes
|
|||
|
//
|
|||
|
|
|||
|
#include "srvsvcp.h"
|
|||
|
|
|||
|
#include <lmerr.h>
|
|||
|
#include <adtcomn.h>
|
|||
|
#include <tstr.h>
|
|||
|
|
|||
|
DWORD AdtsvcDebugLevel = DEBUG_ERROR;
|
|||
|
|
|||
|
//
|
|||
|
// LOCAL FUNCTIONS
|
|||
|
//
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
AdtCheckShareAccessAndGetFullPath(
|
|||
|
LPWSTR pShare,
|
|||
|
LPWSTR pFileName,
|
|||
|
LPWSTR *pPath,
|
|||
|
ACCESS_MASK DesiredAccess
|
|||
|
);
|
|||
|
|
|||
|
NET_API_STATUS NET_API_FUNCTION
|
|||
|
NetrpGetFileSecurity (
|
|||
|
IN LPWSTR ServerName,
|
|||
|
IN LPWSTR ShareName,
|
|||
|
IN LPWSTR FileName,
|
|||
|
IN SECURITY_INFORMATION RequestedInfo,
|
|||
|
OUT PADT_SECURITY_DESCRIPTOR *pSecurityDescriptor
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function returns to the caller a copy of the security descriptor
|
|||
|
protecting a file or directory. It calls GetFileSecurity. The
|
|||
|
Security Descriptor is always returned in the self-relative format.
|
|||
|
|
|||
|
This function is called only when accessing remote files. In this case,
|
|||
|
the filename is broken into ServerName, ShareName, and FileName components.
|
|||
|
The ServerName gets the request to this routine. The ShareName must be
|
|||
|
expanded to find the local path associated with it. This is combined
|
|||
|
with the FileName to create a fully qualified pathname that is local
|
|||
|
to this machine.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ServerName - A pointer to a string containing the name of the remote
|
|||
|
server on which the function is to execute. A NULL pointer or
|
|||
|
string specifies the local machine.
|
|||
|
|
|||
|
ShareName - A pointer to a string that identifies the share name
|
|||
|
on which the file is found.
|
|||
|
|
|||
|
FileName - A pointer to the name fo the file or directory whose
|
|||
|
security is being retrieved.
|
|||
|
|
|||
|
RequestedInfo - The type of security information being requested.
|
|||
|
|
|||
|
pSecurityDescriptor - A pointer to a pointer to a structure which
|
|||
|
contains the buffer pointer for the security descriptor and
|
|||
|
a length field for the security descriptor.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NERR_Success - The operation was successful.
|
|||
|
|
|||
|
ERROR_NOT_ENOUGH_MEMORY - Unable to allocate memory for the security
|
|||
|
descriptor.
|
|||
|
|
|||
|
Other - This function can also return any error that
|
|||
|
GetFileSecurity,
|
|||
|
RpcImpersonateClient, or
|
|||
|
ShareEnumCommon
|
|||
|
can return.
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS status;
|
|||
|
PSECURITY_DESCRIPTOR pNewSecurityDescriptor;
|
|||
|
DWORD bufSize;
|
|||
|
LPWSTR FullPath=NULL;
|
|||
|
ACCESS_MASK DesiredAccess = 0;
|
|||
|
|
|||
|
*pSecurityDescriptor = MIDL_user_allocate(sizeof(ADT_SECURITY_DESCRIPTOR));
|
|||
|
|
|||
|
if (*pSecurityDescriptor == NULL) {
|
|||
|
ADT_LOG0( ERROR, "NetrpGetFileSecurity:MIDL_user_alloc failed\n" );
|
|||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Figure out accesses needed to perform the indicated operation(s).
|
|||
|
// This code is taken from ntos\se\semethod.c
|
|||
|
//
|
|||
|
if ((RequestedInfo & OWNER_SECURITY_INFORMATION) ||
|
|||
|
(RequestedInfo & GROUP_SECURITY_INFORMATION) ||
|
|||
|
(RequestedInfo & DACL_SECURITY_INFORMATION)) {
|
|||
|
DesiredAccess |= READ_CONTROL;
|
|||
|
}
|
|||
|
|
|||
|
if ((RequestedInfo & SACL_SECURITY_INFORMATION)) {
|
|||
|
DesiredAccess |= ACCESS_SYSTEM_SECURITY;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check share perms and create a full path string by getting
|
|||
|
// the path for the share name, and adding the FileName string to it.
|
|||
|
//
|
|||
|
status = AdtCheckShareAccessAndGetFullPath(
|
|||
|
ShareName,
|
|||
|
FileName,
|
|||
|
&FullPath,
|
|||
|
DesiredAccess
|
|||
|
);
|
|||
|
|
|||
|
if( status == NO_ERROR ) {
|
|||
|
if( (status = RpcImpersonateClient(NULL)) == NO_ERROR ) {
|
|||
|
//
|
|||
|
// Get the File Security information
|
|||
|
//
|
|||
|
status = PrivateGetFileSecurity(
|
|||
|
FullPath,
|
|||
|
RequestedInfo,
|
|||
|
&pNewSecurityDescriptor,
|
|||
|
&bufSize);
|
|||
|
|
|||
|
if ( status == NO_ERROR ) {
|
|||
|
(*pSecurityDescriptor)->Length = bufSize;
|
|||
|
(*pSecurityDescriptor)->Buffer = pNewSecurityDescriptor;
|
|||
|
}
|
|||
|
|
|||
|
(VOID)RpcRevertToSelf();
|
|||
|
}
|
|||
|
MIDL_user_free( FullPath );
|
|||
|
}
|
|||
|
|
|||
|
if ( status != NO_ERROR ) {
|
|||
|
MIDL_user_free(*pSecurityDescriptor);
|
|||
|
*pSecurityDescriptor = NULL;
|
|||
|
}
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS NET_API_FUNCTION
|
|||
|
NetrpSetFileSecurity (
|
|||
|
IN LPWSTR ServerName OPTIONAL,
|
|||
|
IN LPWSTR ShareName,
|
|||
|
IN LPWSTR FileName,
|
|||
|
IN SECURITY_INFORMATION SecurityInfo,
|
|||
|
IN PADT_SECURITY_DESCRIPTOR pSecurityDescriptor
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function can be used to set the security of a file or directory.
|
|||
|
It calls SetFileSecurity().
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ServerName - A pointer to a string containing the name of the remote
|
|||
|
server on which the function is to execute. A NULL pointer or
|
|||
|
string specifies the local machine.
|
|||
|
|
|||
|
ShareName - A pointer to a string that identifies the share name
|
|||
|
on which the file or directory is found.
|
|||
|
|
|||
|
FileName - A pointer to the name of the file or directory whose
|
|||
|
security is being changed.
|
|||
|
|
|||
|
SecurityInfo - Information describing the contents
|
|||
|
of the Security Descriptor.
|
|||
|
|
|||
|
pSecurityDescriptor - A pointer to a structure that contains a
|
|||
|
self-relative security descriptor and a length.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NERR_Success - The operation was successful.
|
|||
|
|
|||
|
Other - This function can also return any error that
|
|||
|
SetFileSecurity,
|
|||
|
RpcImpersonateClient, or
|
|||
|
ShareEnumCommon
|
|||
|
can return.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS status;
|
|||
|
LPWSTR FullPath=NULL;
|
|||
|
ACCESS_MASK DesiredAccess = 0;
|
|||
|
|
|||
|
UNREFERENCED_PARAMETER(ServerName);
|
|||
|
|
|||
|
// Validate the parameters
|
|||
|
if( (pSecurityDescriptor->Buffer == NULL) &&
|
|||
|
(pSecurityDescriptor->Length > 0) )
|
|||
|
{
|
|||
|
return ERROR_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Figure out accesses needed to perform the indicated operation(s).
|
|||
|
// This code is taken from ntos\se\semethod.c
|
|||
|
//
|
|||
|
if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
|
|||
|
(SecurityInfo & GROUP_SECURITY_INFORMATION) ) {
|
|||
|
DesiredAccess |= WRITE_OWNER;
|
|||
|
}
|
|||
|
|
|||
|
if (SecurityInfo & DACL_SECURITY_INFORMATION) {
|
|||
|
DesiredAccess |= WRITE_DAC;
|
|||
|
}
|
|||
|
|
|||
|
if (SecurityInfo & SACL_SECURITY_INFORMATION) {
|
|||
|
DesiredAccess |= ACCESS_SYSTEM_SECURITY;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check perms and create a full path string by getting the path
|
|||
|
// for the share name, and adding the FileName string to it.
|
|||
|
//
|
|||
|
status = AdtCheckShareAccessAndGetFullPath(
|
|||
|
ShareName,
|
|||
|
FileName,
|
|||
|
&FullPath,
|
|||
|
DesiredAccess
|
|||
|
);
|
|||
|
|
|||
|
if ( status == NO_ERROR ) {
|
|||
|
if( (status = RpcImpersonateClient(NULL)) == NO_ERROR ) {
|
|||
|
if (RtlValidRelativeSecurityDescriptor(
|
|||
|
pSecurityDescriptor->Buffer,
|
|||
|
pSecurityDescriptor->Length,
|
|||
|
SecurityInfo)) {
|
|||
|
//
|
|||
|
// Call SetFileSecurity
|
|||
|
//
|
|||
|
status = PrivateSetFileSecurity(
|
|||
|
FullPath,
|
|||
|
SecurityInfo,
|
|||
|
pSecurityDescriptor->Buffer);
|
|||
|
} else {
|
|||
|
status = ERROR_INVALID_SECURITY_DESCR;
|
|||
|
}
|
|||
|
|
|||
|
(VOID)RpcRevertToSelf();
|
|||
|
}
|
|||
|
MIDL_user_free(FullPath);
|
|||
|
}
|
|||
|
|
|||
|
return(status);
|
|||
|
}
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
AdtCheckShareAccessAndGetFullPath(
|
|||
|
LPWSTR pShare,
|
|||
|
LPWSTR pFileName,
|
|||
|
LPWSTR *pPath,
|
|||
|
ACCESS_MASK DesiredAccess
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function ensures the DesiredAccess is allowed and finds the
|
|||
|
path associated with the share name, combines this with the
|
|||
|
file name, and creates a fully qualified path name.
|
|||
|
|
|||
|
NOTE: This function allocates storage for the pPath string.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pShare - This is a pointer to the share name string.
|
|||
|
|
|||
|
pFileName - This is a pointer to the file name (or path) string.
|
|||
|
|
|||
|
pPath - This is a pointer to a location where the pointer to the
|
|||
|
complete file path string can be stored. This pointer needs to
|
|||
|
be free'd with MIDL_user_free when the caller is finished with it.
|
|||
|
|
|||
|
DesiredAccess - what we'd like to do through the share
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NO_ERROR - if The operation was completely successful.
|
|||
|
|
|||
|
Other - Errors returned from ShareEnumCommon, and MIDL_user_allocate may be
|
|||
|
returned from this routine.
|
|||
|
|
|||
|
Comments:
|
|||
|
The share access checking is complicated by the fact that the share ACL has
|
|||
|
had the owner and group SIDs stripped out. We need to put them back
|
|||
|
in, or the SsCheckAccess() call will fail.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS status;
|
|||
|
PSHARE_INFO_502 pshi502 = NULL;
|
|||
|
DWORD bufSize;
|
|||
|
DWORD fileNameSize;
|
|||
|
LPWSTR pLastChar;
|
|||
|
DWORD entriesRead;
|
|||
|
DWORD totalEntries;
|
|||
|
PSECURITY_DESCRIPTOR NewDescriptor = NULL;
|
|||
|
SECURITY_DESCRIPTOR ModificationDescriptor;
|
|||
|
GENERIC_MAPPING Mapping;
|
|||
|
SRVSVC_SECURITY_OBJECT SecurityObject;
|
|||
|
HANDLE token;
|
|||
|
|
|||
|
status = ShareEnumCommon(
|
|||
|
502,
|
|||
|
(LPBYTE *)&pshi502,
|
|||
|
(DWORD)-1,
|
|||
|
&entriesRead,
|
|||
|
&totalEntries,
|
|||
|
NULL,
|
|||
|
pShare
|
|||
|
);
|
|||
|
|
|||
|
if( status != NO_ERROR ) {
|
|||
|
goto getout;
|
|||
|
|
|||
|
} else if( entriesRead == 0 || pshi502 == NULL ) {
|
|||
|
status = NERR_NetNameNotFound;
|
|||
|
|
|||
|
} else if( pshi502->shi502_path == NULL ) {
|
|||
|
status = ERROR_BAD_DEV_TYPE;
|
|||
|
|
|||
|
} else if( pshi502->shi502_security_descriptor != NULL ) {
|
|||
|
|
|||
|
status = RtlCopySecurityDescriptor( pshi502->shi502_security_descriptor, &NewDescriptor );
|
|||
|
if( status != STATUS_SUCCESS )
|
|||
|
goto getout;
|
|||
|
|
|||
|
RtlCreateSecurityDescriptor( &ModificationDescriptor, SECURITY_DESCRIPTOR_REVISION );
|
|||
|
|
|||
|
RtlSetOwnerSecurityDescriptor( &ModificationDescriptor, SsData.SsLmsvcsGlobalData->LocalSystemSid, FALSE );
|
|||
|
|
|||
|
RtlSetGroupSecurityDescriptor( &ModificationDescriptor, SsData.SsLmsvcsGlobalData->LocalSystemSid, FALSE );
|
|||
|
|
|||
|
Mapping.GenericRead = FILE_GENERIC_READ;
|
|||
|
Mapping.GenericWrite = FILE_GENERIC_WRITE;
|
|||
|
Mapping.GenericExecute = FILE_GENERIC_EXECUTE;
|
|||
|
Mapping.GenericAll = FILE_ALL_ACCESS;
|
|||
|
|
|||
|
if( ImpersonateSelf( SecurityImpersonation ) == FALSE ) {
|
|||
|
status = GetLastError();
|
|||
|
goto getout;
|
|||
|
}
|
|||
|
|
|||
|
status = NtOpenThreadToken( NtCurrentThread(), TOKEN_QUERY, TRUE, &token );
|
|||
|
|
|||
|
RevertToSelf();
|
|||
|
|
|||
|
if( status != STATUS_SUCCESS )
|
|||
|
goto getout;
|
|||
|
|
|||
|
status = RtlSetSecurityObject (
|
|||
|
GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION,
|
|||
|
&ModificationDescriptor,
|
|||
|
&NewDescriptor,
|
|||
|
&Mapping,
|
|||
|
token
|
|||
|
);
|
|||
|
|
|||
|
NtClose( token );
|
|||
|
|
|||
|
if( status == STATUS_SUCCESS ) {
|
|||
|
|
|||
|
SecurityObject.ObjectName = pShare;
|
|||
|
SecurityObject.Mapping = &Mapping;
|
|||
|
SecurityObject.SecurityDescriptor = NewDescriptor;
|
|||
|
|
|||
|
//
|
|||
|
// SsCheckAccess does an RpcImpersonateClient()...
|
|||
|
//
|
|||
|
status = SsCheckAccess( &SecurityObject, DesiredAccess );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if( status == STATUS_SUCCESS ) {
|
|||
|
|
|||
|
//
|
|||
|
// If the last character is a '\', then we must remove it.
|
|||
|
//
|
|||
|
pLastChar = pshi502->shi502_path + wcslen(pshi502->shi502_path);
|
|||
|
pLastChar--;
|
|||
|
if (*pLastChar == L'\\') {
|
|||
|
*pLastChar = L'\0';
|
|||
|
}
|
|||
|
|
|||
|
bufSize = STRSIZE(pshi502->shi502_path);
|
|||
|
fileNameSize = STRSIZE(pFileName);
|
|||
|
|
|||
|
*pPath = MIDL_user_allocate( bufSize + fileNameSize );
|
|||
|
|
|||
|
if (*pPath != NULL) {
|
|||
|
wcscpy (*pPath, pshi502->shi502_path);
|
|||
|
wcscat (*pPath, pFileName);
|
|||
|
} else {
|
|||
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
getout:
|
|||
|
if( NewDescriptor != NULL )
|
|||
|
RtlDeleteSecurityObject( &NewDescriptor );
|
|||
|
|
|||
|
if( pshi502 != NULL )
|
|||
|
MIDL_user_free( pshi502 );
|
|||
|
|
|||
|
return status;
|
|||
|
}
|