|
|
/*
File userdb.c
Implementation of the local user database object.
Paul Mayfield, 10/8/97 */
#include "rassrv.h"
// Registry values
extern WCHAR pszregRasParameters[]; extern WCHAR pszregServerFlags[]; extern WCHAR pszregPure[];
// Cached values for users
typedef struct _RASSRV_USERINFO { HANDLE hUser; // Handle to user
PWCHAR pszName; PWCHAR pszFullName; // Only loaded if requested
//gangz for secure password bug
//Change this for the new safe encoding password functions
WCHAR szPassword[PWLEN+1]; // Only non-null if this is new password to be committed
WCHAR wszPhoneNumber[MAX_PHONE_NUMBER_LEN + 1]; BYTE bfPrivilege; BYTE bDirty; } RASSRV_USERINFO;
// Structure used to implement/manipulate the local user database
typedef struct _RASSRV_USERDB { HANDLE hServer; // Handle to user server
DWORD dwUserCount; // Number of users in the database
DWORD dwCacheSize; // Number of users can be stored in cache
BOOL bEncrypt; // Whether encryption should be used
BOOL bDccBypass; // Whether dcc connections can bypass auth.
BOOL bPure; // Whether database is "Pure"
BOOL bEncSettingLoaded; // Whether we've read in the enc setting
BOOL bFlushOnClose; RASSRV_USERINFO ** pUserCache; // Cache of users
} RASSRV_USERDB;
// Defines a callback for enumerating users. Returns TRUE to continue the enueration
// FALSE to stop it.
typedef BOOL (* pEnumUserCb)( IN NET_DISPLAY_USER* pUser, IN HANDLE hData);
// We use this to guess the size of the the user array
// (so we can grow it when new users are added)
#define USR_ARRAY_GROW_SIZE 50
// Dirty flags
#define USR_RASPROPS_DIRTY 0x1 // whether callback is dirty
#define USR_FULLNAME_DIRTY 0x2 // whether full name needs to be flushed
#define USR_PASSWORD_DIRTY 0x4 // whether password needs to be flushed
#define USR_ADD_DIRTY 0x8 // whether user needs to be added
// Helper macros for dealing with dirty flags
#define usrDirtyRasProps(pUser) ((pUser)->bDirty |= USR_RASPROPS_DIRTY)
#define usrDirtyFullname(pUser) ((pUser)->bDirty |= USR_FULLNAME_DIRTY)
#define usrDirtyPassword(pUser) ((pUser)->bDirty |= USR_PASSWORD_DIRTY)
#define usrDirtyAdd(pUser) ((pUser)->bDirty |= USR_ADD_DIRTY)
#define usrIsDirty(pUser) ((pUser)->bDirty)
#define usrIsRasPropsDirty(pUser) ((pUser)->bDirty & USR_RASPROPS_DIRTY)
#define usrIsFullNameDirty(pUser) ((pUser)->bDirty & USR_FULLNAME_DIRTY)
#define usrIsPasswordDirty(pUser) ((pUser)->bDirty & USR_PASSWORD_DIRTY)
#define usrIsAddDirty(pUser) ((pUser)->bDirty & USR_ADD_DIRTY)
#define usrClearDirty(pUser) ((pUser)->bDirty = 0)
#define usrClearRasPropsDirty(pUser) ((pUser)->bDirty &= ~USR_CALLBACK_DIRTY)
#define usrClearFullNameDirty(pUser) ((pUser)->bDirty &= ~USR_FULLNAME_DIRTY)
#define usrClearPasswordDirty(pUser) ((pUser)->bDirty &= ~USR_PASSWORD_DIRTY)
#define usrClearAddDirty(pUser) ((pUser)->bDirty &= ~USR_ADD_DIRTY)
#define usrFlagIsSet(_val, _flag) (((_val) & (_flag)) != 0)
#define usrFlagIsClear(_val, _flag) (((_val) & (_flag)) == 0)
//
// Reads in server flags and determines whether encrypted
// password and data are required.
//
// lpdwFlags is assigned one of the following on success
// 0 = data and pwd enc not required
// MPR_USER_PROF_FLAG_SECURE = data and pwd enc required
// MPR_USER_PROF_FLAG_UNDETERMINED = Can't say for sure
//
DWORD usrGetServerEnc( OUT LPDWORD lpdwFlags) { DWORD dwFlags = 0;
if (!lpdwFlags) return ERROR_INVALID_PARAMETER;
// Read in the flags
RassrvRegGetDw(&dwFlags, 0, (const PWCHAR)pszregRasParameters, (const PWCHAR)pszregServerFlags);
// The following bits will be set for secure auth.
//
if ( (usrFlagIsSet (dwFlags, PPPCFG_NegotiateMSCHAP)) && (usrFlagIsSet (dwFlags, PPPCFG_NegotiateStrongMSCHAP)) && (usrFlagIsClear (dwFlags, PPPCFG_NegotiateMD5CHAP)) && (usrFlagIsClear (dwFlags, PPPCFG_NegotiateSPAP)) && (usrFlagIsClear (dwFlags, PPPCFG_NegotiateEAP)) && (usrFlagIsClear (dwFlags, PPPCFG_NegotiatePAP)) ) { *lpdwFlags = MPR_USER_PROF_FLAG_SECURE; return NO_ERROR; }
// The following bits will be set for insecure auth.
//
else if ( (usrFlagIsSet (dwFlags, PPPCFG_NegotiateMSCHAP)) && (usrFlagIsSet (dwFlags, PPPCFG_NegotiateStrongMSCHAP)) && (usrFlagIsSet (dwFlags, PPPCFG_NegotiateSPAP)) && (usrFlagIsSet (dwFlags, PPPCFG_NegotiatePAP)) && (usrFlagIsClear (dwFlags, PPPCFG_NegotiateEAP)) && (usrFlagIsClear (dwFlags, PPPCFG_NegotiateMD5CHAP)) ) { *lpdwFlags = 0; // data and pwd enc not required
return NO_ERROR; }
// Otherwise, we are undetermined
*lpdwFlags = MPR_USER_PROF_FLAG_UNDETERMINED; return NO_ERROR; }
//
// Sets the encryption policy for the server
//
DWORD usrSetServerEnc( IN DWORD dwFlags) { DWORD dwSvrFlags = 0;
// Read in the old flags
RassrvRegGetDw(&dwSvrFlags, 0, (const PWCHAR)pszregRasParameters, (const PWCHAR)pszregServerFlags);
// If the user requires encryption then set MSCHAP
// and CHAP as the only authentication types and
// set the ipsec flag.
if (dwFlags & MPR_USER_PROF_FLAG_SECURE) { dwSvrFlags |= PPPCFG_NegotiateMSCHAP; dwSvrFlags |= PPPCFG_NegotiateStrongMSCHAP; dwSvrFlags &= ~PPPCFG_NegotiateMD5CHAP; dwSvrFlags &= ~PPPCFG_NegotiateSPAP; dwSvrFlags &= ~PPPCFG_NegotiateEAP; dwSvrFlags &= ~PPPCFG_NegotiatePAP; }
// Otherwise, the user does require encryption,
// so enable all authentication types and disable
// the requirement to use IPSEC
else { dwSvrFlags &= ~PPPCFG_NegotiateMD5CHAP; dwSvrFlags &= ~PPPCFG_NegotiateEAP; dwSvrFlags |= PPPCFG_NegotiateMSCHAP; dwSvrFlags |= PPPCFG_NegotiateStrongMSCHAP; dwSvrFlags |= PPPCFG_NegotiateSPAP; dwSvrFlags |= PPPCFG_NegotiatePAP; }
// Commit changes to the registry
RassrvRegSetDw(dwSvrFlags, (const PWCHAR)pszregRasParameters, (const PWCHAR)pszregServerFlags); return NO_ERROR; }
// Enumerates the local users
//
DWORD usrEnumLocalUsers( IN pEnumUserCb pCbFunction, IN HANDLE hData) { DWORD dwErr, dwIndex = 0, dwCount = 100, dwEntriesRead, i; NET_DISPLAY_USER * pUsers; NET_API_STATUS nStatus; RAS_USER_0 RasUser0; HANDLE hUser = NULL, hServer = NULL; // Enumerate the users,
while (TRUE) { // Read in the first block of user names
nStatus = NetQueryDisplayInformation( NULL, 1, dwIndex, dwCount, dwCount * sizeof(NET_DISPLAY_USER), &dwEntriesRead, &pUsers); // Get out if there's an error getting user names
if ((nStatus != NERR_Success) && (nStatus != ERROR_MORE_DATA)) { break; }
// For each user read in, call the callback function
for (i = 0; i < dwEntriesRead; i++) { BOOL bOk;
//For whistler bug 243874 gangz
//On whistler Personal version, we wont show the Administrator
//in the user's listview on the Incoming connection's User Tab
//
if ( (DOMAIN_USER_RID_ADMIN == pUsers[i].usri1_user_id) && IsPersonalPlatform() ) { continue; } bOk = (*pCbFunction)(&(pUsers[i]), hData); if (bOk == FALSE) { nStatus = NERR_Success; break; } }
// Set the index to read in the next set of users
dwIndex = pUsers[dwEntriesRead - 1].usri1_next_index; // Free the users buffer
NetApiBufferFree (pUsers);
// If we've read in everybody, go ahead and break
if (nStatus != ERROR_MORE_DATA) { break; } } return NO_ERROR; }
// Copies the data in pRassrvUser to its equivalent in UserInfo
DWORD usrSyncRasProps( IN RASSRV_USERINFO * pRassrvUser, OUT RAS_USER_0 * UserInfo) { UserInfo->bfPrivilege = pRassrvUser->bfPrivilege; lstrcpynW( UserInfo->wszPhoneNumber, pRassrvUser->wszPhoneNumber, MAX_PHONE_NUMBER_LEN); UserInfo->wszPhoneNumber[MAX_PHONE_NUMBER_LEN] = (WCHAR)0; return NO_ERROR; }
// Commits the data for the given user to the local user database
DWORD usrCommitRasProps( IN RASSRV_USERINFO * pRassrvUser) { DWORD dwErr = NO_ERROR; RAS_USER_0 UserInfo;
dwErr = usrSyncRasProps(pRassrvUser, &UserInfo); if (dwErr != NO_ERROR) return dwErr;
dwErr = MprAdminUserWrite(pRassrvUser->hUser, 0, (LPBYTE)&UserInfo); if (dwErr != NO_ERROR) DbgOutputTrace ("usrCommitRasProps: unable to commit %S (0x%08x)", pRassrvUser->pszName, dwErr); return dwErr; }
// Simple bounds checking
BOOL usrBoundsCheck( IN RASSRV_USERDB * This, IN DWORD dwIndex) { // Dwords are unsigned, so no need to check < 0
if (This->dwUserCount <= dwIndex) return FALSE; return TRUE; }
// Frees an array of users
DWORD usrFreeUserArray( IN RASSRV_USERINFO ** pUsers, IN DWORD dwCount) { DWORD i;
if (!pUsers) return ERROR_INVALID_PARAMETER;
for (i=0; i < dwCount; i++) { if (pUsers[i]) { if (pUsers[i]->hUser) MprAdminUserClose(pUsers[i]->hUser); if (pUsers[i]->pszName) RassrvFree (pUsers[i]->pszName); if (pUsers[i]->pszFullName) RassrvFree (pUsers[i]->pszFullName);
//Wipe password before free memory, if CryptProtectData() is used
//this will also release the memory allocated by it
SafeWipePasswordBuf(pUsers[i]->szPassword);
RassrvFree(pUsers[i]); } }
return NO_ERROR; }
// Standard user comparison function used for sorting
int _cdecl usrCompareUsers( IN const void * elem1, IN const void * elem2) { RASSRV_USERINFO* p1 = *((RASSRV_USERINFO**)elem1); RASSRV_USERINFO* p2 = *((RASSRV_USERINFO**)elem2);
return lstrcmpi(p1->pszName, p2->pszName); }
// Returns whether a given user exists
BOOL usrUserExists ( IN RASSRV_USERDB * This, IN PWCHAR pszName) { DWORD i; int iCmp;
for (i = 0; i < This->dwUserCount; i++) { iCmp = lstrcmpi(This->pUserCache[i]->pszName, pszName); if (iCmp == 0) return TRUE; if (iCmp > 0) return FALSE; }
return FALSE; }
// Resorts the cache
DWORD usrResortCache( IN RASSRV_USERDB * This) { qsort( This->pUserCache, This->dwUserCount, sizeof(RASSRV_USERINFO*), usrCompareUsers); return NO_ERROR; }
// Resizes the user cache to allow for added users
DWORD usrResizeCache( IN RASSRV_USERDB * This, IN DWORD dwNewSize) { RASSRV_USERINFO ** pNewCache; DWORD i;
// Only resize bigger (this could be changed)
if ((!This) || (dwNewSize <= This->dwCacheSize)) return ERROR_INVALID_PARAMETER;
// Allocate the new cache
pNewCache = RassrvAlloc(dwNewSize * sizeof (RASSRV_USERINFO*), TRUE); if (pNewCache == NULL) return ERROR_NOT_ENOUGH_MEMORY;
// Copy over the old entries and free the old cache
if (This->pUserCache) { CopyMemory( (PVOID)pNewCache, (CONST VOID *)(This->pUserCache), This->dwCacheSize * sizeof(RASSRV_USERINFO*)); RassrvFree(This->pUserCache); }
// Reassign the new cache and update the cache size
This->pUserCache = pNewCache; This->dwCacheSize = dwNewSize;
return NO_ERROR; }
// Enumeration callback that adds users to the local database
// as they are read from the system.
BOOL usrInitializeUser( NET_DISPLAY_USER * pNetUser, HANDLE hUserDatabase) { RASSRV_USERDB * This = (RASSRV_USERDB*)hUserDatabase; RASSRV_USERINFO * pRasUser = NULL; DWORD dwErr = NO_ERROR, dwSize; RAS_USER_0 UserInfo;
// Make sure we have a valid database
if (!This) { return FALSE; } // Resize the cache to accomodate more users if needed
if (This->dwUserCount >= This->dwCacheSize) { dwErr = usrResizeCache( This, This->dwCacheSize + USR_ARRAY_GROW_SIZE); if (dwErr != NO_ERROR) { return FALSE; } }
// Allocate this user
pRasUser = RassrvAlloc(sizeof(RASSRV_USERINFO), TRUE); if (pRasUser == NULL) { return FALSE; }
do { // Point to the user name
dwSize = (wcslen(pNetUser->usri1_name) + 1) * sizeof(WCHAR); pRasUser->pszName = RassrvAlloc(dwSize, FALSE); if (!pRasUser->pszName) { dwErr = ERROR_NOT_ENOUGH_MEMORY; break; } wcscpy(pRasUser->pszName, pNetUser->usri1_name);
// Open the user handle
dwErr = MprAdminUserOpen ( This->hServer, pRasUser->pszName, &(pRasUser->hUser)); if (dwErr != NO_ERROR) { break; } // Get the ras user info
dwErr = MprAdminUserRead(pRasUser->hUser, 0, (LPBYTE)&UserInfo); if (dwErr != NO_ERROR) { break; }
// Clear any dirty flags
usrClearDirty(pRasUser);
// Copy the phone number
lstrcpynW( pRasUser->wszPhoneNumber, UserInfo.wszPhoneNumber, MAX_PHONE_NUMBER_LEN); pRasUser->wszPhoneNumber[MAX_PHONE_NUMBER_LEN] = (WCHAR)0;
// Copy the privelege flags
pRasUser->bfPrivilege = UserInfo.bfPrivilege;
// Assign the user in the cache
This->pUserCache[This->dwUserCount] = pRasUser; // Update the user count
This->dwUserCount += 1; } while (FALSE);
// Cleanup
{ if (dwErr != NO_ERROR) { if (pRasUser) { if (pRasUser->pszName) { RassrvFree(pRasUser->pszName); } RassrvFree(pRasUser); } } }
return (dwErr == NO_ERROR) ? TRUE : FALSE; }
//
// Loads the global encryption setting. Because the operation opens
// up .mdb files to read profiles, etc. it is put in its own function
// and is called only when absolutely needed.
//
DWORD usrLoadEncryptionSetting( IN RASSRV_USERDB * This) { DWORD dwErr = NO_ERROR; DWORD dwSvrFlags, dwProfFlags;
if (This->bEncSettingLoaded) { return NO_ERROR; } // Read in the encryption setting by combining the
// server flags with the values in the default
// profile.
dwSvrFlags = MPR_USER_PROF_FLAG_UNDETERMINED; dwProfFlags = MPR_USER_PROF_FLAG_UNDETERMINED; MprAdminUserReadProfFlags (This->hServer, &dwProfFlags); usrGetServerEnc (&dwSvrFlags);
// If both sources confirm the encryption requirement
// then we require encryption
if ((dwProfFlags & MPR_USER_PROF_FLAG_SECURE) && (dwSvrFlags & MPR_USER_PROF_FLAG_SECURE)) { This->bEncrypt = TRUE; } else { This->bEncrypt = FALSE; }
This->bEncSettingLoaded = TRUE;
return dwErr; } // Creates a user data base object, initializing it from the local
// user database and returning a handle to it.
DWORD usrOpenLocalDatabase ( IN HANDLE * hUserDatabase) { RASSRV_USERDB * This = NULL; DWORD dwErr;
if (!hUserDatabase) return ERROR_INVALID_PARAMETER;
// Allocate the database
if ((This = RassrvAlloc(sizeof(RASSRV_USERDB), TRUE)) == NULL) return ERROR_NOT_ENOUGH_MEMORY;
// Connect to the user server
dwErr = MprAdminUserServerConnect(NULL, TRUE, &(This->hServer)); if (dwErr != NO_ERROR) { RassrvFree(This); return dwErr; }
// Load in the data from the system
if ((dwErr = usrReloadLocalDatabase((HANDLE)This)) == NO_ERROR) { *hUserDatabase = (HANDLE)This; This->bFlushOnClose = FALSE; return NO_ERROR; }
DbgOutputTrace ("usrOpenLocalDb: unable to load user db 0x%08x", dwErr); RassrvFree(This); *hUserDatabase = NULL; return dwErr; }
// Reloads the user information cached in the user database obj
// from the system. This can be used to implement a refresh in the ui.
//
DWORD usrReloadLocalDatabase ( IN HANDLE hUserDatabase) { RASSRV_USERDB * This = (RASSRV_USERDB*)hUserDatabase; DWORD dwErr;
// Validate
if (!This) { return ERROR_INVALID_PARAMETER; }
// Cleanup the old database
if (This->pUserCache) { usrFreeUserArray(This->pUserCache, This->dwUserCount); RassrvFree(This->pUserCache); }
// The encryption setting is loaded on demand from the
// usrGetEncryption/usrSetEncryption api's. This is a performance
// tune so that the IC wizard wouldn't have to wait for
// the profile to be loaded even though it doesn't use the result.
// Read in the purity of the system
{ DWORD dwPure = 0; RassrvRegGetDw(&dwPure, 0, (const PWCHAR)pszregRasParameters, (const PWCHAR)pszregPure); if (dwPure == 1) This->bPure = FALSE; else This->bPure = TRUE; }
// Read in whether dcc connections can be bypassed
{ DWORD dwSvrFlags = 0;
RassrvRegGetDw( &dwSvrFlags, dwSvrFlags, (const PWCHAR)pszregRasParameters, (const PWCHAR)pszregServerFlags);
if (dwSvrFlags & PPPCFG_AllowNoAuthOnDCPorts) This->bDccBypass = TRUE; else This->bDccBypass = FALSE; }
// Enumerate the local users from the system adding them
// to this database.
dwErr = usrEnumLocalUsers(usrInitializeUser, hUserDatabase); if (dwErr != NO_ERROR) { return NO_ERROR; }
return NO_ERROR; }
// Frees up the resources held by a user database object.
DWORD usrCloseLocalDatabase ( IN HANDLE hUserDatabase) { DWORD i; RASSRV_USERDB * This = (RASSRV_USERDB*)hUserDatabase;
// Make sure we were passed a valid handle
if (!This) return ERROR_INVALID_PARAMETER;
// We're done if there are no users
if (!This->dwUserCount) return NO_ERROR;
// Commit any settings as appropriate
if (This->bFlushOnClose) usrFlushLocalDatabase(hUserDatabase);
// Free the user cache
usrFreeUserArray(This->pUserCache, This->dwUserCount); RassrvFree(This->pUserCache);
// Disconnect from the user server
MprAdminUserServerDisconnect (This->hServer);
// Free This
RassrvFree(This);
return NO_ERROR; }
// Flushes the data written to the database object
DWORD usrFlushLocalDatabase ( IN HANDLE hUserDatabase) { RASSRV_USERDB * This = (RASSRV_USERDB*)hUserDatabase; RASSRV_USERINFO * pUser; DWORD dwErr, dwRet = NO_ERROR, dwCount, i, dwLength;
dwErr = usrGetUserCount (This, &dwCount); if (dwErr != NO_ERROR) return dwErr;
for (i=0; i<dwCount; i++) { pUser = This->pUserCache[i]; // Flush any dirty settings
if (usrIsDirty(pUser)) { // Add the user to the local user database if it hasn't
// already been done
if (usrIsAddDirty(pUser)) {
//For secure password bug .Net 754400
SafeDecodePasswordBuf(pUser->szPassword); dwErr = RasSrvAddUser ( pUser->pszName, (pUser->pszFullName) ? pUser->pszFullName : L"", (L'\0'!=pUser->szPassword[0]) ? pUser->szPassword : L""); SafeEncodePasswordBuf(pUser->szPassword); if (dwErr != NO_ERROR) dwRet = dwErr;
// Now get the SDO handle to the user
// so we can commit ras properties below.
dwErr = MprAdminUserOpen ( This->hServer, pUser->pszName, &(pUser->hUser)); if (dwErr != NO_ERROR) continue; } // Flush dirty callback properties
if (usrIsRasPropsDirty(pUser)) { if ((dwErr = usrCommitRasProps(This->pUserCache[i])) != NO_ERROR) dwRet = dwErr; }
// Flush dirty password and full name settings
if (usrIsFullNameDirty(pUser) || usrIsPasswordDirty(pUser)) {
SafeDecodePasswordBuf(pUser->szPassword); RasSrvEditUser ( pUser->pszName, (usrIsFullNameDirty(pUser)) ? pUser->pszFullName : NULL, (usrIsPasswordDirty(pUser)) ? pUser->szPassword : NULL);
SafeEncodePasswordBuf(pUser->szPassword); }
// Reset the user as not being dirty
usrClearDirty(pUser); } }
// Flush the encryption setting if it has been read
if (This->bEncSettingLoaded) { DWORD dwFlags;
if (This->bEncrypt) dwFlags = MPR_USER_PROF_FLAG_SECURE; else dwFlags = 0; MprAdminUserWriteProfFlags (This->hServer, dwFlags); usrSetServerEnc(dwFlags); }
// Flush out the purity of the system
{ DWORD dwPure = 0; if (This->bPure) dwPure = 0; else dwPure = 1; RassrvRegSetDw(dwPure, (const PWCHAR)pszregRasParameters, (const PWCHAR)pszregPure); }
// Flush out whether dcc connections can be bypassed
{ DWORD dwSvrFlags = 0;
RassrvRegGetDw( &dwSvrFlags, dwSvrFlags, (const PWCHAR)pszregRasParameters, (const PWCHAR)pszregServerFlags);
if (This->bDccBypass) dwSvrFlags |= PPPCFG_AllowNoAuthOnDCPorts; else dwSvrFlags &= ~PPPCFG_AllowNoAuthOnDCPorts;
RassrvRegSetDw( dwSvrFlags, (const PWCHAR)pszregRasParameters, (const PWCHAR)pszregServerFlags); }
return dwRet; }
// Rolls back the local user database so that no
// changes will be committed when Flush is called.
DWORD usrRollbackLocalDatabase ( IN HANDLE hUserDatabase) { DWORD i, dwIndex, dwErr; BOOL bCommit; RASSRV_USERDB * This = (RASSRV_USERDB*)hUserDatabase;
if (!This) return ERROR_INVALID_PARAMETER; if (!This->dwUserCount) return NO_ERROR;
// Go through the database, marking each user as not dirty
for (i = 0; i < This->dwUserCount; i++) usrClearDirty(This->pUserCache[i]);
This->bFlushOnClose = FALSE; return NO_ERROR; }
//
// Determines whether all users are required to encrypt
// their data and passwords.
//
DWORD usrGetEncryption ( IN HANDLE hUserDatabase, OUT PBOOL pbEncrypted) { RASSRV_USERDB * This = (RASSRV_USERDB*)hUserDatabase; if (!This) { return ERROR_INVALID_PARAMETER; }
// Load in the encryption setting
usrLoadEncryptionSetting(This);
*pbEncrypted = This->bEncrypt;
return NO_ERROR; }
// Gets user encryption setting
DWORD usrSetEncryption ( IN HANDLE hUserDatabase, IN BOOL bEncrypt) { RASSRV_USERDB * This = (RASSRV_USERDB*)hUserDatabase; if (!This) { return ERROR_INVALID_PARAMETER; }
// Load in the encryption setting
usrLoadEncryptionSetting(This);
This->bEncrypt = bEncrypt;
return NO_ERROR; }
// Returns whether dcc connections are allowed to
// bypass authentication
DWORD usrGetDccBypass ( IN HANDLE hUserDatabase, OUT PBOOL pbBypass) { RASSRV_USERDB * This = (RASSRV_USERDB*)hUserDatabase; if (!This) return ERROR_INVALID_PARAMETER;
*pbBypass = This->bDccBypass;
return NO_ERROR; }
// Sets whether dcc connections are allowed to
// bypass authentication
DWORD usrSetDccBypass ( IN HANDLE hUserDatabase, IN BOOL bBypass) { RASSRV_USERDB * This = (RASSRV_USERDB*)hUserDatabase; if (!This) return ERROR_INVALID_PARAMETER;
This->bDccBypass = bBypass;
return NO_ERROR; }
// Reports whether the user database is pure. (i.e. nobody has
// gone into MMC and messed with it).
DWORD usrIsDatabasePure ( IN HANDLE hUserDatabase, OUT PBOOL pbPure) { RASSRV_USERDB * This = (RASSRV_USERDB*)hUserDatabase; if (!This) return ERROR_INVALID_PARAMETER;
*pbPure = This->bPure;
return NO_ERROR; }
// Marks the user database's purity
DWORD usrSetDatabasePure( IN HANDLE hUserDatabase, IN BOOL bPure) { RASSRV_USERDB * This = (RASSRV_USERDB*)hUserDatabase; if (!This) return ERROR_INVALID_PARAMETER;
This->bPure = bPure;
return NO_ERROR; }
// Returns the number of users cached in this database
DWORD usrGetUserCount ( IN HANDLE hUserDatabase, OUT LPDWORD lpdwCount) { RASSRV_USERDB * This = (RASSRV_USERDB*)hUserDatabase; if (!This || !lpdwCount) return ERROR_INVALID_PARAMETER;
*lpdwCount = This->dwUserCount; return NO_ERROR; }
// Adds a user to the given database. This user will not be
// added to the system's local user database until this database
// object is flushed (and as long as Rollback is not called on
// this database object)
//
// On success, an optional handle to the user is returned
//
DWORD usrAddUser ( IN HANDLE hUserDatabase, IN PWCHAR pszName, OUT OPTIONAL HANDLE * phUser) { RASSRV_USERDB * This = (RASSRV_USERDB*)hUserDatabase; RASSRV_USERINFO * pUser; DWORD dwErr, dwLength;
// Validate the parameters
if (!This || !pszName) return ERROR_INVALID_PARAMETER;
// If the user already exists, don't add him
if (usrUserExists(This, pszName)) return ERROR_ALREADY_EXISTS;
// Resize the cache to accomodate if neccessary
if (This->dwUserCount + 1 >= This->dwCacheSize) { dwErr = usrResizeCache(This, This->dwCacheSize + USR_ARRAY_GROW_SIZE); if (dwErr != NO_ERROR) return dwErr; }
// Allocate the new user control block
if ((pUser = RassrvAlloc(sizeof(RASSRV_USERINFO), TRUE)) == NULL) return ERROR_NOT_ENOUGH_MEMORY;
// Allocate space for the name
dwLength = wcslen(pszName); pUser->pszName = RassrvAlloc((dwLength + 1) * sizeof(WCHAR), FALSE); if (pUser->pszName == NULL) return ERROR_NOT_ENOUGH_MEMORY;
// Copy the name
wcscpy(pUser->pszName, pszName);
// Enable the user for dialin by default
usrEnableDialin ((HANDLE)pUser, TRUE); // Dirty the user
usrDirtyAdd(pUser); usrDirtyRasProps(pUser);
// Put the user in the array and re-sort it
This->pUserCache[This->dwUserCount++] = pUser; usrResortCache(This);
// Return the handle
if (phUser) *phUser = (HANDLE)pUser;
//Need this zero memory to tell if a password is set in the future.
RtlSecureZeroMemory(pUser->szPassword,sizeof(pUser->szPassword)); //Other place will always assume the password is encrypted
//So encrypt even the empty password
SafeEncodePasswordBuf(pUser->szPassword); return NO_ERROR; }
// Gives the count of users stored in the user database object
// Deletes the given user
DWORD usrDeleteUser ( IN HANDLE hUserDatabase, IN DWORD dwIndex) { RASSRV_USERDB * This = (RASSRV_USERDB*)hUserDatabase; RASSRV_USERINFO * pUser; DWORD dwErr, dwMoveElemCount; // Validate the parameters
if (!This) return ERROR_INVALID_PARAMETER;
// Bounds Check
if (!usrBoundsCheck(This, dwIndex)) return ERROR_INVALID_INDEX;
// Get a reference to the user in question and remove him
// from the cache
pUser = This->pUserCache[dwIndex];
//Need this to clear password area and any memory allocated(if CryptProtectData() is used)
//
SafeWipePasswordBuf(pUser->szPassword); // Attempt to delete the user from the system
if ((dwErr = RasSrvDeleteUser(pUser->pszName)) != NO_ERROR) return dwErr;
// Remove the user from the cache
This->pUserCache[dwIndex] = NULL;
// Pull down every thing in the cache so that there are no holes
dwMoveElemCount = This->dwUserCount - dwIndex; if (dwMoveElemCount) { MoveMemory(&(This->pUserCache[dwIndex]), &(This->pUserCache[dwIndex + 1]), dwMoveElemCount * sizeof(RASSRV_USERINFO*)); }
// Decrement the number of users
This->dwUserCount--;
// Cleanup the user
usrFreeUserArray(&pUser, 1);
return NO_ERROR; }
// Gives a handle to the user at the given index
DWORD usrGetUserHandle ( IN HANDLE hUserDatabase, IN DWORD dwIndex, OUT HANDLE * hUser) { RASSRV_USERDB * This = (RASSRV_USERDB*)hUserDatabase; if (!This || !hUser) return ERROR_INVALID_PARAMETER;
if (!usrBoundsCheck(This, dwIndex)) return ERROR_INVALID_INDEX;
*hUser = (HANDLE)(This->pUserCache[dwIndex]); return NO_ERROR; }
// Gets a pointer to the name of the user (do not modify this)
DWORD usrGetName ( IN HANDLE hUser, OUT PWCHAR* pszName) { RASSRV_USERINFO* pRassrvUser = (RASSRV_USERINFO*)hUser; if (!pRassrvUser || !pszName) return ERROR_INVALID_PARAMETER;
*pszName = pRassrvUser->pszName; return NO_ERROR; }
// Fills the given buffer with a friendly display name
// (in the form username (fullname))
//*lpdwBuffSize is the number of Characters, NOT including the ending NULL
DWORD usrGetDisplayName ( IN HANDLE hUser, IN PWCHAR pszBuffer, IN OUT LPDWORD lpdwBufSize) { RASSRV_USERINFO * pRassrvUser = (RASSRV_USERINFO*)hUser; NET_API_STATUS nStatus; DWORD dwUserNameLength, dwFullLength, dwSizeRequired; WCHAR pszTemp[IC_USERFULLNAME]; // For whistler bug 39081 gangz
DWORD dwErr = NO_ERROR;
// Sanity check the params
if (!pRassrvUser || !pszBuffer || !lpdwBufSize) { return ERROR_INVALID_PARAMETER; } do { // Get the full name of the user
// For whistler bug 39081 gangz
// This is size in bytes
dwFullLength = sizeof(pszTemp)/sizeof(pszTemp[0]); dwErr = usrGetFullName(hUser, pszTemp, &dwFullLength); if (dwErr != NO_ERROR) { break; } // Make sure the buffer is big enough
dwUserNameLength = wcslen(pRassrvUser->pszName); dwSizeRequired = dwUserNameLength + dwFullLength + ((dwFullLength) ? 3 : 0); if (*lpdwBufSize < dwSizeRequired) { dwErr = ERROR_INSUFFICIENT_BUFFER; break; } if (dwFullLength) { wsprintfW( pszBuffer, L"%s (%s)", pRassrvUser->pszName, pszTemp); } else { wcscpy(pszBuffer, pRassrvUser->pszName); } } while (FALSE);
// Cleanup
{ // The number of characters required, NOT including ending NULL
*lpdwBufSize = dwSizeRequired; }
return dwErr; } // Fills the given buffer with a friendly display name
// (in the form username (fullname))
// *lpdwBufSize is the number of characters, NOT including ending NULL
DWORD usrGetFullName ( IN HANDLE hUser, IN PWCHAR pszBuffer, IN OUT LPDWORD lpdwBufSize) { RASSRV_USERINFO * pRassrvUser = (RASSRV_USERINFO*)hUser; NET_API_STATUS nStatus; USER_INFO_2 * pUserInfo = NULL; DWORD dwLength; PWCHAR pszFullName; DWORD dwErr = NO_ERROR; // Sanity check the params
if (!pRassrvUser || !pszBuffer || !lpdwBufSize) return ERROR_INVALID_PARAMETER;
// If the full name is already loaded, return it
if (pRassrvUser->pszFullName) pszFullName = pRassrvUser->pszFullName;
// or if this is a new user, get the name from memory
else if (usrIsAddDirty(pRassrvUser)) { pszFullName = (pRassrvUser->pszFullName) ? pRassrvUser->pszFullName : L""; } // Load the full name of the user
else { nStatus = NetUserGetInfo( NULL, pRassrvUser->pszName, 2, (LPBYTE*)&pUserInfo); if (nStatus != NERR_Success) { DbgOutputTrace ( "usrGetFullName: %x returned from NetUserGetInfo for %S", nStatus, pRassrvUser->pszName); return nStatus; } pszFullName = (PWCHAR)pUserInfo->usri2_full_name; }
do { // Make sure the length is ok
dwLength = wcslen(pszFullName);
// Assign the full name here if it hasn't already been done
if (dwLength && !pRassrvUser->pszFullName) { DWORD dwSize = dwLength * sizeof(WCHAR) + sizeof(WCHAR); pRassrvUser->pszFullName = RassrvAlloc(dwSize, FALSE); if (pRassrvUser->pszFullName) { wcscpy(pRassrvUser->pszFullName, pszFullName); } }
// Check the size NOT including ending NULL
if (*lpdwBufSize < dwLength ) { dwErr = ERROR_INSUFFICIENT_BUFFER; break; }
// Copy in the full name
wcscpy(pszBuffer, pszFullName); } while (FALSE);
// Cleanup
{ // report the size in number of characters ( NOT include ending NULL)
*lpdwBufSize = dwLength; if (pUserInfo) { NetApiBufferFree((LPBYTE)pUserInfo); } }
return dwErr; }
// Commits the full name of a user
DWORD usrSetFullName ( IN HANDLE hUser, IN PWCHAR pszFullName) { RASSRV_USERINFO* pRassrvUser = (RASSRV_USERINFO*)hUser; DWORD dwLength;
if (!pRassrvUser || !pszFullName) return ERROR_INVALID_PARAMETER;
// If this is not a new name, don't do anything
if (pRassrvUser->pszFullName) { if (wcscmp(pRassrvUser->pszFullName, pszFullName) == 0) return NO_ERROR; RassrvFree(pRassrvUser->pszFullName); }
// Allocate a new one
dwLength = wcslen(pszFullName); pRassrvUser->pszFullName = RassrvAlloc(dwLength * sizeof(WCHAR) + sizeof(WCHAR), FALSE); if (!pRassrvUser->pszFullName) return ERROR_NOT_ENOUGH_MEMORY;
// Copy it over
wcscpy(pRassrvUser->pszFullName, pszFullName);
// Mark it dirty -- a newly added user has his/her full name commited
// whenever it exists automatically
if (!usrIsAddDirty(pRassrvUser)) usrDirtyFullname(pRassrvUser); return NO_ERROR; }
// Commits the password of a user
//pszNewPassword is not encoded
DWORD usrSetPassword ( IN HANDLE hUser, IN PWCHAR pszNewPassword) { RASSRV_USERINFO* pRassrvUser = (RASSRV_USERINFO*)hUser; DWORD dwLength;
if (!pRassrvUser || !pszNewPassword) return ERROR_INVALID_PARAMETER;
// Cleanup the old password if it exists
SafeWipePasswordBuf(pRassrvUser->szPassword);
// Allocate a new one
dwLength = wcslen(pszNewPassword); // Copy it over
lstrcpynW(pRassrvUser->szPassword, pszNewPassword, sizeof(pRassrvUser->szPassword)/sizeof(pRassrvUser->szPassword[0]) );
// Encrypt it
SafeEncodePasswordBuf( pRassrvUser->szPassword );
// Mark it dirty -- a newly added user has his/her full name commited
// whenever it exists automatically
if (!usrIsAddDirty(pRassrvUser)) usrDirtyPassword(pRassrvUser); return NO_ERROR; }
// Determines whether users have callback/dialin priveleges.
DWORD usrGetDialin ( IN HANDLE hUser, OUT BOOL* bEnabled) { RASSRV_USERINFO* pRassrvUser = (RASSRV_USERINFO*)hUser; DWORD dwErr; RAS_USER_0 UserInfo;
if (!pRassrvUser || !bEnabled) return ERROR_INVALID_PARAMETER;
// Get the user info
*bEnabled = (pRassrvUser->bfPrivilege & RASPRIV_DialinPrivilege); return NO_ERROR; }
// Determines which if any callback priveleges are granted to a given user.
// Either (or both) of bAdminOnly and bUserSettable can be null
DWORD usrGetCallback ( IN HANDLE hUser, OUT BOOL* bAdminOnly, OUT BOOL* bUserSettable) { RASSRV_USERINFO* pRassrvUser = (RASSRV_USERINFO*)hUser; DWORD dwErr;
if (!pRassrvUser || !bAdminOnly || !bUserSettable) return ERROR_INVALID_PARAMETER; // Return whether we have callback privelege
if (bAdminOnly) { *bAdminOnly = (pRassrvUser->bfPrivilege & RASPRIV_AdminSetCallback); } if (bUserSettable) { *bUserSettable = (pRassrvUser->bfPrivilege & RASPRIV_CallerSetCallback); } return NO_ERROR; }
// Enable/disable dialin privelege.
DWORD usrEnableDialin ( IN HANDLE hUser, IN BOOL bEnable) { RASSRV_USERINFO* pRassrvUser = (RASSRV_USERINFO*)hUser; DWORD dwErr = NO_ERROR; BOOL bIsEnabled;
if (!pRassrvUser) return ERROR_INVALID_PARAMETER;
// If the dialin privelege is already set as requested return success
bIsEnabled = pRassrvUser->bfPrivilege & RASPRIV_DialinPrivilege; if ((!!bIsEnabled) == (!!bEnable)) return NO_ERROR;
// Otherwise reset the privelege
if (bEnable) pRassrvUser->bfPrivilege |= RASPRIV_DialinPrivilege; else pRassrvUser->bfPrivilege &= ~RASPRIV_DialinPrivilege; // Dirty the user (cause him/her to be flushed at apply time)
usrDirtyRasProps(pRassrvUser);
return dwErr; }
// The flags are evaluated in the following order with whichever condition
// being satisfied fist defining the behavior of the function.
// bNone == TRUE => Callback is disabled for the user
// bCaller == TRUE => Callback is set to caller-settable
// bAdmin == TRUE => Callback is set to a predefine callback number set
// All 3 are FALSE => No op
DWORD usrEnableCallback ( IN HANDLE hUser, IN BOOL bNone, IN BOOL bCaller, IN BOOL bAdmin) { RASSRV_USERINFO* pRassrvUser = (RASSRV_USERINFO*)hUser; DWORD dwErr = NO_ERROR; BOOL bIsEnabled;
if (!pRassrvUser) return ERROR_INVALID_PARAMETER;
if (bNone) { pRassrvUser->bfPrivilege |= RASPRIV_NoCallback; pRassrvUser->bfPrivilege &= ~RASPRIV_CallerSetCallback; pRassrvUser->bfPrivilege &= ~RASPRIV_AdminSetCallback; } else if (bCaller) { pRassrvUser->bfPrivilege &= ~RASPRIV_NoCallback; pRassrvUser->bfPrivilege |= RASPRIV_CallerSetCallback; pRassrvUser->bfPrivilege &= ~RASPRIV_AdminSetCallback; } else if (bAdmin) { pRassrvUser->bfPrivilege &= ~RASPRIV_NoCallback; pRassrvUser->bfPrivilege &= ~RASPRIV_CallerSetCallback; pRassrvUser->bfPrivilege |= RASPRIV_AdminSetCallback; } else return NO_ERROR;
// Dirty the user (cause him/her to be flushed at apply time)
usrDirtyRasProps(pRassrvUser);
return dwErr; }
// Retreives a pointer to the callback number of the given user
DWORD usrGetCallbackNumber( IN HANDLE hUser, OUT PWCHAR * lpzNumber) { RASSRV_USERINFO* pRassrvUser = (RASSRV_USERINFO*)hUser; if (!pRassrvUser || !lpzNumber) return ERROR_INVALID_PARAMETER;
// Return the pointer to the callback number
*lpzNumber = pRassrvUser->wszPhoneNumber;
return NO_ERROR; }
// Sets the callback number of the given user. If lpzNumber is NULL,
// an empty phone number is copied.
DWORD usrSetCallbackNumber( IN HANDLE hUser, IN PWCHAR lpzNumber) { RASSRV_USERINFO* pRassrvUser = (RASSRV_USERINFO*)hUser; DWORD dwErr = NO_ERROR;
if (!pRassrvUser) return ERROR_INVALID_PARAMETER; // Modify the phone number appropriately
if (!lpzNumber) wcscpy(pRassrvUser->wszPhoneNumber, L""); else { lstrcpynW(pRassrvUser->wszPhoneNumber, lpzNumber, MAX_PHONE_NUMBER_LEN); pRassrvUser->wszPhoneNumber[MAX_PHONE_NUMBER_LEN] = (WCHAR)0; }
// Dirty the user (cause him/her to be flushed at apply time)
usrDirtyRasProps(pRassrvUser);
return dwErr; }
|