/*++ Copyright (c) 1991-92 Microsoft Corporation Module Name: WksUser.c Abstract: This file contains the RpcXlate code to handle the NetWkstaUserEnum API. Author: John Rogers (JohnRo) 19-Nov-1991 Environment: Portable to any flat, 32-bit environment. (Uses Win32 typedefs.) Requires ANSI C extensions: slash-slash comments, long external names. Revision History: 19-Nov-1991 JohnRo Implement remote NetWkstaUserEnum(). 21-Nov-1991 JohnRo Removed NT dependencies to reduce recompiles. 07-Feb-1992 JohnRo Use NetApiBufferAllocate() instead of private version. 14-Oct-1992 JohnRo RAID 9732: NetWkstaUserEnum to downlevel: wrong EntriesRead, Total? Set wkui1_oth_domains field. Use PREFIX_ equates. 03-Nov-1992 JohnRo RAID 10418: Fixed overactive assert when Status != NO_ERROR. Fixed memory leak if we couldn't allocate new buffer (old one got lost). Fixed memory leak if nobody is logged-on to target server. --*/ // These must be included first: #include // IN, DWORD, etc. #include // LM20_ equates, NET_API_STATUS, etc. // These may be included in any order: #include // WKSTA_INFO_0, MAX_WKSTA_ equates, etc. #include // NetApiBufferAllocate(). #include // ERROR_ and NERR_ equates. #include // DBGSTATIC, NetpKdPrint(()), FORMAT_ equates. #include // NetpCopyStringToBuffer(). #include // PREFIX_ equates. #include // IF_DEBUG(). #include // My prototypes, RxpGetWkstaInfoLevelEquivalent #include // STRLEN(). NET_API_STATUS RxNetWkstaUserEnum ( IN LPTSTR UncServerName, IN DWORD Level, OUT LPBYTE *BufPtr, IN DWORD PrefMaxSize, OUT LPDWORD EntriesRead, OUT LPDWORD TotalEntries, IN OUT LPDWORD ResumeHandle OPTIONAL ) /*++ Routine Description: RxNetWkstaUserEnum performs the same function as NetWkstaUserEnum, except that the server name is known to refer to a downlevel server. Arguments: (Same as NetWkstaUserEnum, except UncServerName must not be null, and must not refer to the local computer.) Return Value: (Same as NetWkstaUserEnum.) --*/ { LPBYTE NewInfo = NULL; // Buffer to be returned to caller. DWORD NewFixedSize; DWORD NewStringSize; LPWKSTA_INFO_1 OldInfo = NULL; const DWORD OldLevel = 1; NET_API_STATUS Status; UNREFERENCED_PARAMETER(PrefMaxSize); UNREFERENCED_PARAMETER(ResumeHandle); IF_DEBUG(WKSTA) { NetpKdPrint(( PREFIX_NETAPI "RxNetWkstaUserEnum: starting, server=" FORMAT_LPTSTR ", lvl=" FORMAT_DWORD ".\n", UncServerName, Level)); } // // Error check DLL stub and the app. // NetpAssert(UncServerName != NULL); if (BufPtr == NULL) { Status = ERROR_INVALID_PARAMETER; goto Cleanup; } *BufPtr = NULL; // assume error; it makes error handlers easy to code. // This also forces possible GP fault before we allocate memory. // // Compute size of wksta user structure (including strings) // switch (Level) { case 0 : NewFixedSize = sizeof(WKSTA_USER_INFO_0); NewStringSize = (LM20_UNLEN+1) * sizeof(TCHAR); break; case 1 : NewFixedSize = sizeof(WKSTA_USER_INFO_1); NewStringSize = (LM20_UNLEN+1 + LM20_DNLEN+1 + MAX_PATH+1) * sizeof(TCHAR); break; default: Status = ERROR_INVALID_LEVEL; goto Cleanup; } // // Actually remote the API, which will get back the (old) info level // data in native format. // Status = RxpWkstaGetOldInfo( UncServerName, // Required, with \\name. OldLevel, (LPBYTE *) & OldInfo); // buffer (alloc and set this ptr) NetpAssert( Status != ERROR_MORE_DATA ); NetpAssert( Status != NERR_BufTooSmall ); if (Status == NERR_Success) { NetpAssert( OldInfo != NULL ); if ( (OldInfo->wki1_username == NULL) || ( (*(OldInfo->wki1_username)) == (TCHAR) '\0')) { // // Nobody logged on. // *BufPtr = NULL; *EntriesRead = 0; *TotalEntries = 0; } else { // These variables are used by the COPY_STRING macro. LPBYTE NewFixedEnd; LPTSTR NewStringTop; LPWKSTA_INFO_1 src = (LPVOID) OldInfo; LPWKSTA_USER_INFO_1 dest; // superset info level // // Allocate memory for native version of new info, which we'll // return to caller. (Caller must free it with NetApiBufferFree.) // Status = NetApiBufferAllocate( NewFixedSize + NewStringSize, (LPVOID *) & NewInfo); if (Status != NERR_Success) { goto Cleanup; } NetpAssert( NewInfo != NULL ); IF_DEBUG(WKSTA) { NetpKdPrint(( PREFIX_NETAPI "RxNetWkstaUserEnum: allocated new buffer at " FORMAT_LPVOID "\n", (LPVOID) NewInfo )); } // Set up pointers for use by NetpCopyStringsToBuffer. dest = (LPVOID) NewInfo; NewStringTop = (LPTSTR) NetpPointerPlusSomeBytes( dest, NewFixedSize+NewStringSize); NewFixedEnd = NetpPointerPlusSomeBytes(NewInfo, NewFixedSize); #define COPY_STRING( InField, OutField ) \ { \ BOOL CopyOK; \ NetpAssert( dest != NULL); \ NetpAssert( src != NULL); \ NetpAssert( (src -> InField) != NULL); \ CopyOK = NetpCopyStringToBuffer ( \ src->InField, \ STRLEN(src->InField), \ NewFixedEnd, \ & NewStringTop, \ & dest->OutField); \ NetpAssert(CopyOK); \ } // // Downlevel server, so one user is logged on. // *EntriesRead = 1; *TotalEntries = 1; // // Copy/convert data from OldInfo to NewInfo. // // User name is only field in level 0. COPY_STRING( wki1_username, wkui1_username ); if (Level == 1) { // Do fields unique to level 1. COPY_STRING( wki1_logon_domain, wkui1_logon_domain ); COPY_STRING( wki1_oth_domains, wkui1_oth_domains ); COPY_STRING( wki1_logon_server, wkui1_logon_server ); } NetpAssert( Level < 2 ); // Add code here someday? *BufPtr = NewInfo; } } else { // An error from RxpWkstaGetOldInfo()... NetpAssert( OldInfo == NULL ); } Cleanup: if (OldInfo != NULL) { (void) NetApiBufferFree( OldInfo ); } return (Status); } // RxNetWkstaUserEnum