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