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;
|
||
}
|