2025-04-27 07:49:33 -04:00

1217 lines
35 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/******************************************************************\
* Microsoft Windows NT *
* Copyright(c) Microsoft Corp., 1992 *
\******************************************************************/
/*++
Module Name:
USERAPI.C
Description:
This module contains code for all the RASADMIN APIs
that require RAS information from the UAS.
// RasAdminUserEnum
RasAdminGetUserAccountServer
RasAdminUserSetInfo
RasAdminUserGetInfo
RasAdminGetErrorString
Author:
Janakiram Cherala (RamC) July 6,1992
Revision History:
Feb 1,1996 RamC Changes to export these APIs to 3rd parties. These APIs
are now part of RASSAPI.DLL. Added a couple new routines
and renamed some. RasAdminUserEnum is not exported any more.
June 8,1993 RamC Changes to RasAdminUserEnum to speed up user enumeration.
May 13,1993 AndyHe Modified to coexist with other apps using user parms
Mar 16,1993 RamC Change to speed up User enumeration. Now, when
RasAdminUserEnum is invoked, only the user name
information is returned. RasAdminUserGetInfo should
be invoked to get the Ras permissions and Callback
information.
Aug 25,1992 RamC Code review changes:
o changed all lpbBuffers to actual structure
pointers.
o changed all LPTSTR to LPWSTR
o Added a new function RasPrivilegeAndCallBackNumber
July 6,1992 RamC Begun porting from RAS 1.0 (Original version
written by Narendra Gidwani - nareng)
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <ntlsa.h>
#include <ntsam.h>
#include <windows.h>
#include <lm.h>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <malloc.h>
#include <raserror.h>
#include <rassapi.h>
#include <rassapip.h>
#include <util.h> // for Compress & Decompress fns.
#include <usrparms.h> // for UP_CLIENT_DIAL
#include <dsgetdc.h>
#include "sdebug.h" // this is required for the global alloc/free wrapper
DWORD APIENTRY
MprAdminUserGetInfo(
IN const WCHAR * lpszServer,
IN const WCHAR * lpszUser,
IN DWORD dwLevel,
OUT LPBYTE lpbBuffer
);
DWORD APIENTRY
MprAdminUserSetInfo(
IN const WCHAR * lpszServer,
IN const WCHAR * lpszUser,
IN DWORD dwLevel,
IN const LPBYTE lpbBuffer
);
// constants used to increase the number of users enumerated.
#define USERS_INITIAL_COUNT 0x00200 // 512
#define USERS_MAX_COUNT 0X01000 // 4 K
#define BYTES_INITIAL_COUNT 0x03FFF // 16 K
#define BYTES_MAX_COUNT 0x1FFFF // 128 K
/* Forward declarations of private functions */
BOOL CheckIfNT(const WCHAR * lpszServer);
VOID ConvertUnicodeStringToWcs(WCHAR *szUserName, PUNICODE_STRING pUnicode);
DWORD GetAccountDomain( PUNICODE_STRING Server,PUNICODE_STRING Domain);
NTSTATUS OpenLsa(PUNICODE_STRING pSystem, PLSA_HANDLE phLsa );
#if 0
DWORD APIENTRY
RasAdminUserEnum(
IN const WCHAR * lpszServer,
OUT RAS_USER_1 **ppRasUser1,
OUT DWORD* pcEntriesRead
)
/*++
Routine Description:
This routine enumerates all the users in the user database for
a particular server.
Arguments:
lpszServer name of the server which has the user database,
eg., "\\\\UASSRVR" (the server must be one on which
the UAS can be changed i.e., the name returned by
RasAdminGetUserAccountServer).
ppRasUser1 pointer to a pointer to a buffer in which user information
is returned. The returned info is an array of
RAS_USER_1 structures. This routine allocates the buffer.
Invoke the RasAdminBufferFree routine to free the allocated
memory.
NOTE: We only return the user name information, though
we continue to return an array of RAS_USER_1 structures.
This was done for speeding up user enumeration. Call
RasAdminUserGetInfo to get Ras Access and Callback info
for the required user.
pcEntriesRead The number of users enumerated is returned via this
pointer. It is valid only if the return value is
either ERROR_SUCCESS or ERROR_MORE_DATA.
Return Value:
ERROR_SUCCESS if successful
One of the following non-zero error codes indicating failure:
error codes from NetUserEnum indicating failure.
ERROR_NOT_ENOUGH_MEMORY indicating insert_list_head failed due to
lack of memory.
Revision History:
June 5 1993 RamC Changed the routine to allocate memory on behalf
of the caller and eliminated some parameters.
Feb 18,1993 RamC changed the cbUserInfo calculation to include
Max of two buffers to make sure we have enough
space for the number of users.
Commented out printing names - should speed up
name enumeration.
--*/
{
PUSER_INFO_1 pUserInfo;
PUSER_INFO_1 pUserInfoPtr;
DWORD dwIndex;
NET_API_STATUS dwRetCode;
NTSTATUS Status = 0;
BOOL bMoreData = FALSE;
DWORD cHandle = 0;
DWORD cEntriesRead = 0;
DWORD cTotalAvail = 0;
RAS_USER_1 * pRasUser1Ptr;
HANDLE hmem, hnewmem;
// nothing read yet
*pcEntriesRead = 0;
// we first allocate 1 byte and then resize the buffer to fit the
// number of entries read. We could have allocated 0 bytes, but when
// the GMEM_MOVEABLE flag is specified, the block of memory is marked
// as discarded and we can't lock the memory block nor can we resize it.
hmem = GlobalAlloc(GMEM_MOVEABLE, 1);
if(!hmem)
{
DbgPrint("Could not allocate memory for *ppRasUser1.\n");
return GetLastError();
}
*ppRasUser1 = (RAS_USER_1*) GlobalLock(hmem);
if(!*ppRasUser1)
{
DbgPrint("Could not lock memory segment for *ppRasUser1.\n");
return GetLastError();
}
if (!CheckIfNT(lpszServer))
{
while(1)
{
bMoreData = FALSE;
if( dwRetCode = NetUserEnum((WCHAR *)lpszServer,
1, // info level
FILTER_NORMAL_ACCOUNT,
(LPBYTE *)&pUserInfo, // buffer
(DWORD)-1, // prefered max len
&cEntriesRead,
&cTotalAvail,
&cHandle // resume handle
))
{
if ( dwRetCode != ERROR_MORE_DATA)
{
DbgPrint("RasAdminUserEnum: NetUserEnum error %d\n", dwRetCode);
return( dwRetCode);
}
bMoreData = TRUE;
}
GlobalUnlock(hmem);
hnewmem = GlobalReAlloc(hmem,
((*pcEntriesRead) + cEntriesRead) *
sizeof(RAS_USER_1),
GMEM_MOVEABLE);
if(!hnewmem)
{
DWORD LastError = GetLastError();
DbgPrint("Could not reallocate memory for *ppRasUser1.\n");
return (LastError);
}
hmem = hnewmem;
*ppRasUser1 = (RAS_USER_1*) GlobalLock(hmem);
if(!*ppRasUser1)
{
DWORD LastError = GetLastError();
DbgPrint("Could not reallocate memory for *ppRasUser1.\n");
if( pUserInfo )
NetApiBufferFree(pUserInfo);
return (LastError);
}
pRasUser1Ptr = (*ppRasUser1) + (*pcEntriesRead);
(*pcEntriesRead) += cEntriesRead;
for(dwIndex = cEntriesRead, pUserInfoPtr = pUserInfo;
dwIndex > 0;
pRasUser1Ptr++, pUserInfoPtr++, dwIndex-- )
{
memset(&(pRasUser1Ptr->rasuser0), '\0', sizeof(RAS_USER_0));
pRasUser1Ptr->szUser = (WCHAR*)
GlobalAlloc(GMEM_FIXED,
sizeof(TCHAR) *
lstrlen(pUserInfoPtr->usri1_name)+
sizeof(TCHAR));
if( !pRasUser1Ptr->szUser)
{
NetApiBufferFree(pUserInfo);
GlobalUnlock(hmem);
GlobalFree(hmem);
return GetLastError();
}
lstrcpy((LPTSTR) pRasUser1Ptr->szUser, (LPCTSTR) pUserInfoPtr->usri1_name);
}
if( pUserInfo)
NetApiBufferFree(pUserInfo);
if(!bMoreData)
break;
}
}
else // this is an NT server - use SAM calls
{
DWORD err;
OBJECT_ATTRIBUTES ObjectAttributes;
SECURITY_QUALITY_OF_SERVICE SecurityQos;
SAM_HANDLE SamHandle = NULL;
SAM_HANDLE DomainHandle = NULL;
UNICODE_STRING Domain;
UNICODE_STRING Server;
PSID DomainSid = NULL;
UINT cUsersPerRequest;
ULONG cbBytesRequested;
ULONG TotalAvailable, TotalReturned, i;
PDOMAIN_DISPLAY_USER SortedUsers;
//
// Setup ObjectAttributes for SamConnect call.
//
InitializeObjectAttributes(&ObjectAttributes, NULL, 0, 0, NULL);
ObjectAttributes.SecurityQualityOfService = &SecurityQos;
SecurityQos.Length = sizeof(SecurityQos);
SecurityQos.ImpersonationLevel = SecurityIdentification;
SecurityQos.ContextTrackingMode = SECURITY_STATIC_TRACKING;
SecurityQos.EffectiveOnly = FALSE;
RtlInitUnicodeString(&Server, lpszServer);
Status = SamConnect(
&Server,
&SamHandle,
GENERIC_EXECUTE,
&ObjectAttributes
);
if ( !NT_SUCCESS(Status) ) {
DbgPrint("SamConnect failed, status %8.8x\n", Status);
goto Cleanup;
}
if(err = GetAccountDomain(&Server, &Domain))
{
DbgPrint("GetAccountDomain failed, status %d\n", err);
goto Cleanup;
}
Status = SamLookupDomainInSamServer(
SamHandle,
&Domain,
&DomainSid
);
free(Domain.Buffer);
if ( !NT_SUCCESS(Status) ) {
DbgPrint("Cannot find account domain, status %8.8x\n", Status);
Status = STATUS_CANT_ACCESS_DOMAIN_INFO;
goto Cleanup;
}
Status = SamOpenDomain(
SamHandle,
GENERIC_EXECUTE,
DomainSid,
&DomainHandle
);
if ( !NT_SUCCESS(Status) ) {
DbgPrint("Cannot open account domain, status %8.8x\n", Status);
Status = STATUS_CANT_ACCESS_DOMAIN_INFO;
goto Cleanup;
}
cUsersPerRequest = USERS_INITIAL_COUNT;
cbBytesRequested = BYTES_INITIAL_COUNT;
while(1)
{
bMoreData = FALSE;
Status = SamQueryDisplayInformation (
DomainHandle,
DomainDisplayUser,
cHandle, //Index
cUsersPerRequest,
cbBytesRequested,
&TotalAvailable,
&TotalReturned,
&cEntriesRead,
(PVOID*)&SortedUsers
);
// increment the index to take care of the entries read
cHandle += cEntriesRead;
// increase the request size
cUsersPerRequest *= 2;
if(cUsersPerRequest > USERS_MAX_COUNT)
cUsersPerRequest = USERS_MAX_COUNT;
cbBytesRequested *= 2;
if(cbBytesRequested > BYTES_MAX_COUNT)
cbBytesRequested = BYTES_MAX_COUNT;
if(Status == STATUS_MORE_ENTRIES)
bMoreData = TRUE;
if (NT_SUCCESS(Status))
{
WCHAR *szUserName;
szUserName = (WCHAR*)GlobalAlloc(GMEM_FIXED, sizeof(TCHAR)*UNLEN);
if( !szUserName)
{
DbgPrint("Could not allocate memory for szUserName.\n");
return GetLastError();
}
GlobalUnlock(hmem);
hnewmem = GlobalReAlloc(hmem,
((*pcEntriesRead) + cEntriesRead) *
sizeof(RAS_USER_1),
GMEM_MOVEABLE);
if(!hnewmem)
{
DWORD LastError = GetLastError();
DbgPrint("Could not reallocate memory for *ppRasUser1.\n");
SamFreeMemory( SortedUsers );
return (LastError);
}
hmem = hnewmem;
*ppRasUser1 = (RAS_USER_1*) GlobalLock(hmem);
if(!*ppRasUser1)
{
DbgPrint("Could not lock memory segment for *ppRasUser1.\n");
return GetLastError();
}
pRasUser1Ptr = (*ppRasUser1) + (*pcEntriesRead);
(*pcEntriesRead) += cEntriesRead;
for (i=0;i<cEntriesRead ; i++, pRasUser1Ptr++)
{
ConvertUnicodeStringToWcs(szUserName, &SortedUsers[i].LogonName);
memset(&(pRasUser1Ptr->rasuser0), '\0', sizeof(RAS_USER_0));
pRasUser1Ptr->szUser = (WCHAR*)
GlobalAlloc(GMEM_FIXED,
sizeof(TCHAR)*
lstrlen(szUserName)+
sizeof(TCHAR));
if( !pRasUser1Ptr->szUser)
{
DbgPrint("Could not allocate memory for pRasUser1->szUser.\n");
SamFreeMemory( SortedUsers );
if(szUserName)
GlobalFree(szUserName);
GlobalUnlock(hmem);
GlobalFree(hmem);
return GetLastError();
}
lstrcpy(pRasUser1Ptr->szUser, szUserName);
}
if(szUserName)
GlobalFree(szUserName);
Status = SamFreeMemory( SortedUsers );
if (!NT_SUCCESS(Status))
{
DbgPrint("\n\n\n ******** SamFreeMemory() failed. *********\n");
DbgPrint("\n\n\n ******** Status: 0x%lx *********\n", Status);
}
}
if(!bMoreData)
break;
} // end while
//
// Close DomainHandle if open.
//
Cleanup:
if (DomainHandle) {
SamCloseHandle(DomainHandle);
}
//
// Close SamHandle if open.
//
if (SamHandle) {
SamCloseHandle(SamHandle);
}
} //else
if (insert_list_head(*ppRasUser1, RASADMIN_RAS_USER_1_PTR, *pcEntriesRead))
{
FreeUser1(*ppRasUser1, *pcEntriesRead);
GlobalUnlock((HGLOBAL)*ppRasUser1);
GlobalFree(*ppRasUser1);
Status = ERROR_NOT_ENOUGH_MEMORY;
}
return( (NT_SUCCESS(Status)) ? ERROR_SUCCESS : Status );
}
#endif
DWORD APIENTRY
RasAdminUserSetInfo(
IN const WCHAR * lpszServer,
IN const WCHAR * lpszUser,
IN const PRAS_USER_0 pRasUser0
)
/*++
Routine Description:
This routine allows the admin to change the RAS permission for a
user. If the user parms field of a user is being used by another
application, it will be destroyed.
Arguments:
lpszServer name of the server which has the user database,
eg., "\\\\UASSRVR" (the server must be one on which
the UAS can be changed i.e., the name returned by
RasAdminGetUserAccountServer).
lpszUser user account name to retrieve information for,
e.g. "USER".
pRasUser0 pointer to a buffer in which user information is
provided. The buffer should contain a filled
RAS_USER_0 structure.
Return Value:
ERROR_SUCCESS on successful return.
One of the following non-zero error codes indicating failure:
return codes from NetUserGetInfo or NetUserSetInfo
ERROR_INVALID_DATA indicates that the data in pRasUser0 is bad.
--*/
{
return MprAdminUserSetInfo(lpszServer, lpszUser, 0, (LPBYTE)pRasUser0);
}
DWORD APIENTRY
RasAdminSetUserParms(
IN OUT WCHAR * lpszParms,
IN DWORD cchNewParms,
IN PRAS_USER_0 pRasUser0
)
/*++
Routine Description:
This routine is used to modify the RAS user permission and call back number in lpszParms
from the information in pRasuser0.
Arguments:
lpszParms pointer to UsrParms buffer.
pRasUser0 pointer to a buffer in which user information is
provided. The buffer should contain a filled
RAS_USER_0 structure.
Return Value:
ERROR_SUCCESS on successful return.
One of the following non-zero error codes indicating failure:
ERROR_INVALID_DATA indicates that the data in pRasUser0 is bad.
--*/
{
RAS_USER_0 User0;
USER_PARMS UserParms;
DWORD dwRetCode;
WCHAR wchBuffer[sizeof(USER_PARMS)];
ASSERT(lpszParms != NULL);
ASSERT(pRasUser0 != NULL);
CopyMemory(&User0, pRasUser0, sizeof(RAS_USER_0));
//
// This will initialize a USER_PARMS structure with a template
// for default Macintosh and Ras data.
//
InitUsrParams(&UserParms);
//
// We are sharing the user parms field with LM SFM, and want to
// preserver it's portion. So we'll get the user parms and put
// the Mac primary group into our template, which is what we'll
// eventually store back to the user parms field.
//
//
// usr_parms comes back as a wide character string. The MAC Primary
// Group is at offset 1. We'll convert this part to ASCII and store
// it in our template.
//
if (lstrlenW(lpszParms+1) >= UP_LEN_MAC)
{
wcstombs(UserParms.up_PriGrp, lpszParms+1, UP_LEN_MAC);
}
//
// Compress Callback number (the compressed phone number is placed
// back in the RAS_USER_0 structure. The permissions byte may also
// be affected if the phone number is not compressable.
//
if (dwRetCode = RasPrivilegeAndCallBackNumber(TRUE, &User0))
{
return(dwRetCode);
}
//
// Now put the dialin privileges and compressed phone number into
// the USER_PARMS template. Note that the privileges byte is the
// first byte of the callback number field.
//
UserParms.up_CBNum[0] = User0.bfPrivilege;
wcstombs( &UserParms.up_CBNum[1],
User0.szPhoneNumber,
sizeof(UserParms.up_CBNum) - 1);
//
// Wow, that was tough. Now, we'll convert our template into
// wide characters for storing back into user parms field.
//
//
// Fill in the remaining data with ' ' up to the bounds of USER_PARMS.
//
{
USHORT Count;
for (Count = 0; Count < sizeof(UserParms.up_CBNum); Count++ )
{
if (UserParms.up_CBNum[Count] == '\0')
{
UserParms.up_CBNum[Count] = ' ';
}
}
}
UserParms.up_Null = '\0';
if ( lstrlenW( lpszParms ) <= ( sizeof( USER_PARMS ) - 1 ) )
{
mbstowcs( lpszParms, (PBYTE)(&UserParms), sizeof(USER_PARMS) );
}
else
{
mbstowcs( wchBuffer, (PBYTE)(&UserParms), sizeof(USER_PARMS) );
CopyMemory( (PBYTE)lpszParms,
(PBYTE)wchBuffer,
sizeof( wchBuffer ) - sizeof( WCHAR ) );
}
return(ERROR_SUCCESS);
}
DWORD APIENTRY
RasAdminUserGetInfo(
IN const WCHAR * lpszServer,
IN const WCHAR * lpszUser,
OUT PRAS_USER_0 pRasUser0
)
/*++
Routine Description:
This routine retrieves RAS and other UAS information for a user
in the domain the specified server belongs to. It loads the caller's
pRasUser0 with a RAS_USER_0 structure.
Arguments:
lpszServer name of the server which has the user database,
eg., "\\\\UASSRVR" (the server must be one on which
the UAS can be changed i.e., the name returned by
RasAdminGetUserAccountServer).
lpszUser user account name to retrieve information for,
e.g. "USER".
pRasUser0 pointer to a buffer in which user information is
returned. The returned info is a RAS_USER_0 structure.
Return Value:
ERROR_SUCCESS on successful return.
One of the following non-zero error codes indicating failure:
return codes from NetUserGetInfo or NetUserSetInfo
ERROR_INVALID_DATA indicates that user parms is invalid.
--*/
{
return MprAdminUserGetInfo(lpszServer, lpszUser, 0, (LPBYTE)pRasUser0);
}
DWORD APIENTRY
RasAdminGetUserParms(
IN WCHAR * lpszParms,
IN OUT PRAS_USER_0 pRasUser0
)
/*++
Routine Description:
This routine fills the caller's pRasUser0 with a RAS_USER_0 structure information
extracted from lpszParms.
Arguments:
lpszParms UsrParms buffer
pRasUser0 pointer to a buffer in which user information is
returned. The returned info is a RAS_USER_0 structure.
Return Value:
ERROR_SUCCESS on successful return.
One of the following non-zero error codes indicating failure:
ERROR_INVALID_DATA indicates that user parms is invalid.
--*/
{
ASSERT(lpszParms);
ASSERT(pRasUser0);
memset(pRasUser0, '\0', sizeof(RAS_USER_0));
//
// if usr_parms not initialized, default to no RAS privilege
//
if (lpszParms == NULL)
{
pRasUser0->bfPrivilege = RASPRIV_NoCallback;
pRasUser0->szPhoneNumber[0] = UNICODE_NULL;
}
else
{
WCHAR wchUserParms[sizeof(USER_PARMS)];
//
// AndyHe... truncate user_info_2 at sizeof USER_PARMS
//
if ( lstrlenW( lpszParms ) > ( sizeof( USER_PARMS ) - 1 ) )
{
CopyMemory( wchUserParms,
lpszParms,
sizeof( USER_PARMS ) * sizeof( WCHAR ) );
//
// we slam in a null at sizeof(USER_PARMS)-1 which corresponds to
// user_parms.up_Null
//
wchUserParms[sizeof(USER_PARMS)-1] = L'\0';
}
else
{
lstrcpyW( wchUserParms, lpszParms );
}
//
// get RAS info (and validate) from usr_parms
//
if (GetUsrParams(UP_CLIENT_DIAL,
(LPWSTR) wchUserParms,
(LPWSTR) pRasUser0))
{
pRasUser0->bfPrivilege = RASPRIV_NoCallback;
pRasUser0->szPhoneNumber[0] = UNICODE_NULL;
}
else
{
//
// get RAS Privilege and callback number
//
RasPrivilegeAndCallBackNumber(FALSE, pRasUser0);
}
}
return (ERROR_SUCCESS);
}
DWORD APIENTRY
RasAdminGetUserAccountServer(
IN const WCHAR * lpszDomain,
IN const WCHAR * lpszServer,
OUT LPWSTR lpszUasServer
)
/*++
Routine Description:
This routine finds the server with the master UAS (the PDC) from
either a domain name or a server name. Either the domain or the
server (but not both) may be NULL.
Arguments:
lpszDomain Domain name or NULL if none.
lpszServer name of the server which has the user database.
lpszUasServer Caller's buffer for the returned UAS server name.
The buffer should be atleast UNCLEN + 1 characters
long.
Return Value:
ERROR_SUCCESS on successful return.
ERROR_INVALID_PARAMETER if both lpszDomain and lpszServer are NULL.
one of the following non-zero error codes on failure:
return codes from NetGetDCName
--*/
{
PUSER_MODALS_INFO_1 pModalsInfo1 = NULL;
PDOMAIN_CONTROLLER_INFO pControllerInfo = NULL;
DWORD dwErr = NO_ERROR;
WCHAR TempName[UNCLEN + 1];
//
// Check the caller's buffer. Must be UNCLEN+1 bytes
//
lpszUasServer[0] = 0;
lpszUasServer[UNCLEN] = 0;
if ((lpszDomain) && (*lpszDomain))
{
//
// This code will get the name of a DC for this domain.
//
dwErr = DsGetDcName(
NULL,
lpszDomain,
NULL,
NULL,
DS_DIRECTORY_SERVICE_PREFERRED | DS_WRITABLE_REQUIRED,
&pControllerInfo);
if (dwErr != NO_ERROR)
{
return dwErr;
}
//
// Return the name of the DC
//
wcscpy(lpszUasServer, pControllerInfo->DomainControllerName);
// Cleanup
//
NetApiBufferFree(pControllerInfo);
}
else
{
if ((lpszServer) && (*lpszServer))
{
lstrcpyW(TempName, lpszServer);
}
else
{
//
// Should have specified a computer name
//
return (ERROR_INVALID_PARAMETER);
}
//
// Ok, we have the name of a server to use - now find out it's
// server role.
//
if (dwErr = NetUserModalsGet(TempName, 1, (LPBYTE *) &pModalsInfo1))
{
DbgPrint("Admapi: NetUserModalGet error - server %ws\n", TempName);
return dwErr;
}
if (pModalsInfo1 == NULL)
{
return ERROR_CAN_NOT_COMPLETE;
}
//
// Examine the role played by this server
//
switch (pModalsInfo1->usrmod1_role)
{
case UAS_ROLE_STANDALONE:
case UAS_ROLE_PRIMARY:
//
// In this case our server is a primary or a standalone.
// in either case we use it.
//
break;
case UAS_ROLE_BACKUP:
case UAS_ROLE_MEMBER:
//
// Use the primary domain controller as the remote server
// in this case.
//
wsprintf(TempName, L"\\\\%s", pModalsInfo1->usrmod1_primary);
break;
}
lstrcpyW(lpszUasServer, TempName);
NetApiBufferFree(pModalsInfo1);
}
return (dwErr);
}
DWORD APIENTRY
RasAdminGetErrorString(
IN UINT ResourceId,
OUT WCHAR * lpszString,
IN DWORD InBufSize )
/* Load caller's buffer 'lpszString' of length 'InBufSize' with the
** resource string associated with ID 'ResourceId'.
**
** Returns 0 if successful, otherwise a non-0 error code.
**
*/
{
DWORD dwErr = 0;
HINSTANCE hMsgDll;
if (ResourceId < RASBASE || ResourceId > RASBASEEND || !lpszString)
return ERROR_INVALID_PARAMETER;
if (InBufSize == 1)
{
/* strange case, but a bug was filed...
*/
lpszString[ 0 ] = '\0';
return ERROR_INSUFFICIENT_BUFFER;
}
if ((hMsgDll = LoadLibraryA("rasmsg.dll")) == NULL) {
return GetLastError();
}
if (!FormatMessageW(
FORMAT_MESSAGE_FROM_HMODULE,
hMsgDll,
ResourceId,
0,
lpszString,
InBufSize,
NULL))
{
dwErr = GetLastError();
}
return dwErr;
}
DWORD
RasPrivilegeAndCallBackNumber(
BOOL Compress,
PRAS_USER_0 pRasUser0
)
/*++
Routine Description:
This routine either compresses or decompresses the users call
back number depending on the boolean value Compress.
Return Value:
ERROR_SUCCESS on successful return.
one of the following non-zero error codes on failure:
ERROR_INVALID_DATA indicating that usr_parms is invalid
--*/
{
DWORD dwRetCode;
switch( pRasUser0->bfPrivilege & RASPRIV_CallbackType) {
case RASPRIV_NoCallback:
case RASPRIV_AdminSetCallback:
case RASPRIV_CallerSetCallback:
if (Compress == TRUE)
{
WCHAR compressed[ RASSAPI_MAX_CALLBACK_NUMBER_SIZE + 1];
// compress the phone number to fit in the
// user parms field
if (dwRetCode = RasAdminCompressPhoneNumber(pRasUser0->szPhoneNumber,
compressed))
{
return (dwRetCode);
}
else
{
lstrcpy((LPTSTR) pRasUser0->szPhoneNumber,
(LPCTSTR) compressed);
}
}
else
{
WCHAR decompressed[ RASSAPI_MAX_CALLBACK_NUMBER_SIZE + 1];
//
// decompress the phone number
//
if (RasAdminDecompressPhoneNumber(pRasUser0->szPhoneNumber,
decompressed))
{
pRasUser0->bfPrivilege = RASPRIV_NoCallback;
pRasUser0->szPhoneNumber[0] = UNICODE_NULL;
}
else
{
lstrcpy((LPTSTR) pRasUser0->szPhoneNumber,
(LPCTSTR) decompressed);
}
}
break;
default:
if (Compress == TRUE)
{
return(ERROR_INVALID_DATA);
}
else
{
pRasUser0->bfPrivilege = RASPRIV_NoCallback;
pRasUser0->szPhoneNumber[0] = UNICODE_NULL;
}
break;
}
return(ERROR_SUCCESS);
}
BOOL
CheckIfNT(const WCHAR * lpszServer)
/*
* Check to see if the server lpszServer is an NT or a downlevel server.
*
* We assume here that the server service is running on the server lpszServer
*
*/
{
PSERVER_INFO_101 ServerInfo101;
if(NetServerGetInfo(
(WCHAR *)lpszServer,
101, // level 101 info
(LPBYTE *) &ServerInfo101
))
{
return FALSE;
}
return((ServerInfo101->sv101_type & SV_TYPE_NT) ? TRUE:FALSE);
}
VOID
ConvertUnicodeStringToWcs(WCHAR *szUserName, PUNICODE_STRING pUnicode)
{
USHORT cbLen = pUnicode->Length/sizeof(WCHAR);
WCHAR *pwc = pUnicode->Buffer;
*szUserName = L'\0';
if(cbLen == 0)
return;
while( (cbLen-- > 0) && (*pwc != L'\0'))
{
*szUserName++ = *pwc++;
}
*szUserName = L'\0';
}
DWORD GetAccountDomain(
IN PUNICODE_STRING Server,
OUT PUNICODE_STRING Domain
)
/*
* Given the server name, this routine determines the Account Domain for
* the given server. This is an NT only routine.
*
* For example if the server name is \\ramc2 and the local domain name is
* ramc2, this routine will return ramc2.
* If the server \\ramc2 were a BDC in the domain NTWINS, the domain name
* returned will be NTWINS.
*
* This routine allocates memory for storing the domain name. It is the
* responsiblity of the caller to free Domain->Buffer using free().
*
*/
{
DWORD rc = 0;
NTSTATUS ntStatus = STATUS_SUCCESS;
LSA_HANDLE hLsa = NULL;
PPOLICY_ACCOUNT_DOMAIN_INFO pAcctDomainInfo = NULL;
PUNICODE_STRING DomainName;
//
// Open the LSA
//
if ((ntStatus = OpenLsa(Server, &hLsa)) != NO_ERROR)
if (!NT_SUCCESS(ntStatus))
{
return (1L);
}
//
// Get the account domain
//
ntStatus = LsaQueryInformationPolicy(hLsa, PolicyAccountDomainInformation,
(PVOID *) &pAcctDomainInfo);
if (!NT_SUCCESS(ntStatus))
{
rc = 1L;
goto clean;
}
DomainName = &pAcctDomainInfo->DomainName;
Domain->Length = DomainName->Length;
Domain->MaximumLength = DomainName->MaximumLength;
Domain->Buffer = malloc(DomainName->Length);
if(!(Domain->Buffer))
{
rc = 1L;
goto clean;
}
RtlMoveMemory(Domain->Buffer, DomainName->Buffer, DomainName->Length);
clean:
if (pAcctDomainInfo != NULL)
{
LsaFreeMemory(pAcctDomainInfo);
}
if (hLsa != NULL)
{
LsaClose(hLsa);
}
return (rc);
}
//**
//
// Call: OpenLsa
//
// Returns: Returns from LsaOpenPolicy.
//
// Description: The LSA will be opened.
//
NTSTATUS OpenLsa(
IN PUNICODE_STRING pSystem OPTIONAL,
IN OUT PLSA_HANDLE phLsa
)
{
SECURITY_QUALITY_OF_SERVICE QOS;
OBJECT_ATTRIBUTES ObjAttribs;
NTSTATUS ntStatus;
//
// Open the LSA and obtain a handle to it.
//
QOS.Length = sizeof(QOS);
QOS.ImpersonationLevel = SecurityImpersonation;
QOS.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
QOS.EffectiveOnly = FALSE;
InitializeObjectAttributes(&ObjAttribs, NULL, 0L, NULL, NULL);
ObjAttribs.SecurityQualityOfService = &QOS;
ntStatus = LsaOpenPolicy(pSystem, &ObjAttribs,
POLICY_VIEW_LOCAL_INFORMATION | POLICY_LOOKUP_NAMES, phLsa);
return (ntStatus);
}