You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2927 lines
88 KiB
2927 lines
88 KiB
/*++
|
|
|
|
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;
|
|
}
|
|
|