562 lines
14 KiB
C
562 lines
14 KiB
C
|
/*++
|
|||
|
|
|||
|
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);
|
|||
|
}
|
|||
|
|