|
|
/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
user.c
Abstract:
user related option functions
Author:
Xiaofeng Zang (xiaoz) 17-Sep-2001 Created
Revision History:
<alias> <date> <comments>
--*/
#include "StdAfx.h"
#include "clmt.h"
#include <dsrole.h>
#include <Ntdsapi.h>
#include <wtsapi32.h>
#define MAX_FIELD_COUNT 7
#define OP_USER 0
#define OP_GRP 1
#define OP_PROFILE 2
#define OP_DOMAIN_GRP 3
#define TYPE_USER_PROFILE_PATH 1
#define TYPE_USER_SCRIPT_PATH 2
#define TYPE_USER_HOME_DIR 3
#define TYPE_TS_INIT_PROGRAM 4
#define TYPE_TS_WORKING_DIR 5
#define TYPE_TS_PROFILE_PATH 6
#define TYPE_TS_HOME_DIR 7
//
// Function prototypes used in user.c
//
HRESULT RenameDocuments_and_Settings(HINF, BOOL);
HRESULT ChangeUserInfo(LPTSTR, LPTSTR, LPTSTR, LPTSTR, LPTSTR, LPTSTR, LPTSTR, BOOL, BOOL, BOOL); HRESULT ChangeGroupInfo(LPTSTR, LPTSTR, LPTSTR, LPTSTR, LPTSTR, BOOL, BOOL, BOOL);
HRESULT ChangeUserName(LPTSTR, LPTSTR, BOOL, BOOL); HRESULT ChangeUserDesc(LPTSTR, LPTSTR, LPTSTR, BOOL); HRESULT ChangeUserFullName(LPTSTR, LPTSTR, LPTSTR, BOOL);
HRESULT SetUserNetworkProfilePath(LPCTSTR, LPCTSTR); HRESULT SetUserLogOnScriptPath(LPCTSTR, LPCTSTR); HRESULT SetUserHomeDir(LPCTSTR, LPCTSTR); HRESULT SetTSUserPath(LPCTSTR, LPCTSTR, WTS_CONFIG_CLASS);
HRESULT ChangeGroupName(LPTSTR, LPTSTR, BOOL, BOOL); HRESULT ChangeGroupDesc(LPTSTR, LPTSTR, LPTSTR, BOOL, BOOL);
HRESULT ChangeRDN(LPTSTR, LPTSTR, LPTSTR, BOOL);
HRESULT AddProfileChangeItem(DWORD, LPTSTR, LPTSTR, LPTSTR, LPTSTR, LPTSTR, LPTSTR);
HRESULT PolicyGetPrivilege(LPTSTR, PLSA_HANDLE, PLSA_UNICODE_STRING*, PULONG); HRESULT PolicySetPrivilege(LPTSTR, LSA_HANDLE, PLSA_UNICODE_STRING, ULONG);
HRESULT PreFixUserProfilePath(LPCTSTR, LPCTSTR, LPTSTR, DWORD); BOOL IsPathLocal(LPCTSTR); HRESULT CheckNewBuiltInUserName(LPCTSTR, LPTSTR, DWORD);
HRESULT AddProfilePathItem(LPCTSTR, LPCTSTR, LPCTSTR, LPCTSTR, DWORD); HRESULT AddTSProfilePathItem(LPCTSTR, LPCTSTR, LPCTSTR, WTS_CONFIG_CLASS);
//-----------------------------------------------------------------------------
//
// Function: UsrGrpAndDoc_and_SettingsRename
//
// Descrip: This routine renames user/group name and profile directory
// specified in section [UserGrp.ObjectRename] of the INF file
//
// Returns: TRUE if succeeds, FALSE otherwise
//
// Notes: none
//
// History: 09/17/2001 xiaoz created
//
// Notes: none
//
//-----------------------------------------------------------------------------
HRESULT UsrGrpAndDoc_and_SettingsRename( HINF hInf, // Handle to INF file
BOOL bTest ) { INFCONTEXT InfContext; LONG nLineCount, nLineIndex; LONG nFieldCount, nFieldIndex; TCHAR szType[MAX_PATH]; TCHAR szOldName[MAX_PATH]; TCHAR szNewName[MAX_PATH]; TCHAR szOldFullName[MAX_PATH]; TCHAR szNewFullName[MAX_PATH]; LPTSTR *lplpOldName; LPTSTR *lplpNewName; LPTSTR *lplpOldDesc; LPTSTR *lplpNewDesc; LPTSTR *lplpOldFullName; LPTSTR *lplpNewFullName; LPTSTR lpString[MAX_FIELD_COUNT + 1]; DWORD dwType; BOOL bRet; BOOL bCurrentUserRenamed; HRESULT hr = S_OK; BOOL bErrorOccured = FALSE; LPTSTR lpszOldComment,lpszNewComment; size_t cchMaxFieldLen[MAX_FIELD_COUNT + 1]; DWORD dwErr; PBYTE pdsInfo; WCHAR szDomainName[MAX_COMPUTERNAME_LENGTH + 1]; BOOL fIsDC;
lpszOldComment = lpszNewComment = NULL; for (nFieldIndex = 0 ; nFieldIndex <= MAX_FIELD_COUNT ; nFieldIndex++) { cchMaxFieldLen[nFieldIndex] = MAX_PATH; } // 1 for type, 2 one old name , 3 for new name
// 4 and 5 are for old and new comments
cchMaxFieldLen[4] = cchMaxFieldLen[5] = 0;
if (hInf == INVALID_HANDLE_VALUE) { hr = E_INVALIDARG; goto Exit; }
//
// Check if the machine is Domain Controller or not
//
dwErr = DsRoleGetPrimaryDomainInformation(NULL, DsRolePrimaryDomainInfoBasic, &pdsInfo); if (dwErr == ERROR_SUCCESS) { DSROLE_MACHINE_ROLE dsMachineRole;
dsMachineRole = ((DSROLE_PRIMARY_DOMAIN_INFO_BASIC *) pdsInfo)->MachineRole;
if (dsMachineRole == DsRole_RoleBackupDomainController || dsMachineRole == DsRole_RolePrimaryDomainController) { fIsDC = TRUE; hr = StringCchCopy(szDomainName, ARRAYSIZE(szDomainName), ((DSROLE_PRIMARY_DOMAIN_INFO_BASIC *) pdsInfo)->DomainNameFlat); if (FAILED(hr)) { goto Exit; } } else { fIsDC = FALSE; }
DsRoleFreeMemory(pdsInfo); } else { hr = HRESULT_FROM_WIN32(dwErr); goto Exit; }
nLineCount = SetupGetLineCount(hInf, USERGRPSECTION); if (nLineCount < 0) { DPF(PROwar, TEXT("section name [%s] is empty !"), USERGRPSECTION); hr = S_FALSE; goto Exit; }
// here we scan the whole section and find out how much space
// needed for comments
for(nLineIndex = 0 ; nLineIndex < nLineCount ; nLineIndex++) { if (SetupGetLineByIndex(hInf, USERGRPSECTION, nLineIndex, &InfContext)) { nFieldCount = SetupGetFieldCount(&InfContext);
// We need at least 3 fields to be valid input
if (nFieldCount < 3) { DPF(PROerr, TEXT("section name [%s] line %d error:missing field !"), USERGRPSECTION,nLineIndex); hr = HRESULT_FROM_WIN32(ERROR_BAD_FORMAT); goto Exit; }
//if there is no comments field, just skip
if (nFieldCount < 4) { continue; }
for (nFieldIndex = 4 ; nFieldIndex <= 5 ; nFieldIndex++) { DWORD cchReqSize;
if (!SetupGetStringField(&InfContext, nFieldIndex, NULL, 0, &cchReqSize)) { DPF(PROerr, TEXT("Failed to get field [%d] from line [%d] in section [%s]"), nFieldIndex, nLineIndex, USERGRPSECTION);
hr = HRESULT_FROM_WIN32(GetLastError()); goto Exit; } if (cchMaxFieldLen[nFieldIndex] < cchReqSize) { cchMaxFieldLen[nFieldIndex] = cchReqSize; } } } else { DPF(PROerr, TEXT("can not get line [%d] of section [%s]!"), nLineIndex, USERGRPSECTION); hr = HRESULT_FROM_WIN32(GetLastError()); goto Exit; } } if (cchMaxFieldLen[4]) { cchMaxFieldLen[4]++; lpszOldComment = malloc(cchMaxFieldLen[4]*sizeof(TCHAR)); } if (cchMaxFieldLen[5]) { cchMaxFieldLen[5]++; lpszNewComment = malloc(cchMaxFieldLen[5]*sizeof(TCHAR)); } if ( (!lpszNewComment && lpszOldComment) || (lpszNewComment && !lpszOldComment) ) { hr = E_OUTOFMEMORY; goto Exit; }
//here we do real stuff
for(nLineIndex = 0 ; nLineIndex < nLineCount ; nLineIndex++) { // we think user name and full name should not exceed MAX_PATH
// if we meet this, we will just ignored(skipp this line)
// the following variable is used to flag whether we meed
// such field.
BOOL bMeetUnexpectedLongField = FALSE;
lpString[1] = szType; lpString[2] = szOldName; lpString[3] = szNewName; lpString[4] = lpszOldComment; lpString[5] = lpszNewComment; lpString[6] = szOldFullName; lpString[7] = szNewFullName;
lplpOldName = &lpString[2]; lplpNewName = &lpString[3]; lplpOldDesc = &lpString[4]; lplpNewDesc = &lpString[5]; lplpOldFullName = &lpString[6]; lplpNewFullName = &lpString[7];
//
// Fetch data from INF file
//
if (SetupGetLineByIndex(hInf, USERGRPSECTION, nLineIndex, &InfContext)) { nFieldCount = SetupGetFieldCount(&InfContext);
// We need at least 3 fields to be valid input
if (nFieldCount < 3) { DPF(PROerr, TEXT("section name [%s] line %d error:missing field !"), USERGRPSECTION,nLineIndex); hr = HRESULT_FROM_WIN32(ERROR_BAD_FORMAT); goto Exit; }
// Read all the fields in INF line
// Field index for values starts from 1, field 0 is key name
for (nFieldIndex = 1 ; nFieldIndex <= nFieldCount ; nFieldIndex++) { DWORD cchReqSize;
if (!SetupGetStringField(&InfContext, nFieldIndex, lpString[nFieldIndex], cchMaxFieldLen[nFieldIndex], &cchReqSize)) { dwErr = GetLastError(); if (dwErr == ERROR_MORE_DATA) { bMeetUnexpectedLongField = TRUE; continue; } else { DPF(PROerr, TEXT("Failed to get field [%d] from line [%d] in section [%s]"), nFieldIndex, nLineIndex, USERGRPSECTION); hr = HRESULT_FROM_WIN32(GetLastError()); goto Exit; } } } if (bMeetUnexpectedLongField) { DPF(PROwar, TEXT("user name or full name too long in line [%d] in section [%s]"), nLineIndex, USERGRPSECTION); continue; } // If INF line does not supply all the field,
// set the pointers to the rest of fields to NULL
for (nFieldIndex = nFieldCount + 1 ; nFieldIndex <= MAX_FIELD_COUNT ; nFieldIndex++) { lpString[nFieldIndex] = NULL; } } else { DPF(PROerr, TEXT("can not get line [%d] of section [%s]!"), nLineIndex, USERGRPSECTION); hr = HRESULT_FROM_WIN32(GetLastError()); goto Exit; }
//
// Process the fetched data
//
dwType = _tstoi(szType);
switch (dwType & 0xFFFF) { case OP_USER:
hr = ChangeUserInfo(*lplpOldName, *lplpNewName, *lplpOldDesc, *lplpNewDesc, *lplpOldFullName, *lplpNewFullName, szDomainName, bTest, fIsDC, dwType & 0xFFFF0000 ? TRUE:FALSE); if (FAILED(hr)) { DPF(PROerr, TEXT("UsrGrpAndDoc_and_SettingsRename: Failed to change user info for account <%s>"), *lplpOldName); bErrorOccured = TRUE; }
break;
case OP_GRP:
hr = ChangeGroupInfo(*lplpOldName, *lplpNewName, *lplpOldDesc, *lplpNewDesc, szDomainName, bTest, fIsDC, FALSE); if (FAILED(hr)) { DPF(PROerr, TEXT("UsrGrpAndDoc_and_SettingsRename: Failed to change group info for account <%s>"), *lplpOldName); bErrorOccured = TRUE; }
break;
case OP_PROFILE:
hr = RenameDocuments_and_Settings(hInf,bTest); if (FAILED(hr)) { DPF(PROerr,TEXT("changing profiled directory failed")); bErrorOccured = TRUE; }
break;
case OP_DOMAIN_GRP:
if (fIsDC) { hr = ChangeGroupInfo(*lplpOldName, *lplpNewName, *lplpOldDesc, *lplpNewDesc, szDomainName, bTest, fIsDC, TRUE); if (FAILED(hr)) { DPF(PROerr, TEXT("UsrGrpAndDoc_and_SettingsRename: Failed to change group info for account <%s>"), *lplpOldName); bErrorOccured = TRUE; } }
break; }
if ((hr == S_OK) && bTest) { hr = AddProfileChangeItem(dwType & 0xFFFF, *lplpOldName, *lplpNewName, *lplpOldDesc, *lplpNewDesc, *lplpOldFullName, *lplpNewFullName); } }
if (bErrorOccured) { hr = E_FAIL; }
Exit: FreePointer(lpszOldComment); FreePointer(lpszNewComment); return hr; }
/*++
Routine Description:
This routine renames a user name and updated all related setting(eg user's profile directory,current logon default name , comments... Arguments:
szUsrName - original user name szNewUsrName - the new user name szComments - comments of new user name szFullName - Full name of the new user name
Return Value:
TRUE if succeeds --*/ HRESULT ChangeUserInfo( LPTSTR lpOldName, // Old user name
LPTSTR lpNewName, // New user name
LPTSTR lpOldDesc, // Old user description
LPTSTR lpNewDesc, // New user description
LPTSTR lpOldFullName, // (optional) Old user full name
LPTSTR lpNewFullName, // (optional) New user full name
LPTSTR lpDomainName, // (optional) Machine domain name
BOOL bTest, // Analyze mode or not
BOOL fIsDC, // Is the machine a Domain Controller
BOOL bCreateHardLink ) { HRESULT hr = S_OK; DWORD dwErr; NET_API_STATUS status; USER_INFO_0 usrinfo0; BOOL bNameChanged = FALSE; if (lpOldName == NULL || lpNewName == NULL) { hr = E_INVALIDARG; goto Exit; }
//
// Reset the Comment for the User
//
if (lpOldDesc != NULL && lpNewDesc != NULL) { hr = ChangeUserDesc(lpOldName, lpOldDesc, lpNewDesc, bTest); if (FAILED(hr)) { DPF(PROerr, TEXT("ChangerUserInfo: Failed to change description for user <%s>"), lpOldName); goto Exit; } }
//
// Reset the Full Name of the User
//
if (lpOldFullName != NULL && lpNewFullName != NULL) { hr = ChangeUserFullName(lpOldName, lpOldFullName, lpNewFullName, bTest); if (FAILED(hr)) { DPF(PROerr, TEXT("ChangeUserInfo: Failed to change Full Name for user <%s>"), lpOldName); goto Exit; } }
//
// Reset the user CN name for the user (RDN)
//
if (fIsDC) { hr = ChangeRDN(lpOldName, lpNewName, lpDomainName, bTest); if (FAILED(hr)) { DPF(PROerr, TEXT("ChangeUserInfo: Failed to change RDN for user <%s>"), lpOldName); goto Exit; } }
//
// Reset the user name (SAM account name)
//
if (MyStrCmpI(lpOldName, lpNewName) != LSTR_EQUAL) { hr = ChangeUserName(lpOldName, lpNewName, bTest,bCreateHardLink); if (FAILED(hr)) { DPF(PROerr, TEXT("ChangeUserInfo: Failed to change SAM account name for user <%s>"), lpOldName); goto Exit; } }
Exit: return hr; }
//-----------------------------------------------------------------------------
//
// Function: ChangeGroupInfo
//
// Descrip: Chage the local group information
// - Account name (SAM account name)
// - Account RDN
// - Description
//
// Returns: S_OK - Group information is okay to change
// S_FALSE - Group name cannot be changed (not an error)
// otherwise - error occured
//
// Notes: none
//
// History: 09/17/2001 xiaoz created
// 04/25/2002 Rerkboos Modified to work with domain group
//
// Notes: none
//
//-----------------------------------------------------------------------------
HRESULT ChangeGroupInfo( LPTSTR lpOldName, // Old user name
LPTSTR lpNewName, // New user name
LPTSTR lpOldDesc, // Old user description
LPTSTR lpNewDesc, // New user description
LPTSTR lpDomainName, // (optional) Machine domain name
BOOL bTest, // Analyze mode or not
BOOL fIsDC, // Is the machine a Domain Controller
BOOL bUseDomainAPI // Use domain API or not
) { HRESULT hr = S_OK;
if (lpOldName == NULL || lpNewName == NULL) { return E_INVALIDARG; }
//
// Change group description
//
if (lpOldDesc && lpNewDesc) { hr = ChangeGroupDesc(lpOldName, lpOldDesc, lpNewDesc, bTest, bUseDomainAPI); if (FAILED(hr)) { DPF(PROerr, TEXT("ChangeGroupInfo: Failed to change description for group <%s>"), lpOldName); goto Exit; } }
//
// Change group RDN
//
if (fIsDC) { hr = ChangeRDN(lpOldName, lpNewName, lpDomainName, bTest); if (FAILED(hr)) { DPF(PROerr, TEXT("ChangeGroupInfo: Failed to change RDN for group <%s>"), lpOldName); goto Exit; } }
//
// Change group name (SAM)
//
if (MyStrCmpI(lpOldName, lpNewName) != LSTR_EQUAL) { hr = ChangeGroupName(lpOldName, lpNewName, bTest, bUseDomainAPI); if (FAILED(hr)) { DPF(PROerr, TEXT("ChangeGroupInfo: Failed to change SAM account name for group <%s>"), lpOldName); goto Exit; } }
Exit: return hr; }
//-----------------------------------------------------------------------------
//
// Function: ChangeUserName
//
// Descrip: Chage the User name (SAM account name)
//
// Returns: S_OK - User name is okay to change
// S_FALSE - User name cannot be changed (not an error)
// otherwise - error occured
//
// Notes: none
//
// History: 09/17/2001 xiaoz created
// 04/25/2002 Rerkboos Modified to work with domain group
//
// Notes: none
//
//-----------------------------------------------------------------------------
HRESULT ChangeUserName( LPTSTR lpOldName, // Old user name
LPTSTR lpNewName, // New user name
BOOL bTest, // Analyze mode or not
BOOL bCreateHardLink ) { LPUSER_INFO_0 lpUsrInfo0; USER_INFO_1052 usrinfo1052; USER_INFO_0 usrinfo0New; NET_API_STATUS nStatus; DWORD dwErr, dwLen; HRESULT hr; TCHAR szProfilePath[MAX_PATH],szNewProfilePath[MAX_PATH]; TCHAR szExpProfilePath[MAX_PATH],szExpNewProfilePath[MAX_PATH]; TCHAR szLogonName[MAX_PATH]; LPTSTR lpCurrProfileDir; LPTSTR lpCurrUsername; BOOL bCheckRegistry = TRUE;
if (lpOldName == NULL || lpNewName == NULL) { hr = E_INVALIDARG; goto Exit; }
if (MyStrCmpI(lpOldName, lpNewName) == 0) { hr = S_OK; goto Exit; }
hr = GetSetUserProfilePath(lpOldName, szProfilePath, MAX_PATH, PROFILE_PATH_READ, REG_EXPAND_SZ); if (HRESULT_CODE(hr) == ERROR_FILE_NOT_FOUND) { bCheckRegistry = FALSE; } else if (FAILED(hr)) { goto Exit; }
if (bCheckRegistry) { // Compute a new unique profile directory name
if ( !ComputeLocalProfileName(lpOldName, lpNewName, szNewProfilePath, ARRAYSIZE(szNewProfilePath), REG_EXPAND_SZ) ) { hr = E_FAIL; goto Exit; } } if (bTest) { lpCurrProfileDir = szProfilePath; lpCurrUsername = lpOldName; } else { lpCurrProfileDir = szNewProfilePath; lpCurrUsername = lpNewName; }
// Search for the old user name in the system
nStatus = NetUserGetInfo(NULL, lpOldName, 0, (LPBYTE *) &lpUsrInfo0); switch (nStatus) { case NERR_Success: // user name found, reset the name to new one
usrinfo0New.usri0_name = lpCurrUsername; nStatus = NetUserSetInfo(NULL, lpOldName, 0, (LPBYTE) &usrinfo0New, &dwErr); if (nStatus == NERR_Success) { hr = S_OK; } else { hr = HRESULT_FROM_WIN32(nStatus); }
NetApiBufferFree(lpUsrInfo0); break;
case NERR_UserNotFound: // user name is not found on the system
hr = S_FALSE; break;
default: // error occured
hr = HRESULT_FROM_WIN32(nStatus); break; } if (hr != S_OK) { goto Exit; } //here it means we succeeded change (or test changing) the user name
//change user profile path through netapi if necessary
if (bCheckRegistry) { //Expand the original and new profile path
if (!ExpandEnvironmentStrings(szProfilePath, szExpProfilePath, MAX_PATH)) { goto Exit; } if (!ExpandEnvironmentStrings(szNewProfilePath, szExpNewProfilePath, MAX_PATH)) { goto Exit; }
//If it's not test, we do real renaming)
if (!bTest) { } else { LPTSTR lpOld,lpNew;
hr = MyMoveDirectory(szExpProfilePath,szExpNewProfilePath,TRUE,bTest,FALSE,0); if(FAILED(hr)) { DPF (APPerr, L"Move Dir from %s to %s failed ! Error Code %d (%#x)", szExpProfilePath,szExpNewProfilePath,hr, hr); goto Exit; } if (bCreateHardLink) { TCHAR szCommonPerfix[MAX_PATH+1]; TCHAR szLinkName[2 * MAX_PATH], szLinkValue[2 * MAX_PATH];
if (PathCommonPrefix(szExpProfilePath,szExpNewProfilePath,szCommonPerfix)) { LPTSTR lpszOlduserName = szExpProfilePath,lpszNewuserName = szExpNewProfilePath;
lpszOlduserName += lstrlen(szCommonPerfix); lpszNewuserName += lstrlen(szCommonPerfix); szCommonPerfix[1] = TEXT('\0'); if (lpszOlduserName && lpszNewuserName) { HRESULT myhr, myhr1; myhr = StringCchCopy(szLinkName,ARRAYSIZE(szLinkName),szCommonPerfix); myhr = StringCchCat(szLinkName,ARRAYSIZE(szLinkName),TEXT(":\\Documents and Settings\\"));
myhr = StringCchCopy(szLinkValue,ARRAYSIZE(szLinkValue),szCommonPerfix); myhr = StringCchCat(szLinkValue,ARRAYSIZE(szLinkValue),TEXT(":\\Documents and Settings\\"));
myhr = StringCchCat(szLinkName,ARRAYSIZE(szLinkName),lpszOlduserName); myhr1 = StringCchCat(szLinkValue,ARRAYSIZE(szLinkValue),lpszNewuserName); if ( (myhr == S_OK) && (myhr1 == S_OK) ) { hr = AddHardLinkEntry(szLinkName,szLinkValue,TEXT("0"),NULL,NULL,NULL); } } } } AddUserNameChangeLog(lpOldName, lpNewName);
lpOld = StrRChrI(szExpProfilePath,NULL,TEXT('\\')); lpNew = StrRChrI(szExpNewProfilePath,NULL,TEXT('\\')); if (lpOld && lpNew) { if (!AddItemToStrRepaceTable((LPTSTR) lpOldName, (LPTSTR) lpOld+1, (LPTSTR) lpNew+1, szExpProfilePath, CSIDL_USERNAME_IN_USERPROFILE, &g_StrReplaceTable)) { hr = E_OUTOFMEMORY; goto Exit; } } }
//Get current login user name
dwLen = ARRAYSIZE(szLogonName); if (!GetUserName(szLogonName, &dwLen)) { hr = HRESULT_FROM_WIN32(GetLastError()); goto Exit; } // rename the profile path, if the current user profile path needs to be changed
// we have to do a delayed renaming
if (!MyStrCmpI(szLogonName,lpOldName)) { #define DEFAULT_USERNAME_KEY TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon")
hr = RegResetValue(HKEY_LOCAL_MACHINE, DEFAULT_USERNAME_KEY, TEXT("DefaultUserName"), REG_SZ, lpOldName, lpCurrUsername, 0, NULL); if(FAILED(hr)) { goto Exit; }
hr = RegResetValue(HKEY_LOCAL_MACHINE, DEFAULT_USERNAME_KEY, TEXT("AltDefaultUserName"), REG_SZ, lpOldName, lpCurrUsername, 0, NULL); if(FAILED(hr)) { goto Exit; } } } hr = S_OK; Exit: return hr; }
//-----------------------------------------------------------------------------
//
// Function: ChangeGroupName
//
// Descrip: Chage the Group name (SAM account name)
//
// Returns: S_OK - group name is okay to change
// S_FALSE - group name cannot be changed (not an error)
// otherwise - error occured
//
// Notes: none
//
// History: 09/17/2001 xiaoz created
// 04/25/2002 Rerkboos Modified to work with domain group
//
// Notes: none
//
//-----------------------------------------------------------------------------
HRESULT ChangeGroupName( LPTSTR lpOldName, // Old user name
LPTSTR lpNewName, // New user name
BOOL bTest, // Analyze mode or not
BOOL bDomainAPI // Local group API or not
) { HRESULT hr = S_OK; NET_API_STATUS nStatus; DWORD dwErr; PLOCALGROUP_INFO_1 plgrpi1LocalGroup = NULL; PGROUP_INFO_1 pgrpi1DomainGroup = NULL; LOCALGROUP_INFO_0 lgrpi0NewName; GROUP_INFO_0 grpi0NewName; PPVOID ppvGroupInfo; PPVOID ppvNewGroupInfo; LPTSTR lpCurrentName; PVOID pvNewGroupNameInfo; LSA_HANDLE PolicyHandle; PLSA_UNICODE_STRING pPrivileges; ULONG CountOfRights; BOOL bGotGP = FALSE;
DWORD (*pfnGroupGetInfo)(LPCWSTR, LPCWSTR, DWORD, LPBYTE *); DWORD (*pfnGroupSetInfo)(LPCWSTR, LPCWSTR, DWORD, LPBYTE, LPDWORD);
if (lpOldName == NULL || lpNewName == NULL) { return E_INVALIDARG; }
//
// Choose which set of APIs/variables we will use
//
if (bDomainAPI) { // Domain group
ppvGroupInfo = &pgrpi1DomainGroup; ppvNewGroupInfo = &pgrpi1DomainGroup; pvNewGroupNameInfo = &grpi0NewName; pfnGroupGetInfo = &NetGroupGetInfo; pfnGroupSetInfo = &NetGroupSetInfo; } else { // Local group
ppvGroupInfo = &plgrpi1LocalGroup; ppvNewGroupInfo = &plgrpi1LocalGroup; pvNewGroupNameInfo = &lgrpi0NewName; pfnGroupGetInfo = &NetLocalGroupGetInfo; pfnGroupSetInfo = &NetLocalGroupSetInfo; }
//
// Check whether the new group name has already been used in the system or not
//
nStatus = (*pfnGroupGetInfo)(NULL, lpNewName, 1, (LPBYTE *) ppvNewGroupInfo); if (nStatus == NERR_Success) { // New group name already exists in the system,
// don't change the group name
NetApiBufferFree(*ppvNewGroupInfo); return S_FALSE; }
//
// Check wheter the old user name exists in the system or not
//
nStatus = (*pfnGroupGetInfo)(NULL, lpOldName, 1, (LPBYTE *) ppvGroupInfo); switch (nStatus) { case NERR_Success:
if (bDomainAPI) { lpCurrentName = pgrpi1DomainGroup->grpi1_name ; } else { lpCurrentName = plgrpi1LocalGroup->lgrpi1_name; } if (bTest) { // in analyzing mode, use the old group name
lgrpi0NewName.lgrpi0_name = lpCurrentName; grpi0NewName.grpi0_name = lpCurrentName; } else { // in modifying mode, use the new group name from INF
lgrpi0NewName.lgrpi0_name = lpNewName; grpi0NewName.grpi0_name = lpNewName; }
if (!bTest) { HRESULT hrGP = PolicyGetPrivilege(lpOldName, &PolicyHandle, &pPrivileges, &CountOfRights); if (hrGP == S_OK) { bGotGP = TRUE; } }
//
// Set the new group name (SAM account name)
//
nStatus = (*pfnGroupSetInfo)(NULL, lpOldName, 0, (LPBYTE) pvNewGroupNameInfo, &dwErr); if (nStatus == NERR_Success) { hr = S_OK; } else { hr = HRESULT_FROM_WIN32(nStatus); }
if (bGotGP) { if (SUCCEEDED(hr)) { // Reset the policy
hr = PolicySetPrivilege(lpNewName, PolicyHandle, pPrivileges, CountOfRights); }
LsaFreeMemory(pPrivileges); LsaClose(PolicyHandle); }
NetApiBufferFree(*ppvGroupInfo); break;
case ERROR_NO_SUCH_ALIAS: case NERR_GroupNotFound:
hr = S_FALSE; break;
default: hr = HRESULT_FROM_WIN32(nStatus); }
return hr; }
//-----------------------------------------------------------------------------
//
// Function: ChangeUserDesc
//
// Descrip: Chage the User description
//
// Returns: S_OK - User description is okay to change
// S_FALSE - User description cannot be changed (not an error)
// otherwise - error occured
//
// Notes: none
//
// History: 09/17/2001 xiaoz created
// 04/25/2002 Rerkboos Modified to work with domain group
//
// Notes: none
//
//-----------------------------------------------------------------------------
HRESULT ChangeUserDesc( LPTSTR lpUserName, // User name
LPTSTR lpOldDesc, // Old user description
LPTSTR lpNewDesc, // New user description
BOOL bTest // Anylyze mode or not
) { LPUSER_INFO_10 lpUsrInfo10; USER_INFO_1007 usri1007New; NET_API_STATUS nStatus; DWORD dwErr; HRESULT hr;
if (lpUserName == NULL || lpOldDesc == NULL || lpNewDesc == NULL) { return E_INVALIDARG; }
if (MyStrCmpI(lpOldDesc, lpNewDesc) == LSTR_EQUAL) { return S_OK; }
// Get the current comment for user
nStatus = NetUserGetInfo(NULL, lpUserName, 10, (LPBYTE *) &lpUsrInfo10); switch (nStatus) { case NERR_Success: // old comment found
if (MyStrCmpI(lpUsrInfo10->usri10_comment, lpOldDesc) == 0) { if (bTest) { usri1007New.usri1007_comment = lpOldDesc; } else { usri1007New.usri1007_comment = lpNewDesc; } nStatus = NetUserSetInfo(NULL, lpUserName, 1007, (LPBYTE) &usri1007New, &dwErr); if (nStatus == NERR_Success) { hr = S_OK; } else { hr = HRESULT_FROM_WIN32(nStatus); } } else { hr = S_OK; }
NetApiBufferFree(lpUsrInfo10); break; case NERR_UserNotFound: hr = S_FALSE; break; default: // error occured
hr = HRESULT_FROM_WIN32(nStatus); break; }
return hr; }
//-----------------------------------------------------------------------------
//
// Function: ChangeGroupDesc
//
// Descrip: Chage the group description
//
// Returns: S_OK - Group description is okay to change
// S_FALSE - Group description cannot be changed (not an error)
// otherwise - error occured
//
// Notes: none
//
// History: 09/17/2001 xiaoz created
// 04/25/2002 Rerkboos Modified to work with domain group
//
// Notes: We will change commments first if we meet following 3 conditions
// 1. Both old and new comments are present
// 2. Old description (from INF file which is OS default) is same as
// current group's comment
// 3. Old and new comments are different
//
//-----------------------------------------------------------------------------
HRESULT ChangeGroupDesc( LPTSTR lpGroupName, // User name
LPTSTR lpOldDesc, // Old description
LPTSTR lpNewDesc, // New description
BOOL bTest, // Anylyze mode or not
BOOL bDomainAPI // Is Domain Net API
) { HRESULT hr; NET_API_STATUS nStatus; PLOCALGROUP_INFO_1 plgrpi1LocalGroup = NULL; PGROUP_INFO_1 pgrpi1DomainGroup = NULL; LOCALGROUP_INFO_1 lgrpi1NewComment; GROUP_INFO_1 grpi1NewComment; PPVOID ppvGroupInfo; PVOID pvNewGroupCommentInfo; LPTSTR lpCurrentComment; DWORD dwErr;
DWORD (*pfnGroupGetInfo)(LPCWSTR, LPCWSTR, DWORD, LPBYTE *); DWORD (*pfnGroupSetInfo)(LPCWSTR, LPCWSTR, DWORD, LPBYTE, LPDWORD);
if (lpGroupName == NULL || lpOldDesc == NULL || lpNewDesc == NULL) { return E_INVALIDARG; }
if (MyStrCmpI(lpOldDesc, lpNewDesc) == LSTR_EQUAL) { // Default group description are the same, do nothing
return S_FALSE; }
//
// Choose which set of APIs/variables we will use
//
if (bDomainAPI) { // Domain group
ppvGroupInfo = &pgrpi1DomainGroup; pvNewGroupCommentInfo = &grpi1NewComment; pfnGroupGetInfo = &NetGroupGetInfo; pfnGroupSetInfo = &NetGroupSetInfo; } else { // Local group
ppvGroupInfo = &plgrpi1LocalGroup; pvNewGroupCommentInfo = &lgrpi1NewComment; pfnGroupGetInfo = &NetLocalGroupGetInfo; pfnGroupSetInfo = &NetLocalGroupSetInfo; }
// Get the current group description
nStatus = (*pfnGroupGetInfo)(NULL, lpGroupName, 1, (LPBYTE *) ppvGroupInfo); switch (nStatus) { case NERR_Success: if (bDomainAPI) { lpCurrentComment = pgrpi1DomainGroup->grpi1_comment ; } else { lpCurrentComment = plgrpi1LocalGroup->lgrpi1_comment; }
if (bTest) { //In analyzing mode , we do a reset old value to see whether we will succeed
lgrpi1NewComment.lgrpi1_comment = lpCurrentComment; grpi1NewComment.grpi1_comment = lpCurrentComment; } else { // in modifying mode, use the new group comment from INF
lgrpi1NewComment.lgrpi1_comment = lpNewDesc; grpi1NewComment.grpi1_comment = lpNewDesc; }
//
// Set the new group comment
//
nStatus = (*pfnGroupSetInfo)(NULL, lpGroupName, 1, (LPBYTE) pvNewGroupCommentInfo, &dwErr); if (nStatus == NERR_Success) { hr = S_OK; } else { hr = HRESULT_FROM_WIN32(nStatus); }
NetApiBufferFree(*ppvGroupInfo); break;
case ERROR_NO_SUCH_ALIAS: case NERR_GroupNotFound:
hr = S_FALSE; break;
default: hr = HRESULT_FROM_WIN32(nStatus); }
return hr; }
//-----------------------------------------------------------------------------
//
// Function: ChangeUserFullName
//
// Descrip: Chage the User full name
//
// Returns: S_OK - User full name is okay to change
// S_FALSE - User full name cannot be changed (not an error)
// otherwise - error occured
//
// Notes: none
//
// History: 09/17/2001 xiaoz created
// 04/25/2002 Rerkboos Modified to work with domain group
//
// Notes: none
//
//-----------------------------------------------------------------------------
HRESULT ChangeUserFullName( LPTSTR lpUserName, // User name
LPTSTR lpOldFullName, // Old full name
LPTSTR lpNewFullName, // New full name
BOOL bTest // Anylyze mode or not
) { LPUSER_INFO_10 lpUsrInfo10; USER_INFO_1011 usri1011New; NET_API_STATUS nStatus; DWORD dwErr; HRESULT hr;
if (lpUserName == NULL || lpOldFullName == NULL || lpNewFullName == NULL) { return E_INVALIDARG; }
if (MyStrCmpI(lpOldFullName, lpNewFullName) == 0) { return S_OK; }
// Get the current comment for user
nStatus = NetUserGetInfo(NULL, lpUserName, 10, (LPBYTE *) &lpUsrInfo10); switch (nStatus) { case NERR_Success: // old comment found
if (MyStrCmpI(lpUsrInfo10->usri10_full_name, lpOldFullName) == 0) { if (bTest) { usri1011New.usri1011_full_name = lpOldFullName; } else { usri1011New.usri1011_full_name = lpNewFullName; } nStatus = NetUserSetInfo(NULL, lpUserName, 1011, (LPBYTE) &usri1011New, &dwErr); if (nStatus == NERR_Success) { hr = S_OK; } else { hr = HRESULT_FROM_WIN32(nStatus); } } else { hr = S_OK; }
NetApiBufferFree(lpUsrInfo10); break; case NERR_UserNotFound: hr = S_FALSE; break; default: // error occured
hr = HRESULT_FROM_WIN32(nStatus); break; }
return hr; }
//-----------------------------------------------------------------------------
//
// Function: SetUserNetworkProfilePath
//
// Descrip: Set the path to network user's profile.
//
// Returns: S_OK - profile path is changed correctly
//
// History: 05/20/2002 Rerkboos Created
//
// Notes: none
//
//-----------------------------------------------------------------------------
HRESULT SetUserNetworkProfilePath( LPCTSTR lpUserName, // User Name
LPCTSTR lpNewPath // New Path
) { HRESULT hr = S_OK; NET_API_STATUS nStatus; USER_INFO_1052 usri1052;
if (lpNewPath == NULL || *lpNewPath == TEXT('\0')) { return S_FALSE; }
usri1052.usri1052_profile = (LPTSTR) lpNewPath; nStatus = NetUserSetInfo(NULL, lpUserName, 1052, (LPBYTE) &usri1052, NULL); if (nStatus != NERR_Success) { hr = HRESULT_FROM_WIN32(nStatus); }
return hr; }
//-----------------------------------------------------------------------------
//
// Function: SetUserLogOnScriptPath
//
// Descrip: Set the path to users's logon script file.
//
// Returns: S_OK - profile path is changed correctly
//
// History: 05/20/2002 Rerkboos Created
//
// Notes: none
//
//-----------------------------------------------------------------------------
HRESULT SetUserLogOnScriptPath( LPCTSTR lpUserName, // User Name
LPCTSTR lpNewPath // New path
) { HRESULT hr = S_OK; NET_API_STATUS nStatus; USER_INFO_1009 usri1009;
if (lpNewPath == NULL || *lpNewPath == TEXT('\0')) { return S_FALSE; }
usri1009.usri1009_script_path = (LPTSTR) lpNewPath; nStatus = NetUserSetInfo(NULL, lpUserName, 1009, (LPBYTE) &usri1009, NULL); if (nStatus != NERR_Success) { hr = HRESULT_FROM_WIN32(nStatus); }
return hr; }
//-----------------------------------------------------------------------------
//
// Function: SetUserHomeDir
//
// Descrip: Set the path of the home directory for the user
//
// Returns: S_OK - profile path is changed correctly
//
// History: 05/20/2002 Rerkboos Created
//
// Notes: none
//
//-----------------------------------------------------------------------------
HRESULT SetUserHomeDir( LPCTSTR lpUserName, // User Name
LPCTSTR lpNewPath // New path
) { HRESULT hr = S_OK; NET_API_STATUS nStatus; USER_INFO_1006 usri1006;
if (lpNewPath == NULL || *lpNewPath == TEXT('\0')) { return S_FALSE; }
usri1006.usri1006_home_dir = (LPTSTR) lpNewPath; nStatus = NetUserSetInfo(NULL, lpUserName, 1006, (LPBYTE) &usri1006, NULL); if (nStatus != NERR_Success) { hr = HRESULT_FROM_WIN32(nStatus); }
return hr; }
//-----------------------------------------------------------------------------
//
// Function: SetTSUserPath
//
// Descrip: Set the Terminal Services related profile path. The type of
// profile path is determined by WTSConfigClass parameter.
//
// Returns: S_OK - profile path is changed correctly
//
// History: 05/20/2002 Rerkboos Created
//
// Notes: none
//
//-----------------------------------------------------------------------------
HRESULT SetTSUserPath( LPCTSTR lpUserName, // User Name
LPCTSTR lpNewProfilePath, // New path
WTS_CONFIG_CLASS WTSConfigClass // TS configuration class
) { HRESULT hr = S_OK; BOOL bRet; DWORD cbNewProfilePath;
cbNewProfilePath = lstrlen(lpNewProfilePath) * sizeof(TCHAR); bRet = WTSSetUserConfig(WTS_CURRENT_SERVER_NAME, (LPTSTR) lpUserName, WTSConfigClass, (LPTSTR) lpNewProfilePath, cbNewProfilePath); if (!bRet) { hr = HRESULT_FROM_WIN32(GetLastError()); }
return hr; }
//-----------------------------------------------------------------------------
//
// Function: PreFixUserProfilePath
//
// Descrip: Replace the "%documents_and_settings%\OldUserName\..." to
// "%documents_and_settings%\NewUserName\...". The function will
// not fix the paths after "%documents_and_settings%\OldUserName",
// they will just get append to the new profile path.
//
// Returns: S_OK - Path has been fixed
// S_FALSE - Path does not need the fix
// Else - error occurred
//
// History: 05/20/2002 Rerkboos Created
// 06/16/2002 Rerkboos Change to return HRESULT
//
// Notes: none
//
//-----------------------------------------------------------------------------
HRESULT PreFixUserProfilePath( LPCTSTR lpOldPath, // Old path
LPCTSTR lpNewProfilePath, // Expected new profile path (with unloc user name)
LPTSTR lpPath, // Buffer to store new profile path
DWORD cchPath // Size of buffer (in TCHAR)
) { HRESULT hr = S_OK; BOOL bRet; TCHAR szNewPath[MAX_PATH]; DWORD cchNewProfilePath; TCHAR chEnd;
cchNewProfilePath = lstrlen(lpNewProfilePath); if (StrCmpNI(lpNewProfilePath, lpOldPath, cchNewProfilePath) == LSTR_EQUAL) { chEnd = *(lpOldPath + cchNewProfilePath);
if (chEnd == TEXT('\\')) { hr = StringCchCopy(szNewPath, ARRAYSIZE(szNewPath), lpNewProfilePath); if (SUCCEEDED(hr)) { bRet = ConcatenatePaths(szNewPath, (lpOldPath + cchNewProfilePath + 1), ARRAYSIZE(szNewPath)); if (bRet) { if ((DWORD) lstrlen(szNewPath) < cchPath) { hr = StringCchCopy(lpPath, cchPath, szNewPath); } } else { hr = E_FAIL; } } } else if (chEnd == TEXT('\0')) { if ((DWORD) lstrlen(lpNewProfilePath) < cchPath) { hr = StringCchCopy(lpPath, cchPath, lpNewProfilePath); } } } else { hr = StringCchCopy(lpPath, cchPath, lpOldPath); hr = (FAILED(hr) ? hr : S_FALSE); }
return hr; }
//-----------------------------------------------------------------------------
//
// Function: ReplaceLocStringInPath
//
// Descrip: This is a simplify version of ReplaceSingleString() from utils.c
// The function will replace all localized strings in path without
// checking that the path is valid or not. As we are already know
// that the input path MUST be valid one.
//
// Returns: Address to newly allocated string buffer if the function does
// replace localized string(s).
// NULL otherwise.
//
// History: 05/22/2002 rerkboos created
//
// Notes: Caller must free the allocated memory using HeapFree() API or
// MEMFREE() macro.
//
//-----------------------------------------------------------------------------
LPTSTR ReplaceLocStringInPath( LPCTSTR lpOldString, BOOL bVerifyPath ) { LPTSTR lpNewString = NULL; DWORD cchNewString; DWORD dwMatchNum; DWORD dwNumReplaced; BOOL bRet;
if (lpOldString == NULL || *lpOldString == TEXT('\0')) { return NULL; }
dwMatchNum = GetMaxMatchNum((LPTSTR) lpOldString, &g_StrReplaceTable);
if (dwMatchNum > 0) { cchNewString = lstrlen(lpOldString) + (g_StrReplaceTable.cchMaxStrLen * dwMatchNum); lpNewString = (LPTSTR) MEMALLOC(cchNewString * sizeof(TCHAR));
if (lpNewString != NULL) { bRet = ReplaceMultiMatchInString((LPTSTR) lpOldString, lpNewString, cchNewString, dwMatchNum, &g_StrReplaceTable, &dwNumReplaced, bVerifyPath); if (!bRet) { MEMFREE(lpNewString); lpNewString = NULL; } } }
return lpNewString; }
//-----------------------------------------------------------------------------
//
// Function: ChangeRDN
//
// Descrip: Chage the User/group RDN
//
// Returns: S_OK - User/group RDN is okay to change
// S_FALSE - User/group RDN cannot be changed (not an error)
// otherwise - error occured
//
// History: 09/17/2001 xiaoz created
// 04/25/2002 Rerkboos Modified to work with domain group
//
// Notes: none
//
//-----------------------------------------------------------------------------
HRESULT ChangeRDN( LPTSTR lpOldRDN, // Old user/group RDN
LPTSTR lpNewRDN, // New user/group RDN
LPTSTR lpDomainName, // Machine domain name
BOOL bTest // Analyze mode or not
) { HRESULT hr; LPTSTR lpOldFQDN; BOOL bRDNChangeNeeded = FALSE; LPTSTR lpNewRDNWithCN = NULL; DWORD cchNewRDNWithCN; LPTSTR lpOldFQDNWithLDAP = NULL; DWORD cchOldFQDNWithLDAP; LPTSTR lpContainerPathWithLDAP = NULL; DWORD cchContainerPathWithLDAP; LPTSTR lpContainerPath;
//
// First, try to get a FQDN of the old RDN
//
hr = GetFQDN(lpOldRDN, lpDomainName, &lpOldFQDN); if (hr == S_OK) { // Old RDN exists in the system, find out more if we should rename it
hr = GetFQDN(lpNewRDN, lpDomainName, NULL); if (hr == S_FALSE) { // New name doesn't exits, we are ok to rename old RDN
bRDNChangeNeeded = TRUE; } }
if (!bRDNChangeNeeded) { goto EXIT; } //
// Next, if the old RDN exists then we prepare some value to use in next step
//
lpContainerPath = StrStrI(lpOldFQDN, TEXT("=Users")); if (lpContainerPath) { // Make container path points to "CN=Users, CN=...., CN=com"
lpContainerPath -= 2; cchContainerPathWithLDAP = lstrlen(lpContainerPath) + lstrlen(TEXT("LDAP://")) + 1; lpContainerPathWithLDAP = (LPTSTR) MEMALLOC(cchContainerPathWithLDAP * sizeof(TCHAR)); if (lpContainerPathWithLDAP) { hr = StringCchPrintf(lpContainerPathWithLDAP, cchContainerPathWithLDAP, TEXT("LDAP://%s"), lpContainerPath); if (FAILED(hr)) { goto EXIT; } } else { hr = E_OUTOFMEMORY; goto EXIT; } } else { hr = S_FALSE; goto EXIT; }
// Compose the string "CN=new RDN name"
cchNewRDNWithCN = lstrlen(lpNewRDN) + lstrlen(lpOldRDN) + lstrlen(TEXT("CN=")) + 1; lpNewRDNWithCN = (LPTSTR) MEMALLOC(cchNewRDNWithCN * sizeof(TCHAR)); if (lpNewRDNWithCN) { if (bTest) { hr = StringCchPrintf(lpNewRDNWithCN, cchNewRDNWithCN, TEXT("CN=%s"), lpOldRDN); } else { hr = StringCchPrintf(lpNewRDNWithCN, cchNewRDNWithCN, TEXT("CN=%s"), lpNewRDN); }
if (FAILED(hr)) { goto EXIT; } } else { hr = E_OUTOFMEMORY; goto EXIT; }
// Compose the string "LDAP://CN=Old RDN, OU=Users, ...."
cchOldFQDNWithLDAP = lstrlen(lpOldFQDN) + lstrlen(TEXT("LDAP://")) + 1; lpOldFQDNWithLDAP = (LPTSTR) MEMALLOC(cchOldFQDNWithLDAP * sizeof(TCHAR)); if (lpOldFQDNWithLDAP) { hr = StringCchPrintf(lpOldFQDNWithLDAP, cchOldFQDNWithLDAP, TEXT("LDAP://%s"), lpOldFQDN); if (FAILED(hr)) { goto EXIT; } } else { hr = E_OUTOFMEMORY; goto EXIT; }
//
// Now, this is the part to do an RDN renaming
//
hr = RenameRDN(lpContainerPathWithLDAP, lpOldFQDNWithLDAP, lpNewRDNWithCN); if (FAILED(hr)) { DPF(PROerr, TEXT("ChangeDomainGroupName: Unable to change RDN name for %s"), lpOldRDN); }
EXIT: if (lpNewRDNWithCN) { MEMFREE(lpNewRDNWithCN); }
if (lpOldFQDNWithLDAP) { MEMFREE(lpOldFQDNWithLDAP); }
if (lpContainerPathWithLDAP) { MEMFREE(lpContainerPathWithLDAP); }
return hr; }
//-----------------------------------------------------------------------------
//
// Function: GetFQDN
//
// Descrip: Get Fully Qualified Domain Name
//
// Returns: S_OK - Successfully get FQDN
// S_FALSE - FQDN for the account not found
// otherwise - error occured
//
// History: 04/25/2002 Rerkboos Created
//
// Notes: none
//
//-----------------------------------------------------------------------------
HRESULT GetFQDN( LPTSTR lpAccountName, // Account name
LPTSTR lpDomainName, // Machine domain name
LPTSTR *plpFQDN // Address of the pointer to FQDN of the account
) { HRESULT hr = E_FAIL; HANDLE hDS; DWORD dwErr; LPTSTR lpFQDN = NULL; LPTSTR lpOldSamAccount = NULL; DWORD cchOldSamAccount;
dwErr = DsBind(NULL, lpDomainName, &hDS); if (dwErr == NO_ERROR) { cchOldSamAccount = lstrlen(lpDomainName) + lstrlen(lpAccountName) + 2; lpOldSamAccount = (LPTSTR) MEMALLOC(cchOldSamAccount * sizeof(TCHAR));
if (lpOldSamAccount) { // Compose a SAM account name DOMAIN\USERNAME
hr = StringCchPrintf(lpOldSamAccount, cchOldSamAccount, TEXT("%s\\%s"), lpDomainName, lpAccountName); if (SUCCEEDED(hr)) { PDS_NAME_RESULT pdsName;
// Get an FQDN name of a specified SAM account name
dwErr = DsCrackNames(hDS, DS_NAME_NO_FLAGS, DS_NT4_ACCOUNT_NAME, DS_FQDN_1779_NAME, 1, &lpOldSamAccount, &pdsName); if (dwErr == DS_NAME_NO_ERROR) { if (pdsName->rItems->status == DS_NAME_NO_ERROR) { if (plpFQDN) { *plpFQDN = pdsName->rItems->pName; }
hr = S_OK; } else if (pdsName->rItems->status == DS_NAME_ERROR_NOT_FOUND) { hr = S_FALSE; } else { hr = HRESULT_FROM_WIN32(pdsName->rItems->status); } } }
MEMFREE(lpOldSamAccount); }
DsUnBind(&hDS); } if (dwErr != NO_ERROR) { hr = HRESULT_FROM_WIN32(dwErr); }
return hr; }
HRESULT RenameDocuments_and_Settings( HINF hInf, BOOL bTest) { const FOLDER_INFO *pfi; HRESULT hr = S_OK; TCHAR szSection[MAX_PATH]; INFCONTEXT context ; int nOriIndexFldr, nNewIndexFldr; TCHAR szOriFld[MAX_PATH], szNewFld[MAX_PATH];
if (!bTest) { return S_OK; } for (pfi = c_rgFolderInfo; pfi->id != -1; pfi++) { if (pfi->id == CSIDL_PROFILES_DIRECTORY) { break; } } if (pfi->id == -1 ) { hr = E_FAIL; goto Cleanup; } //Get the folder Line for the section just found
if (FAILED(hr = StringCchCopy(szSection,MAX_PATH,SHELL_FOLDER_PREFIX))) { goto Cleanup; } if (FAILED(hr = StringCchCat(szSection,MAX_PATH,pfi->pszIdInString))) { goto Cleanup; }
if (!SetupFindFirstLine(hInf, szSection,SHELL_FOLDER_FOLDER,&context)) { hr = E_FAIL; goto Cleanup; }
nOriIndexFldr = 3; nNewIndexFldr = 4;
if (!SetupGetStringField(&context,nOriIndexFldr,szOriFld,MAX_PATH,NULL) || !SetupGetStringField(&context,nNewIndexFldr,szNewFld,MAX_PATH,NULL)) { hr = E_FAIL; goto Cleanup; } if (!MyStrCmpI(szOriFld,szNewFld)) { hr = S_FALSE; goto Cleanup; } hr = FixFolderPath(pfi->id, NULL,hInf,TEXT("System"),FALSE); Cleanup: return hr; }
HRESULT AddProfileChangeItem( DWORD dwType, LPTSTR lpOldName, LPTSTR lpNewName, LPTSTR lpOldDesc, LPTSTR lpNewDesc, LPTSTR lpOldFullName, LPTSTR lpNewFullName) { LPTSTR lpszOneline = NULL; size_t ccbOneline; TCHAR szIndex[MAX_PATH]; HRESULT hr; if (lpOldName == NULL || lpNewName == NULL) { hr = E_INVALIDARG; goto Cleanup; } if ( (dwType != OP_USER) && (dwType != OP_GRP) && (dwType != OP_PROFILE) && (dwType != OP_DOMAIN_GRP) ) { hr = E_INVALIDARG; goto Cleanup; } if ( (!lpOldDesc && lpNewDesc )||(lpOldDesc && !lpNewDesc) ) { hr = E_INVALIDARG; goto Cleanup; } if ( (!lpOldFullName && lpNewFullName )||(lpOldFullName && !lpNewFullName) ) { hr = E_INVALIDARG; goto Cleanup; }
ccbOneline = lstrlen(lpOldName) + lstrlen(lpNewName)+ MAX_PATH; if (lpOldDesc) { ccbOneline += (lstrlen(lpOldDesc) + lstrlen(lpNewDesc)); } if (lpOldFullName) { ccbOneline += (lstrlen(lpOldFullName)+ lstrlen(lpNewFullName)); } if (!(lpszOneline = malloc(ccbOneline * sizeof(TCHAR)))) { hr = E_OUTOFMEMORY; goto Cleanup; } switch (dwType) { case OP_USER://fall through, no break here
case OP_GRP: case OP_DOMAIN_GRP: if (lpOldDesc && lpOldFullName) { // if comments and fill name are both presented
if (FAILED(StringCchPrintf(lpszOneline,ccbOneline,TEXT("%d,\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\""), dwType,lpOldName,lpNewName,lpOldDesc,lpNewDesc,lpOldFullName,lpNewFullName))) { hr = E_FAIL; goto Cleanup; } } else if (!lpOldDesc && !lpOldFullName) { // if comments and fill name are both not presented
if (FAILED(StringCchPrintf(lpszOneline,ccbOneline,TEXT("%d,\"%s\",\"%s\""),dwType,lpOldName,lpNewName))) { hr = E_FAIL; goto Cleanup; }
} else if (lpOldDesc) { // if only comments are there
if (FAILED(StringCchPrintf(lpszOneline,ccbOneline,TEXT("%d,\"%s\",\"%s\",\"%s\",\"%s\""), dwType,lpOldName,lpNewName,lpOldDesc,lpNewDesc))) { hr = E_FAIL; goto Cleanup; } } else { // if only full name are there
if (FAILED(StringCchPrintf(lpszOneline,ccbOneline,TEXT("%d,\"%s\",\"%s\",\"\",\"\",\"%s\",\"%s\""),dwType, lpOldName,lpNewName,lpOldFullName,lpNewFullName))) { hr = E_FAIL; goto Cleanup; } } break; case OP_PROFILE: if (FAILED(StringCchPrintf(lpszOneline,ccbOneline,TEXT("%d,\"%s\",\"%s\""),dwType, lpOldName,lpNewName))) { hr = E_FAIL; goto Cleanup; } break; } g_dwKeyIndex++; _itot(g_dwKeyIndex,szIndex,16); if (!WritePrivateProfileString(USERGRPSECTION,szIndex,lpszOneline,g_szToDoINFFileName)) { hr = HRESULT_FROM_WIN32(GetLastError()); goto Cleanup; } hr = S_OK; Cleanup: FreePointer(lpszOneline); return hr; }
HRESULT PolicyGetPrivilege( LPTSTR userName, PLSA_HANDLE pPolicyHandle, PLSA_UNICODE_STRING *ppPrivileges, PULONG pCountOfRights)
{ LSA_OBJECT_ATTRIBUTES ObjectAttributes ; NTSTATUS status; PSID psid = NULL; HRESULT hr;
hr = GetSIDFromName(userName,&psid); if (hr != S_OK) { goto cleanup; } ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes)); status = LsaOpenPolicy(NULL,&ObjectAttributes, POLICY_ALL_ACCESS,pPolicyHandle); if (STATUS_SUCCESS != status) { hr = HRESULT_FROM_WIN32(LsaNtStatusToWinError(status)); goto cleanup; } status = LsaEnumerateAccountRights(*pPolicyHandle,psid,ppPrivileges,pCountOfRights); if (STATUS_SUCCESS != status) { hr = HRESULT_FROM_WIN32(LsaNtStatusToWinError(status)); goto cleanup; } cleanup: if (psid) { free(psid); } return hr; }
HRESULT PolicySetPrivilege( LPTSTR userName, LSA_HANDLE PolicyHandle, PLSA_UNICODE_STRING pPrivileges, ULONG CountOfRights) { NTSTATUS status; PSID psid = NULL; HRESULT hr;
hr = GetSIDFromName(userName,&psid); if (hr != S_OK) { goto cleanup; } status = LsaAddAccountRights(PolicyHandle,psid,pPrivileges,CountOfRights); if (STATUS_SUCCESS != status) { hr = HRESULT_FROM_WIN32(LsaNtStatusToWinError(status)); goto cleanup; } cleanup: if (psid) { free(psid); } return hr;
}
//-----------------------------------------------------------------------------
//
// Function: IsPathLocal
//
// Descrip: Check if the path is a local system drive, not UNC.
//
// Returns: TRUE - Path is on local system drive
// FALSE - otherwise
//
// History: 04/25/2002 Rerkboos Created
//
// Notes: none
//
//-----------------------------------------------------------------------------
BOOL IsPathLocal( LPCTSTR lpPath ) { BOOL bIsPathLocal = FALSE; TCHAR szSysWinDir[MAX_PATH]; TCHAR szExpPath[MAX_PATH]; UINT uRet;
if (lpPath == NULL || *lpPath == TEXT('\0')) { return FALSE; }
ExpandEnvironmentStrings(lpPath, szExpPath, ARRAYSIZE(szExpPath)); uRet = GetSystemWindowsDirectory(szSysWinDir, ARRAYSIZE(szSysWinDir)); if (uRet > 0) { // Compare the first 2 characters for a Drive letter
if (StrCmpNI(szSysWinDir, szExpPath, 2) == LSTR_EQUAL) { bIsPathLocal = TRUE; } }
return bIsPathLocal; }
HRESULT EnumUserProfile(PROFILEENUMPROC pfnProfileProc) { HRESULT hr = S_FALSE; BOOL bRet; LPUSER_INFO_0 lpusri0 = NULL; LPUSER_INFO_0 lpTmp; NET_API_STATUS nStatus; DWORD dwEntriesRead = 0; DWORD dwTotalEntries = 0; DWORD dwResumeHandle = 0; LPVOID lpSid = NULL; DWORD cbSid; LPTSTR lpStringSid = NULL; TCHAR szDomain[MAX_PATH]; DWORD cbDomain; SID_NAME_USE SidUse; DWORD i; DWORD dwLevel = 0;
cbSid = SECURITY_MAX_SID_SIZE; lpSid = MEMALLOC(cbSid); if (lpSid == NULL) { return E_OUTOFMEMORY; }
do { nStatus = NetUserEnum(NULL, // This server
0, FILTER_NORMAL_ACCOUNT, (LPBYTE *) &lpusri0, MAX_PREFERRED_LENGTH, &dwEntriesRead, &dwTotalEntries, &dwResumeHandle); if (nStatus == NERR_Success || nStatus == ERROR_MORE_DATA) { lpTmp = lpusri0; if (lpTmp != NULL) { // Loop through all entries
for (i = 0 ; i < dwEntriesRead ; i++) { cbDomain = ARRAYSIZE(szDomain) * sizeof(TCHAR); bRet = LookupAccountName(NULL, lpTmp->usri0_name, (PSID) lpSid, &cbSid, szDomain, &cbDomain, &SidUse); if (bRet) { bRet = ConvertSidToStringSid((PSID) lpSid, &lpStringSid); if (bRet) { hr = pfnProfileProc(lpTmp->usri0_name, lpStringSid);
LocalFree(lpStringSid);
if (FAILED(hr)) { goto EXIT; } } }
if (!bRet) { hr = HRESULT_FROM_WIN32(GetLastError()); goto EXIT; }
lpTmp++; }
NetApiBufferFree(lpusri0); lpusri0 = NULL; } } else { hr = HRESULT_FROM_WIN32(nStatus); goto EXIT; } } while (nStatus == ERROR_MORE_DATA);
EXIT: if (lpusri0 != NULL) { NetApiBufferFree(lpusri0); }
if (lpSid != NULL) { MEMFREE(lpSid); }
return hr; }
//-----------------------------------------------------------------------------
//
// Function: AnalyzeMiscProfilePathPerUser
//
// Synopsis: Analyze the user's profile path. If the profile paths need to
// be changed, the function will add entries to CLMTDO.INF. These
// entries will be set by ResetMiscProfilePathPerUser() function
// later in the DoCritical state.
//
// Returns: S_OK, we don't care the error
//
// History: 06/03/2002 Rerkboos Created
//
// Notes: This is a call-back function for LoopUser() function.
//
//-----------------------------------------------------------------------------
HRESULT AnalyzeMiscProfilePathPerUser( LPCTSTR lpUserName, // User name
LPCTSTR lpUserSid // User's SID
) { HRESULT hr; BOOL bRet; NET_API_STATUS nStatus; LPUSER_INFO_3 lpusri3; TCHAR szNewUserName[MAX_PATH]; TCHAR szNewProfilePath[MAX_PATH * 2]; TCHAR szNewEngProfilePath[MAX_PATH * 2]; LPTSTR lpNewEngProfilePath = NULL; DWORD cchNewEngProfilePath;
DPF(APPmsg, TEXT("Enter AnalyzeMiscProfilePathPerUser:"));
// If lpUserName is built-in account, we will get the unlocalized name
// from INF file
hr = CheckNewBuiltInUserName(lpUserName, szNewUserName, ARRAYSIZE(szNewUserName)); if (SUCCEEDED(hr)) { if (hr == S_FALSE) { // Username is not built-in account,
// we will not change the account name.
hr = StringCchCopy(szNewUserName, ARRAYSIZE(szNewUserName), lpUserName); if (FAILED(hr)) { goto EXIT; } }
// Compute a new unique profile directory for the new unlocalized name
// we don't want the new profile directory to duplicate.
bRet = ComputeLocalProfileName(lpUserName, szNewUserName, szNewProfilePath, ARRAYSIZE(szNewProfilePath), REG_SZ); if (!bRet) { // This user does not have profile path set in the registry
// Assume it is %documents and settings%\user name
DWORD cchNewProfilePath = ARRAYSIZE(szNewProfilePath); bRet = GetProfilesDirectory(szNewProfilePath, &cchNewProfilePath); if (bRet) { bRet = ConcatenatePaths(szNewProfilePath, lpUserName, ARRAYSIZE(szNewProfilePath)); if (bRet) { if (IsDirExisting(szNewProfilePath)) { // %documents and settings%\user name dir alreay exists,
// cannot use this dir, we just ignore this user
hr = S_FALSE; goto EXIT; } } }
if (!bRet) { hr = E_FAIL; goto EXIT; } }
// szNewProfilePath should be "%Loc_documents_and_settings%\NewUser"
// We have to fix it to "%Eng_documents_and_settings%\NewUser"
lpNewEngProfilePath = ReplaceLocStringInPath(szNewProfilePath, TRUE); if (lpNewEngProfilePath == NULL) { // If Loc string and Eng string are the same,
// duplicate the old string to new string
hr = DuplicateString(&lpNewEngProfilePath, &cchNewEngProfilePath, szNewProfilePath); if (FAILED(hr)) { goto EXIT; } } } else { goto EXIT; }
// Get current information of current user name,
// and we will add entries to CLMTDO.INF if the change is needed.
nStatus = NetUserGetInfo(NULL, lpUserName, 3, (LPBYTE *) &lpusri3); if (nStatus == NERR_Success) { // Check the User's Profile path
hr = AddProfilePathItem(lpUserName, lpUserSid, lpusri3->usri3_profile, lpNewEngProfilePath, TYPE_USER_PROFILE_PATH);
hr = AddProfilePathItem(lpUserName, lpUserSid, lpusri3->usri3_script_path, lpNewEngProfilePath, TYPE_USER_SCRIPT_PATH); hr = AddProfilePathItem(lpUserName, lpUserSid, lpusri3->usri3_home_dir, lpNewEngProfilePath, TYPE_USER_HOME_DIR);
NetApiBufferFree(lpusri3); }
hr = AddTSProfilePathItem(lpUserName, lpUserSid, lpNewEngProfilePath, WTSUserConfigInitialProgram);
hr = AddTSProfilePathItem(lpUserName, lpUserSid, lpNewEngProfilePath, WTSUserConfigWorkingDirectory);
hr = AddTSProfilePathItem(lpUserName, lpUserSid, lpNewEngProfilePath, WTSUserConfigTerminalServerProfilePath);
hr = AddTSProfilePathItem(lpUserName, lpUserSid, lpNewEngProfilePath, WTSUserConfigTerminalServerHomeDir);
DPF(APPmsg, TEXT("Exit AnalyzeMiscProfilePathPerUser:"));
EXIT: if (lpNewEngProfilePath != NULL) { MEMFREE(lpNewEngProfilePath); }
return S_OK; }
//-----------------------------------------------------------------------------
//
// Function: ResetMiscProfilePathPerUser
//
// Synopsis: Reset the profile paths for the user. The function will read
// the entries for each user from CLMTDO.INF. The entries were
// added by AnalyzeMiscProfilePathPerUser() function.
//
// Returns: S_OK if function succeeded
//
// History: 06/03/2002 Rerkboos Created
//
// Notes: This is a call-back function for LoopUser() function.
//
//-----------------------------------------------------------------------------
HRESULT ResetMiscProfilePathPerUser( LPCTSTR lpUserName, // User Name
LPCTSTR lpUserSid // User's SID
) { HRESULT hr = S_OK; BOOL bRet; TCHAR szSectionName[MAX_PATH]; TCHAR szProfilePath[MAX_PATH]; LONG lLineCount; LONG lLineIndex; INT iType; INFCONTEXT context;
DPF(APPmsg, TEXT("Enter ResetProfilePathPerUser:"));
hr = StringCchPrintf(szSectionName, ARRAYSIZE(szSectionName), TEXT("PROFILE.UPDATE.%s"), lpUserSid); if (FAILED(hr)) { goto EXIT; }
lLineCount = SetupGetLineCount(g_hInfDoItem, szSectionName); for (lLineIndex = 0 ; lLineIndex < lLineCount ; lLineIndex++) { bRet = SetupGetLineByIndex(g_hInfDoItem, szSectionName, lLineIndex, &context); if (bRet) { bRet = SetupGetIntField(&context, 0, &iType) && SetupGetStringField(&context, 1, szProfilePath, ARRAYSIZE(szProfilePath), NULL); if (bRet) { switch (iType) { case TYPE_USER_PROFILE_PATH: hr = SetUserNetworkProfilePath(lpUserName, szProfilePath); break;
case TYPE_USER_SCRIPT_PATH: hr = SetUserLogOnScriptPath(lpUserName, szProfilePath); break;
case TYPE_USER_HOME_DIR: hr = SetUserHomeDir(lpUserName, szProfilePath); break;
case TYPE_TS_INIT_PROGRAM: hr = SetTSUserPath(lpUserName, szProfilePath, WTSUserConfigInitialProgram); break;
case TYPE_TS_WORKING_DIR: hr = SetTSUserPath(lpUserName, szProfilePath, WTSUserConfigWorkingDirectory); break;
case TYPE_TS_PROFILE_PATH: hr = SetTSUserPath(lpUserName, szProfilePath, WTSUserConfigTerminalServerProfilePath); break;
case TYPE_TS_HOME_DIR: hr = SetTSUserPath(lpUserName, szProfilePath, WTSUserConfigTerminalServerHomeDir); break; } } }
if (!bRet) { hr = HRESULT_FROM_WIN32(GetLastError()); goto EXIT; } }
DPF(APPmsg, TEXT("Exit ResetProfilePathPerUser:"));
EXIT: return hr; }
//-----------------------------------------------------------------------------
//
// Function: CheckNewBuiltInUserName
//
// Synopsis: Check the user name with the built-in accounts listed in
// CLMT.INF. If the user name matches, the function will return
// the associaged English user name.
//
// Returns: S_OK if the user name is built-in account
// S_FALSE if the user name is not built-in account
// Otherwise, error occurred
//
// History: 06/03/2002 Rerkboos Created
//
// Notes: None.
//
//-----------------------------------------------------------------------------
HRESULT CheckNewBuiltInUserName( LPCTSTR lpUserName, // Localized User name
LPTSTR lpNewUserName, // Buffer to store associated English User name
DWORD cchNewUserName // Size of the buffer (in TCHAR)
) { HRESULT hr = S_FALSE; BOOL bRet; LONG lLineCount; LONG lLineIndex; INT iType; INFCONTEXT context; TCHAR szOldUserName[MAX_PATH];
lLineCount = SetupGetLineCount(g_hInf, USERGRPSECTION); for (lLineIndex = 0 ; lLineIndex < lLineCount ; lLineIndex++) { SetupGetLineByIndex(g_hInf, USERGRPSECTION, lLineIndex, &context); bRet = SetupGetIntField(&context, 1, &iType); if (iType == OP_USER) { bRet = SetupGetStringField(&context, 2, szOldUserName, ARRAYSIZE(szOldUserName), NULL); if (bRet) { if (MyStrCmpI(szOldUserName, lpUserName) == LSTR_EQUAL) { bRet = SetupGetStringField(&context, 3, lpNewUserName, cchNewUserName, NULL); if (bRet) { hr = S_OK; goto EXIT; } } }
if (!bRet) { hr = HRESULT_FROM_WIN32(GetLastError()); goto EXIT; } } }
EXIT: return hr; }
//-----------------------------------------------------------------------------
//
// Function: AddProfilePathItem
//
// Synopsis: Add the user's path that needs to be changed to CLMTDO.INF
//
// Returns: S_OK if the path needs to be changed, and added to CLMTDO.INF
// S_FALSE if it's not neccessary to change the path
// otherwise, error occurred
//
// History: 06/03/2002 Rerkboos Created
//
// Notes: None.
//
//-----------------------------------------------------------------------------
HRESULT AddProfilePathItem( LPCTSTR lpUserName, // User name
LPCTSTR lpUserSid, // User's SID
LPCTSTR lpOldLocProfilePath, // Current path
LPCTSTR lpNewEngProfilePath, // New English profile path
DWORD dwType) { HRESULT hr = S_FALSE; BOOL bRet; LPTSTR lpOldEngProfilePath; TCHAR szFinalPath[MAX_PATH]; TCHAR szSectionName[MAX_PATH]; TCHAR szType[4]; TCHAR szExpandedOldLocPath[MAX_PATH]; TCHAR szExpandedNewEngPath[MAX_PATH];
if (lpUserName == NULL || *lpUserName == TEXT('\0') || lpOldLocProfilePath == NULL || *lpOldLocProfilePath == TEXT('\0') || lpNewEngProfilePath == NULL || *lpNewEngProfilePath == TEXT('\0')) { return S_FALSE; }
ExpandEnvironmentStrings(lpOldLocProfilePath, szExpandedOldLocPath, ARRAYSIZE(szExpandedOldLocPath));
ExpandEnvironmentStrings(lpNewEngProfilePath, szExpandedNewEngPath, ARRAYSIZE(szExpandedNewEngPath));
if (IsPathLocal(szExpandedOldLocPath)) { // szExpandedOldLocPath should be "%Loc_documents_and_settings%\OldUser"
// We have to fix it to "%Eng_documents_and_settings%\OldUser"
lpOldEngProfilePath = ReplaceLocStringInPath(szExpandedOldLocPath, TRUE); if (lpOldEngProfilePath != NULL) { // Loc path is NOT the same as Eng path
hr = PreFixUserProfilePath(lpOldEngProfilePath, szExpandedNewEngPath, szFinalPath, ARRAYSIZE(szFinalPath));
MEMFREE(lpOldEngProfilePath);
if (SUCCEEDED(hr)) { hr = StringCchPrintf(szSectionName, ARRAYSIZE(szSectionName), TEXT("PROFILE.UPDATE.%s"), lpUserSid); if (SUCCEEDED(hr)) { _ultot(dwType, szType, 10);
// Add entry to CLMTDO.INF
WritePrivateProfileString(szSectionName, szType, szFinalPath, g_szToDoINFFileName); } } } }
return hr; }
//-----------------------------------------------------------------------------
//
// Function: AddTSProfilePathItem
//
// Synopsis: Add the Terminal Services Realted user's path that needs to be
// changed to CLMTDO.INF
//
// Returns: S_OK if the path needs to be changed, and added to CLMTDO.INF
// S_FALSE if it's not neccessary to change the path
// otherwise, error occurred
//
// History: 06/03/2002 Rerkboos Created
//
// Notes: None.
//
//-----------------------------------------------------------------------------
HRESULT AddTSProfilePathItem( LPCTSTR lpUserName, // User name
LPCTSTR lpUserSid, // User's SID
LPCTSTR lpNewEngProfilePath, // New English profile path
WTS_CONFIG_CLASS WTSConfigClass // TS Path config class
) { HRESULT hr = S_FALSE; BOOL bRet; LPTSTR lpTSDir; DWORD cbTSDir; DWORD dwType;
bRet = WTSQueryUserConfig(WTS_CURRENT_SERVER_NAME, (LPTSTR) lpUserName, WTSConfigClass, &lpTSDir, &cbTSDir); if (bRet) { switch (WTSConfigClass) { case WTSUserConfigInitialProgram: dwType = TYPE_TS_INIT_PROGRAM; break;
case WTSUserConfigWorkingDirectory: dwType = TYPE_TS_WORKING_DIR; break;
case WTSUserConfigTerminalServerProfilePath: dwType = TYPE_TS_PROFILE_PATH; break;
case WTSUserConfigTerminalServerHomeDir: dwType = TYPE_TS_HOME_DIR; break; }
hr = AddProfilePathItem(lpUserName, lpUserSid, lpTSDir, lpNewEngProfilePath, dwType);
WTSFreeMemory(lpTSDir); }
return hr; }
|