/*++ Copyright (c) 1991-1993 Microsoft Corporation Module Name: rxaccess.c Abstract: Contains down-level remoted NetAccess routines: RxNetAccessAdd RxNetAccessDel RxNetAccessEnum RxNetAccessGetInfo RxNetAccessGetUserPerms RxNetAccessSetInfo (GetAccessDescriptors) (MapResourceName) Author: Richard Firth (rfirth) 20-May-1991 Environment: Win-32/flat address space Notes: Routines in this module assume that caller-supplied parameters have already been verified. No effort is made to further check the veracity of parms. Any actions causing exceptions must be trapped at a higher level. This applies to ALL parameters - strings, pointers, buffers, etc. Revision History: 20-May-1991 RFirth Created 13-Sep-1991 JohnRo Use correct typedef for descriptors (LPDESC, not LPTSTR). Made changes as suggested by PC-LINT. 16-Sep-1991 JohnRo Use DBGSTATIC for nonexported routines. 25-Sep-1991 JohnRo Correct UNICODE use. (Use POSSIBLE_WCSSIZE() for LPWSTR types.) Fixed MIPS build error. 21-Nov-1991 JohnRo Removed NT dependencies to reduce recompiles. 05-Dec-1991 RFirth Enum returns in TotalEntries (or EntriesLeft) the number of items to be enumerated BEFORE this call. Used to be number left after this call 07-Feb-1992 JohnRo Avoid compiler warnings. Use NetApiBufferAllocate() instead of private version. 11-Jan-1993 JohnRo Made changes suggested by PC-LINT 5.0 30-Apr-1993 JohnRo Fix NET_API_FUNCTION references. (NetAccess routines are just #define'd as RxNetAccess routines in lmaccess.h, so we need NET_API_FUNCTION here too!) --*/ #include #include #include "downlevl.h" #include // Don't complain about "unneeded" includes of these files: /*lint -efile(764,rxaccess.h) */ /*lint -efile(766,rxaccess.h) */ #include "rxaccess.h" #include // // local prototypes // DBGSTATIC void GetAccessDescriptors( IN DWORD Level, OUT LPDESC* pDesc16, OUT LPDESC* pDesc32, OUT LPDESC* pDescSmb, OUT LPDWORD pDataSize ); DBGSTATIC BOOL MapResourceName( IN LPTSTR LocalName, OUT LPTSTR RemoteName ); // // routines // NET_API_STATUS NET_API_FUNCTION RxNetAccessAdd( IN LPCWSTR ServerName, IN DWORD Level, IN LPBYTE Buffer, OUT LPDWORD ParmError OPTIONAL ) /*++ Routine Description: Add a user account to a remote down-level server database. Buffer contains an ACCESS_INFO_1 structure followed by a list of ACCESS_LIST structures Assumes: 1. all parameters already verified at higher level Arguments: ServerName - at which server to perform this request Level - of information being supplied. Must be 1 Buffer - pointer to user's buffer containing ACCESS_INFO_1 struct ParmError - optional pointer to place to deposit parameter error Return Value: NET_API_STATUS: Success - NERR_Success Failure - ERROR_INVALID_PARAMETER One of the fields in the ACCESS_INFO_1 structure may blow a down-level limit --*/ { NET_API_STATUS rc; DWORD badparm; DWORD buflen; DWORD count; DWORD len; PACCESS_LIST aclptr; TCHAR mappedName[MAX_PATH]; LPACCESS_INFO_1 infoPtr = NULL; // // set up default for ParmError and probe writability if value given // if (ParmError == NULL) { ParmError = &badparm; } *ParmError = PARM_ERROR_UNKNOWN; // // Don't allow null servername // if ( ServerName == NULL || *ServerName == L'\0' ) { return(NERR_InvalidComputer); } // // Down-level servers only support 1 level of Add information - 1. If this // isn't it then throw out this request without further ado // if (Level != 1) { return ERROR_INVALID_LEVEL; } // // calculate the size of the buffer we are passing in (32-bit size) // // // How to calculate the maximum for the resource name (PATHLEN?) // try to blow up a down-level server by submitting eg 4K string // buflen = sizeof(ACCESS_INFO_1); // fixed part len = POSSIBLE_STRLEN(((ACCESS_INFO_1*)Buffer)->acc1_resource_name); if (!len) { *ParmError = ACCESS_RESOURCE_NAME_INFOLEVEL; return ERROR_INVALID_PARAMETER; } buflen += len; // // loop through the list of ACLs, checking the user/group name against the // down-level limit // // // STRSIZE returns the number of characters, so all // we need is count * sizeof(16-bit ACCESS_LIST structure) + sizeof(16-bit // ACCESS_INFO_1 structure) + STRSIZE(resource name) // aclptr = (PACCESS_LIST)(Buffer + sizeof(ACCESS_INFO_1)); for (count = ((ACCESS_INFO_1*)Buffer)->acc1_count; count; --count) { buflen += sizeof(ACCESS_LIST); // fixed part of access list if (len = POSSIBLE_STRLEN(aclptr->acl_ugname)) { if (len > LM20_UNLEN) { *ParmError = ACCESS_ACCESS_LIST_INFOLEVEL; return ERROR_INVALID_PARAMETER; } } } // // if we need to map the resource name then we have to create a new buffer // for the access list // if (MapResourceName(((LPACCESS_INFO_1)Buffer)->acc1_resource_name, mappedName)) { infoPtr = (LPACCESS_INFO_1)NetpMemoryAllocate(buflen); if (infoPtr == NULL) { return ERROR_NOT_ENOUGH_MEMORY; } RtlMoveMemory(infoPtr, Buffer, buflen); infoPtr->acc1_resource_name = mappedName; Buffer = (LPBYTE)infoPtr; } rc = RxRemoteApi(API_WAccessAdd, // API # (LPWSTR) ServerName, // where it will run REMSmb_NetAccessAdd_P, // parameter descriptor REM16_access_info_1, // Data descriptor/16-bit REM32_access_info_1, // Data descriptor/32-bit REMSmb_access_info_1, // Data descriptor/SMB REM16_access_list, // Aux descriptor/16-bit REM32_access_list, // Aux descriptor/32-bit REMSmb_access_list, // Aux descriptor/SMB FALSE, // this call needs user to be logged on 1, // level. Since there's only 1 push immediate Buffer, // caller's share_info_1 struct buflen // parameter supplied by us ); // // if we mapped the resource name free up the buffer // if (infoPtr) { NetpMemoryFree(infoPtr); } // // we didn't expect to get any data in return. Just pass the return // code back to our caller // return rc; } //NET_API_STATUS //RxNetAccessCheck( // ) //{ // /** CANNOT BE REMOTED **/ //} NET_API_STATUS NET_API_FUNCTION RxNetAccessDel( IN LPCWSTR ServerName, IN LPCWSTR ResourceName ) /*++ Routine Description: Remotely delete a resource's Access Control List entry from a down-level server database. The caller must have Admin privilege to successfully execute this routine Arguments: ServerName - at which server to perform this request ResourceName- name of thing to delete Return Value: NET_API_STATUS: Success = NERR_Success Failure = --*/ { TCHAR mappedName[MAX_PATH]; // // Don't allow null servername // if ( ServerName == NULL || *ServerName == L'\0' ) { return(NERR_InvalidComputer); } // // The ResourceName parameter must be a non-NUL(L) string // if (!VALID_STRING(ResourceName)) { return ERROR_INVALID_PARAMETER; } if (MapResourceName((LPWSTR)ResourceName, mappedName)) { ResourceName = mappedName; } return RxRemoteApi(API_WAccessDel, // API # (LPWSTR) ServerName, // where it will run REMSmb_NetAccessDel_P, // parameter descriptor NULL, // Data descriptor/16-bit NULL, // Data descriptor/32-bit NULL, // Data descriptor/SMB NULL, // Aux descriptor/16-bit NULL, // Aux descriptor/32-bit NULL, // Aux descriptor/SMB FALSE, // this call needs user to be logged on ResourceName ); } NET_API_STATUS NET_API_FUNCTION RxNetAccessEnum( IN LPCWSTR ServerName, IN LPCWSTR BasePath, IN DWORD Recursive, IN DWORD Level, OUT LPBYTE* Buffer, IN DWORD PrefMaxLen, OUT LPDWORD EntriesRead, OUT LPDWORD EntriesLeft, IN OUT LPDWORD ResumeHandle OPTIONAL ) /*++ Routine Description: Retrieves access info from a remote down-level server NOTE: Assumes that calling routine (NetAccessEnum) has validated the caller's pointers: Buffer, EntriesRead and EntriesLeft are all valid, writable pointers Arguments: ServerName - at which server to perform this request BasePath - for the resource(s) Recursive - flag: 0 = return information only for resources identified in BasePath. !0 = return information for all resources under BasePath Level - of information requested. Must be zero Buffer - pointer to place to store pointer to returned buffer PrefMaxLen - caller's preferred maximum buffer size EntriesRead - pointer to returned number of enum elements in buffer EntriesLeft - pointer to returned total enum elements available to the caller ResumeHandle- optional pointer to handle for resuming interrupted searches Return Value: NET_API_STATUS: Success = NERR_Success Failure = --*/ { NET_API_STATUS rc; LPDESC pDesc16; LPDESC pDesc32; LPDESC pDescSmb; LPBYTE ourbuf; DWORD infolen, entries_read, total_avail; TCHAR mappedName[MAX_PATH]; UNREFERENCED_PARAMETER(PrefMaxLen); // // Don't allow null servername // if ( ServerName == NULL || *ServerName == L'\0' ) { return(NERR_InvalidComputer); } // // Set the number of entries read and total available to sensible defaults. // Side effect of testing writability of supplied parameters // *Buffer = NULL; *EntriesRead = 0; *EntriesLeft = 0; // // Check for invalid parameters. // NB Assumes that DWORD is unsigned // NB Assume that calling routine (ie NetAccessEnum) has validated the // caller's pointers // Ensure that: // Level is not >1 // ResumeHandle is NULL or a pointer to NULL // if (!NULL_REFERENCE(ResumeHandle)) { return ERROR_INVALID_PARAMETER; } if (Level > 1) { return ERROR_INVALID_LEVEL; } // // Decide which descriptors to use, based on the Level parameter // GetAccessDescriptors(Level, &pDesc16, &pDesc32, &pDescSmb, &infolen); // // allocate the buffer in which to return the enumerated info, using the // supplied size criteria. If we fail then return the error code to the // caller // ourbuf = NULL; if (MapResourceName((LPWSTR)BasePath, mappedName)) { BasePath = mappedName; } rc = RxRemoteApi(API_WAccessEnum, // API number (LPWSTR) ServerName, // where it will run REMSmb_NetAccessEnum_P, // parameter descriptor pDesc16, // Data descriptor/16-bit pDesc32, // Data descriptor/32-bit pDescSmb, // Data descriptor/SMB REM16_access_list, // Aux descriptor/16-bit REM32_access_list, // Aux descriptor/32-bit REMSmb_access_list, // Aux descriptor/SMB ALLOCATE_RESPONSE, BasePath, // where to start Recursive, // get tree or not Level, // level parameter &ourbuf, 65535, &entries_read, // pointer to entries read variable &total_avail // pointer to total entries variable ); if (rc) { if (ourbuf != NULL) { (void) NetApiBufferFree(ourbuf); } } else { *Buffer = ourbuf; *EntriesRead = entries_read; *EntriesLeft = total_avail; } return rc; } NET_API_STATUS NET_API_FUNCTION RxNetAccessGetInfo( IN LPCWSTR ServerName, IN LPCWSTR ResourceName, IN DWORD Level, OUT LPBYTE* Buffer ) /*++ Routine Description: Retrieves access information about a specific resource from a remote down-level server Arguments: ServerName - at which server to perform this request ResourceName- name of resource we are trying to get info for Level - of information required: 0 or 1 Buffer - pointer to place to store address of buffer containing requested information Return Value: NET_API_STATUS: Success = NERR_Success Failure = ERROR_INVALID_LEVEL Specified Level parameter can not be accepted ERROR_INVALID_PARAMETER ResourceName or Buffer not valid --*/ { NET_API_STATUS rc; LPDESC pDesc16; // pointer to 16-bit info descriptor for RxRemoteApi LPDESC pDesc32; // pointer to 32-bit info descriptor for RxRemoteApi LPDESC pDescSmb; // pointer to SMB info descriptor for RxRemoteApi LPDESC pAuxDesc16; // pointer to 16-bit aux info descriptor for RxRemoteApi LPDESC pAuxDesc32; // pointer to 32-bit aux info descriptor for RxRemoteApi LPDESC pAuxDescSmb; // pointer to SMB aux info descriptor for RxRemoteApi LPBYTE ourbuf; // buffer we allocate, fill, and give to the caller DWORD total_avail; // 32-bit total available if supplied buffer too small DWORD infolen; // 32-bit place to store size of required buffer TCHAR mappedName[MAX_PATH]; // // Don't allow null servername // if ( ServerName == NULL || *ServerName == L'\0' ) { return(NERR_InvalidComputer); } // // Perform parameter validity checks: // Level must be in range 0 <= Level <= 1 // ResourceName must be non-NULL pointer to non-NULL string // Buffer must be non-NULL pointer // NB. Assumes DWORD unsigned // if (Level > 1) { return ERROR_INVALID_LEVEL; } if (NULL_REFERENCE(ResourceName) || !Buffer) { return ERROR_INVALID_PARAMETER; } // // set Buffer to default value and catch any bad address errors // *Buffer = NULL; // // Work out the descriptor and buffer size requirements based on the // requested level // GetAccessDescriptors(Level, &pDesc16, &pDesc32, &pDescSmb, &infolen); if (Level == 1) { pAuxDesc16 = REM16_access_list; pAuxDesc32 = REM32_access_list; pAuxDescSmb = REMSmb_access_list; } else { pAuxDesc16 = NULL; pAuxDesc32 = NULL; pAuxDescSmb = NULL; } // // get a better way to allocate the buffer length // infolen = 4096; // // allocate a buffer size required to fit in 1 structure at info level // requested. If the allocation fails then return the error // if (rc = NetApiBufferAllocate(infolen, (LPVOID *) &ourbuf)) { return rc; } if (MapResourceName((LPWSTR)ResourceName, mappedName)) { ResourceName = mappedName; } rc = RxRemoteApi(API_WAccessGetInfo, (LPWSTR) ServerName, // where it will happen REMSmb_NetAccessGetInfo_P, // parameter descriptor pDesc16, // Data descriptor/16-bit pDesc32, // Data descriptor/32-bit pDescSmb, // Data descriptor/SMB pAuxDesc16, // Aux descriptor/16-bit pAuxDesc32, // Aux descriptor/32-bit pAuxDescSmb, // Aux descriptor/SMB FALSE, // this call needs user to be logged on ResourceName, // pointer to thing to get info on Level, // level of info ourbuf, // pointer to buffer sourced by us infolen, // size of our sourced buffer &total_avail // pointer to total available ); // // If the remote NetShareGetInfo call succeeded then give the returned // buffer to the caller // if (rc == NERR_Success) { *Buffer = ourbuf; } else { // // if we didn't record a success then free the buffer previously allocated // (void) NetApiBufferFree(ourbuf); } return rc; } NET_API_STATUS NET_API_FUNCTION RxNetAccessGetUserPerms( IN LPCWSTR ServerName, IN LPCWSTR UserName, IN LPCWSTR ResourceName, OUT LPDWORD Perms ) /*++ Routine Description: Retrieves the access information for a particular resource for a specified user or group Arguments: ServerName - at which server to perform this request UserName - name of user or group which can access resource ResourceName- name of resource to get information for Perms - pointer to place to store permissions Return Value: NET_API_STATUS: Success = NERR_Success Failure = ERROR_INVALID_PARAMETER (return code from remoted NetAccessGetUserPerms) --*/ { TCHAR mappedName[MAX_PATH]; // // Don't allow null servername // if ( ServerName == NULL || *ServerName == L'\0' ) { return(NERR_InvalidComputer); } // // set *Perms to default value and verify writability of Perms // *Perms = 0; // // Perform parameter validity checks: // UserName must be non-NULL pointer to non-NULL string // ResourceName must be non-NULL pointer to non-NULL string // Perms must be non-NULL pointer // if (!VALID_STRING(UserName) || !VALID_STRING(ResourceName)) { return ERROR_INVALID_PARAMETER; } if (MapResourceName( (LPWSTR) ResourceName, mappedName)) { ResourceName = mappedName; } return RxRemoteApi(API_WAccessGetUserPerms, // API # (LPWSTR) ServerName, // where it will run REMSmb_NetAccessGetUserPerms_P, // parameter descriptor NULL, // Data descriptor/16-bit NULL, // Data descriptor/32-bit NULL, // Data descriptor/SMB NULL, // Aux descriptor/16-bit NULL, // Aux descriptor/32-bit NULL, // Aux descriptor/SMB FALSE, // this call needs user to be logged on UserName, // for whom the bells toll ResourceName, // pointer to thing to get info on Perms // pointer to returned permissions ); } NET_API_STATUS NET_API_FUNCTION RxNetAccessSetInfo( IN LPCWSTR ServerName, IN LPCWSTR ResourceName, IN DWORD Level, IN LPBYTE Buffer, OUT LPDWORD ParmError OPTIONAL ) /*++ Routine Description: Changes the access control information for a resource at a specific down-level remote server Arguments: ServerName - at which server to perform this request ResourceName- name of resource to change access information Level - level of information buffer being supplied - 1 or ACCESS_ATTR_INFOLEVEL Buffer - pointer to buffer containing information ParmError - optional pointer to place to store parameter error Return Value: NET_API_STATUS: Success = NERR_Success Failure = --*/ { DWORD parmnum; TCHAR mappedName[MAX_PATH]; UNREFERENCED_PARAMETER(ParmError); // // Don't allow null servername // if ( ServerName == NULL || *ServerName == L'\0' ) { return(NERR_InvalidComputer); } // // Perform parameter validity checks: // Level must be 1 or 1002 // ResourceName must be non-NULL pointer to non-NULL string // Buffer must be non-NULL // ParmNum must be in range // NB. Does not assume that DWORD is unsigned // if ((Level != 1) && (Level != ACCESS_ATTR_INFOLEVEL)) { return ERROR_INVALID_LEVEL; } if (!VALID_STRING(ResourceName) || !Buffer) { return ERROR_INVALID_PARAMETER; } // // convert the NT level information to down-level. Level must be 1 at down- // level server. ParmNum can be PARMNUM_ALL (0) or ACCESS_ATTR_PARMNUM (2) // Note that the size of the data being passed to the down-level server will // be calculated in RxRemoteApi. We do not need to pass in a valid buffer // length, although the parameter string (REMSmb_NetAccessSetInfo_P) has a // 'T' descriptor saying this is what the server is getting. We just need // a place-holder on the stack, hence 0 // parmnum = (Level == 1) ? PARMNUM_ALL : ACCESS_ATTR_PARMNUM; if (MapResourceName( (LPWSTR) ResourceName, mappedName)) { ResourceName = mappedName; } return RxRemoteApi( API_WAccessSetInfo, // API # (LPWSTR) ServerName, // where it will run REMSmb_NetAccessSetInfo_P, // parameter descriptor REM16_access_info_1_setinfo, // Data descriptor/16-bit REM32_access_info_1_setinfo, // Data descriptor/32-bit REMSmb_access_info_1_setinfo, // Data descriptor/SMB REM16_access_list, // Aux descriptor/16-bit REM32_access_list, // Aux descriptor/32-bit REMSmb_access_list, // Aux descriptor/SMB FALSE, // this call needs user to be logged on ResourceName, // pointer to thing to set info on 1, // level of info Buffer, // pointer to buffer sourced by caller 0, // size of our buffer IGNORED! // // in this case, the field index and parm num are the // same value // MAKE_PARMNUM_PAIR(parmnum, parmnum) ); } DBGSTATIC void GetAccessDescriptors( IN DWORD level, OUT LPDESC* pDesc16, OUT LPDESC* pDesc32, OUT LPDESC* pDescSmb, OUT LPDWORD pDataSize ) /*++ Routine Description: A routinette to return pointers to the 16- and 32-bit access info structure descriptor strings for each level (0, 1). Also returns the size of the 16-bit structure Arguments: level - of information to be returned pDesc16 - pointer to returned 16-bit descriptor string pDesc32 - pointer to returned 32-bit descriptor string pDescSmb - pointer to returned SMB descriptor string pDataSize - pointer to returned size of 16-bit structure Return Value: None. --*/ { switch (level) { case 0: *pDesc16 = REM16_access_info_0; *pDesc32 = REM32_access_info_0; *pDescSmb = REMSmb_access_info_0; *pDataSize = sizeof(ACCESS_INFO_0); break; case 1: *pDesc16 = REM16_access_info_1; *pDesc32 = REM32_access_info_1; *pDescSmb = REMSmb_access_info_1; *pDataSize = sizeof(ACCESS_INFO_1); break; #if DBG // // just to be completely paranoid... // default: NetpKdPrint(("%s.%u Unknown Level parameter: %u\n", __FILE__, __LINE__, level)); #endif } } DBGSTATIC BOOL MapResourceName( IN LPTSTR LocalName, OUT LPTSTR RemoteName ) /*++ Routine Description: Maps a local resource name to the remote name. Only applies to resource names which start with a drive specification "[A-Z]:" and then only if the drive letter specifies a remoted drive ASSUMES: RemoteName is large enough to hold the mapped name Arguments: LocalName - pointer to name of local resource specification RemoteName - pointer to buffer which will receive mapped resource name Return Value: BOOL TRUE - name was mapped FALSE - name not mapped --*/ { TCHAR driveName[3]; NET_API_STATUS status; LPUSE_INFO_0 lpUse; LPTSTR resourceName; BOOL mapped; DWORD i; if (LocalName[1] != TCHAR_COLON) { (VOID) STRCPY(RemoteName, LocalName); return FALSE; } driveName[0] = LocalName[0]; driveName[1] = TCHAR_COLON; driveName[2] = TCHAR_EOS; // // map the local drive name to the UNC name. If NetUseGetInfo returns // any error, then don't map // status = NetUseGetInfo(NULL, driveName, 0, (LPBYTE*)(LPVOID)&lpUse); if (status == NERR_Success) { (VOID) STRCPY(RemoteName, lpUse->ui0_remote); resourceName = LocalName + 2; // // if the rest of the resource name does not start with a path // separator (it should!) then add one // if (!IS_PATH_SEPARATOR(*resourceName) && *resourceName) { (VOID) STRCAT(RemoteName, (LPTSTR) TEXT("\\")); } (VOID) NetApiBufferFree((LPBYTE)lpUse); mapped = TRUE; } else { *RemoteName = TCHAR_EOS; resourceName = LocalName; mapped = FALSE; } // // concatenate the rest of the resource name to the UNC. If NetUseGetInfo // failed then the UNC is a NULL string and the rest of the resource name // is LocalName // (VOID) STRCAT(RemoteName, resourceName); // // strip trailing path separators // for (i = STRLEN(RemoteName) - 1; IS_PATH_SEPARATOR(RemoteName[i]); --i) { ; } RemoteName[i+1] = TCHAR_EOS; return mapped; }