/*++ 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 #include #include // needed for windows.h when I have nt.h #include #include // MIDL generated - includes windows.h & rpc.h #include #include #include // NERR_ error codes #include // LPUSE_INFO_0 #include // NetApiBufferFree #include // // 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); }