windows-nt/Source/XPSP1/NT/ds/netapi/svcdlls/srvsvc/client/adtwrap.c

562 lines
14 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1993 Microsoft Corporation
Module Name:
adtwrap.c
Abstract:
These are the Admin Tools Service API RPC client stubs.
Author:
Dan Lafferty (danl) 25-Mar-1993
Environment:
User Mode - Win32
Revision History:
25-Mar-1993 Danl
Created
--*/
//
// INCLUDES
//
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h> // needed for windows.h when I have nt.h
#include <windows.h>
#include <srvsvc.h> // MIDL generated - includes windows.h & rpc.h
#include <rpc.h>
#include <lmcons.h>
#include <lmerr.h> // NERR_ error codes
#include <lmuse.h> // LPUSE_INFO_0
#include <lmapibuf.h> // NetApiBufferFree
#include <adtcomn.h>
//
// GLOBALS
//
DWORD AdtsvcDebugLevel = DEBUG_ERROR;
//
// LOCAL PROTOTYPES
//
DWORD
AdtParsePathName(
LPWSTR lpPathName,
LPWSTR *pNewFileName,
LPWSTR *pServerName,
LPWSTR *pShareName
);
LPWSTR
AdtFindNextToken(
WCHAR Token,
LPWSTR String,
LPDWORD pNumChars
);
DWORD
NetpGetFileSecurity(
IN LPWSTR lpFileName,
IN SECURITY_INFORMATION RequestedInformation,
OUT PSECURITY_DESCRIPTOR *pSecurityDescriptor,
OUT LPDWORD pnLength
)
/*++
Routine Description:
This function returns to the caller a copy of the security descriptor
protecting a file or directory.
NOTE: The buffer containing the security descriptor is allocated for
the caller. It is the caller's responsibility to free the buffer by
calling the NetApiBufferFree() function.
Arguments:
lpFileName - A pointer to the name fo the file or directory whose
security is being retrieved.
SecurityInformation - security information being requested.
pSecurityDescriptor - A pointer to a location where the pointer
to the security descriptor is to be placed. The security
descriptor is returned in the self-relative format.
pnLength - The size, in bytes, of the returned security descriptor.
Return Value:
NO_ERROR - The operation was successful.
ERROR_NOT_ENOUGH_MEMORY - Unable to allocate memory for the security
descriptor.
This function can also return any error that GetFileSecurity can
return.
--*/
{
NET_API_STATUS status;
ADT_SECURITY_DESCRIPTOR returnedSD;
PADT_SECURITY_DESCRIPTOR pReturnedSD;
LPWSTR pServerName;
LPWSTR pShareName;
LPWSTR pNewFileName;
RpcTryExcept {
//
// Pick the server name out of the filename. Or translate the
// local drive name into a \\servername\sharename.
//
status = AdtParsePathName(lpFileName,&pNewFileName,&pServerName,&pShareName);
}
RpcExcept (1) {
//
// Get RPC exception code.
//
status = RpcExceptionCode();
}
RpcEndExcept
if (status != NO_ERROR) {
LocalFree(pServerName);
return(status);
}
if (pServerName == NULL) {
//
// Call Locally.
//
ADT_LOG0(TRACE,"Call Local version (PrivateGetFileSecurity)\n");
status = PrivateGetFileSecurity (
lpFileName,
RequestedInformation,
pSecurityDescriptor,
pnLength
);
return(status);
}
//
// This is a remote call - - use RPC
//
//
// Initialize the fields in the structure so that RPC does not
// attempt to marshall anything on input.
//
ADT_LOG0(TRACE,"Call Remote version (NetrpGetFileSecurity)\n");
returnedSD.Length = 0;
returnedSD.Buffer = NULL;
RpcTryExcept {
pReturnedSD = NULL;
status = NetrpGetFileSecurity (
pServerName,
pShareName,
pNewFileName,
RequestedInformation,
&pReturnedSD);
}
RpcExcept (1) {
//
// Get RPC exception code.
//
status = RpcExceptionCode();
}
RpcEndExcept
if (status == NO_ERROR) {
*pSecurityDescriptor = pReturnedSD->Buffer;
*pnLength = pReturnedSD->Length;
}
LocalFree(pServerName);
return (status);
}
DWORD
NetpSetFileSecurity (
IN LPWSTR lpFileName,
IN SECURITY_INFORMATION SecurityInformation,
IN PSECURITY_DESCRIPTOR pSecurityDescriptor
)
/*++
Routine Description:
This function can be used to set the security of a file or directory.
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.
lpFileName - A pointer to the name of the file or directory whose
security is being changed.
SecurityInformation - information describing the contents
of the Security Descriptor.
pSecurityDescriptor - A pointer to a well formed Security Descriptor.
Return Value:
NO_ERROR - The operation was successful.
This function can also return any error that SetFileSecurity can
return.
--*/
{
DWORD status= NO_ERROR;
NTSTATUS ntStatus=STATUS_SUCCESS;
ADT_SECURITY_DESCRIPTOR descriptorToPass;
DWORD nSDLength;
LPWSTR pNewFileName=NULL;
LPWSTR pServerName=NULL;
LPWSTR pShareName;
nSDLength = 0;
RpcTryExcept {
//
// Pick the server name out of the filename. Or translate the
// local drive name into a \\servername\sharename.
//
status = AdtParsePathName(lpFileName,&pNewFileName,&pServerName,&pShareName);
}
RpcExcept (1) {
//
// Get RPC exception code.
//
status = RpcExceptionCode();
}
RpcEndExcept
if (status != NO_ERROR) {
if (pServerName != NULL) {
LocalFree(pServerName);
}
return(status);
}
if (pServerName == NULL) {
//
// Call Locally and return result.
//
status = PrivateSetFileSecurity (
lpFileName,
SecurityInformation,
pSecurityDescriptor);
return(status);
}
//
// Call remotely
//
RpcTryExcept {
//
// Force the Security Descriptor to be self-relative if it is not
// already.
// The first call to RtlMakeSelfRelativeSD is used to determine the
// size.
//
ntStatus = RtlMakeSelfRelativeSD(
pSecurityDescriptor,
NULL,
&nSDLength);
if (ntStatus != STATUS_BUFFER_TOO_SMALL) {
status = RtlNtStatusToDosError(ntStatus);
goto CleanExit;
}
descriptorToPass.Length = nSDLength;
descriptorToPass.Buffer = LocalAlloc (LMEM_FIXED,nSDLength);
if (descriptorToPass.Buffer == NULL) {
status = ERROR_NOT_ENOUGH_MEMORY;
goto CleanExit;
}
//
// Make an appropriate self-relative security descriptor.
//
ntStatus = RtlMakeSelfRelativeSD(
pSecurityDescriptor,
descriptorToPass.Buffer,
&nSDLength);
if (ntStatus != NO_ERROR) {
LocalFree (descriptorToPass.Buffer);
status = RtlNtStatusToDosError(ntStatus);
goto CleanExit;
}
status = NetrpSetFileSecurity (
pServerName,
pShareName,
pNewFileName,
SecurityInformation,
&descriptorToPass);
LocalFree (descriptorToPass.Buffer);
CleanExit:
;
}
RpcExcept (1) {
//
// Get RPC exception code.
//
status = RpcExceptionCode();
}
RpcEndExcept
LocalFree(pServerName);
return (status);
}
DWORD
AdtParsePathName(
LPWSTR lpPathName,
LPWSTR *pNewFileName,
LPWSTR *pServerName,
LPWSTR *pShareName
)
/*++
Routine Description:
NOTE: This function allocates memory when the path contains a remote name.
The pShareName and pServerName strings are in a single buffer that is
to be freed at pServerName.
pNewFileName is NOT allocate by this routine. It points to a substring
within the passed in lpPathName.
Arguments:
lpPathName - This is a pointer to the filename-path string. It can have
any of the following formats:
x:\filedir\file.nam (remote)
\\myserver\myshare\filedir\file.nam (remote)
filedir\file.nam (local)
This could also just contain a directory name (and not a filename).
pNewFileName - This is a location where a pointer to the buffer
containing the file name can be placed. This will just contain the
filename or directory name relative to the root directory.
pServerName - This is a location where a pointer to the buffer containing
the server name can be placed. If this is for the local machine, then
a NULL will be placed in this location.
pShareName - This is a location where a pointer to a buffer containing
the share name can be placed. If this is for the local machine, then
a NULL will be placed in this location.
Return Value:
--*/
#define REMOTE_DRIVE 0
#define REMOTE_PATH 1
#define LOCAL 2
{
DWORD status = NO_ERROR;
NET_API_STATUS netStatus=NERR_Success;
WCHAR useName[4];
LPUSE_INFO_0 pUseInfo=NULL;
LPWSTR pNewPathName=NULL;
DWORD DeviceType = LOCAL;
LPWSTR pPrivateServerName;
LPWSTR pPrivateShareName;
LPWSTR pEnd;
DWORD numServerChars;
DWORD numChars;
WCHAR token;
*pServerName = NULL;
*pShareName = NULL;
//
// If the fileName starts with a drive letter, then use NetUseGetInfo
// to get the remote name.
//
if (lpPathName[1] == L':') {
if (((L'a' <= lpPathName[0]) && (lpPathName[0] <= L'z')) ||
((L'A' <= lpPathName[0]) && (lpPathName[0] <= L'Z'))) {
//
// This is in the form of a local device. Get the server/sharename
// associated with this device.
//
wcsncpy(useName, lpPathName, 2);
useName[2]=L'\0';
netStatus = NetUseGetInfo(
NULL, // server name
useName, // use name
0, // level
(LPBYTE *)&pUseInfo); // buffer
if (netStatus != NERR_Success) {
//
// if we get NERR_UseNotFound back, then this must be
// a local drive letter, and not a redirected one.
// In this case we return success.
//
if (netStatus == NERR_UseNotFound) {
return(NERR_Success);
}
return(netStatus);
}
DeviceType = REMOTE_DRIVE;
pNewPathName = pUseInfo->ui0_remote;
}
}
else {
if (wcsncmp(lpPathName,L"\\\\",2) == 0) {
DeviceType = REMOTE_PATH;
pNewPathName = lpPathName;
}
}
if (DeviceType != LOCAL) {
//
// Figure out how many characters for the server and share portion
// of the string.
// Add 2 characters for the leading "\\\\", allocate a buffer, and
// copy the characters.
//
numChars = 2;
pPrivateShareName = AdtFindNextToken(L'\\',pNewPathName+2,&numChars);
if (pPrivateShareName == NULL) {
status = ERROR_BAD_PATHNAME;
goto CleanExit;
}
numServerChars = numChars;
token = L'\\';
if (DeviceType == REMOTE_DRIVE) {
token = L'\0';
}
pEnd = AdtFindNextToken(token,pPrivateShareName+1,&numChars);
if (pEnd == NULL) {
status = ERROR_BAD_PATHNAME;
goto CleanExit;
}
//
// If this is a remotepath name, then the share name portion will
// also contain the '\' token. Remove this by decrementing the
// count.
//
if (DeviceType == REMOTE_PATH) {
numChars--;
}
pPrivateServerName = LocalAlloc(LMEM_FIXED,(numChars+1) * sizeof(WCHAR));
if (pPrivateServerName == NULL) {
status = GetLastError();
goto CleanExit;
}
//
// Copy the the "\\servername\sharename" to the new buffer and
// place NUL characters in place of the single '\'.
//
wcsncpy(pPrivateServerName, pNewPathName, numChars);
pPrivateShareName = pPrivateServerName + numServerChars;
*(pPrivateShareName -1) = L'\0'; // NUL terminate the server name
pPrivateServerName[ numChars ] = L'\0'; // NUL terminate the share name
if (DeviceType == REMOTE_PATH) {
*pNewFileName = pEnd;
}
else {
*pNewFileName = lpPathName+2;
}
*pServerName = pPrivateServerName;
*pShareName = pPrivateShareName;
}
CleanExit:
if (pUseInfo != NULL) {
NetApiBufferFree(pUseInfo);
}
return(status);
}
LPWSTR
AdtFindNextToken(
WCHAR Token,
LPWSTR pString,
LPDWORD pNumChars
)
/*++
Routine Description:
Finds the first occurance of Token in the pString.
Arguments:
Token - This is the unicode character that we are searching for in the
string.
pString - This is a pointer to the string in which the token is to be
found.
pNumChars - This is a pointer to a DWORD that will upon exit increment
by the number of characters found in the string (including the
token).
Return Value:
If the token is found this returns a pointer to the Token.
Otherwise, it returns NULL.
--*/
{
DWORD saveNum=*pNumChars;
while ((*pString != Token) && (*pString != L'\0')) {
pString++;
(*pNumChars)++;
}
if (*pString != Token) {
*pNumChars = saveNum;
return(NULL);
}
(*pNumChars)++;
return(pString);
}