Windows-Server-2003/base/ntsetup/syssetup/security.c

1210 lines
30 KiB
C

/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
security.c
Abstract:
Routines to deal with security, user accounts, etc.
Externally exposed routines:
SignalLsa
CreateSamEvent
WaitForSam
SetAccountsDomainSid
CreateLocalAdminAccount
CreateLocalUserAccount
SetLocalUserPassword
Author:
Ted Miller (tedm) 5-Apr-1995
adapted from legacy\dll\security.c
Revision History:
--*/
#include "setupp.h"
#include <Lmaccess.h>
#pragma hdrstop
PCWSTR SamEventName = L"\\SAM_SERVICE_STARTED";
PCWSTR SsiAccountNamePostfix = L"$";
PCWSTR SsiSecretName = L"$MACHINE.ACC";
#define DOMAIN_NAME_MAX 33
#define PASSWORD_MAX 14
//
// Constants used for logging that are specific to this source file.
//
PCWSTR szLsaOpenPolicy = L"LsaOpenPolicy";
PCWSTR szLsaSetInformationPolicy = L"LsaSetInformationPolicy";
PCWSTR szLsaQueryInformationPolicy = L"LsaQueryInformationPolicy";
PCWSTR szNtSetEvent = L"NtSetEvent";
PCWSTR szNtCreateEvent = L"NtCreateEvent";
PCWSTR szSamConnect = L"SamConnect";
PCWSTR szGetAccountsDomainName = L"GetAccountsDomainName";
PCWSTR szSamLookupDomainInSamServer = L"SamLookupDomainInSamServer";
PCWSTR szSamOpenDomain = L"SamOpenDomain";
PCWSTR szSamEnumerateUsersInDomain = L"SamEnumerateUsersInDomain";
PCWSTR szSamOpenUser = L"SamOpenUser";
PCWSTR szSamChangePasswordUser = L"SamChangePasswordUser";
PCWSTR szSamCreateUserInDomain = L"SamCreateUserInDomain";
PCWSTR szSamQueryInformationUser = L"SamQueryInformationUser";
PCWSTR szSamSetInformationUser = L"SamSetInformationUser";
PCWSTR szMyAddLsaSecretObject = L"MyAddLsaSecretObject";
VOID
SetupLsaInitObjectAttributes(
IN OUT POBJECT_ATTRIBUTES ObjectAttributes,
IN OUT PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService
);
BOOL
GetAccountsDomainName(
IN LSA_HANDLE hPolicy, OPTIONAL
OUT PWSTR Name,
IN DWORD NameBufferSize
);
LSA_HANDLE
OpenLsaPolicy(
VOID
);
PSID
CreateSidFromSidAndRid(
IN PSID DomainSid,
IN DWORD Rid
);
NTSTATUS
MyAddLsaSecretObject(
IN PCWSTR Password
);
BOOL
SetAccountsDomainSid(
IN DWORD Seed,
IN PCWSTR DomainName
)
/*++
Routine Description:
Routine to set the sid of the AccountDomain.
Arguments:
Seed - The seed is used to generate a unique Sid. The seed should
be generated by looking at the systemtime before and after
a dialog and subtracting the milliseconds field.
DomainName - supplies name to give to local domain
Return value:
Boolean value indicating outcome.
--*/
{
PSID Sid;
PSID SidPrimary ;
OBJECT_ATTRIBUTES ObjectAttributes;
SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
LSA_HANDLE PolicyHandle = NULL;
PPOLICY_ACCOUNT_DOMAIN_INFO PolicyCurrentAccountDomainInfo = NULL;
NTSTATUS Status;
BOOL bResult;
//
//
// Open the LSA Policy object to set the account domain sid. The access
// mask needed for this is POLICY_TRUST_ADMIN.
//
SetupLsaInitObjectAttributes(&ObjectAttributes,&SecurityQualityOfService);
Status = LsaOpenPolicy(NULL,&ObjectAttributes,MAXIMUM_ALLOWED,&PolicyHandle);
if(!NT_SUCCESS(Status)) {
SetuplogError(
LogSevError,
SETUPLOG_USE_MESSAGEID,
MSG_LOG_SETACCOUNTDOMAINSID, NULL,
SETUPLOG_USE_MESSAGEID,
MSG_LOG_X_RETURNED_NTSTATUS,
szLsaOpenPolicy,
Status,
NULL,NULL);
return(FALSE);
}
Status = LsaQueryInformationPolicy(
PolicyHandle,
PolicyAccountDomainInformation,
&PolicyCurrentAccountDomainInfo
);
if(NT_SUCCESS(Status)) {
RtlInitUnicodeString(&PolicyCurrentAccountDomainInfo->DomainName,DomainName);
Status = LsaSetInformationPolicy(
PolicyHandle,
PolicyAccountDomainInformation,
(PVOID) PolicyCurrentAccountDomainInfo
);
LsaFreeMemory( PolicyCurrentAccountDomainInfo );
}
if(NT_SUCCESS(Status)) {
bResult = TRUE;
} else {
bResult = FALSE;
SetuplogError(
LogSevError,
SETUPLOG_USE_MESSAGEID,
MSG_LOG_SETACCOUNTDOMAINSID, NULL,
SETUPLOG_USE_MESSAGEID,
MSG_LOG_X_RETURNED_NTSTATUS,
szLsaSetInformationPolicy,
Status,
NULL,NULL);
}
LsaClose(PolicyHandle);
return(bResult);
}
VOID
SetupLsaInitObjectAttributes(
IN OUT POBJECT_ATTRIBUTES ObjectAttributes,
IN OUT PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService
)
/*++
Routine Description:
This function initializes the given Object Attributes structure, including
Security Quality Of Service. Memory must be allcated for both
ObjectAttributes and Security QOS by the caller. Borrowed from
lsa
Arguments:
ObjectAttributes - Pointer to Object Attributes to be initialized.
SecurityQualityOfService - Pointer to Security QOS to be initialized.
Return Value:
None.
--*/
{
SecurityQualityOfService->Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
SecurityQualityOfService->ImpersonationLevel = SecurityImpersonation;
SecurityQualityOfService->ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
SecurityQualityOfService->EffectiveOnly = FALSE;
InitializeObjectAttributes(ObjectAttributes,NULL,0,NULL,NULL);
//
// The InitializeObjectAttributes macro presently stores NULL for
// the SecurityQualityOfService field, so we must manually copy that
// structure for now.
//
ObjectAttributes->SecurityQualityOfService = SecurityQualityOfService;
}
BOOL
CreateLocalUserAccount(
IN PCWSTR UserName,
IN PCWSTR Password,
IN PSID* PointerToUserSid OPTIONAL
)
/*++
Routine Description:
Routine to add a local user account to the AccountDomain. This account
is created with the password indicated.
Arguments:
UserName - supplies name for user account
Password - supplies initial password for user account.
PointerToUserSid - If this argument is present, then on return it will contain the
pointer to the user sid. It is the responsibility of the caller
to free the Sid, using MyFree.
Return value:
Boolean value indicating outcome.
--*/
{
return (NT_SUCCESS(CreateLocalAdminAccount(UserName,
Password,
PointerToUserSid
)
)
);
}
NTSTATUS
CreateLocalAdminAccountEx(
IN PCWSTR UserName,
IN PCWSTR Password,
IN PCWSTR Description,
IN PSID* PointerToUserSid OPTIONAL
)
/*++
Routine Description:
Routine to add a local user account to the AccountDomain. This account
has ADMINISTRATOR priveledges and is created with the password indicated.
Arguments:
UserName - supplies name for user account
Password - supplies initial password for user account.
Description - Description that appears in user manager.
PointerToUserSid - If this argument is present, then on return it will contain the
pointer to the user sid. It is the responsibility of the caller
to free the Sid, using MyFree.
Return value:
Boolean value indicating outcome.
--*/
{
OBJECT_ATTRIBUTES ObjectAttributes;
SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
UNICODE_STRING UnicodeString;
SAM_HANDLE ServerHandle;
SAM_HANDLE DomainHandle;
SAM_HANDLE UserHandle;
SAM_HANDLE AliasHandle;
SAM_HANDLE BuiltinDomainHandle;
WCHAR AccountsDomainName[DOMAIN_NAME_MAX];
NTSTATUS Status;
PSID BuiltinDomainId;
PSID UserSid;
ULONG User_RID;
PUSER_CONTROL_INFORMATION UserControlInfo;
USER_SET_PASSWORD_INFORMATION UserPasswordInfo;
LSA_HANDLE PolicyHandle = NULL;
PPOLICY_ACCOUNT_DOMAIN_INFO PolicyCurrentAccountDomainInfo = NULL;
USER_ADMIN_COMMENT_INFORMATION AdminCommentInfo;
//
// Use SamConnect to connect to the local domain ("") and get a handle
// to the local sam server.
//
SetupLsaInitObjectAttributes(&ObjectAttributes,&SecurityQualityOfService);
RtlInitUnicodeString(&UnicodeString,L"");
Status = SamConnect(
&UnicodeString,
&ServerHandle,
SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
&ObjectAttributes
);
if(!NT_SUCCESS(Status)) {
goto err0;
}
//
// Use the LSA to retrieve the name of the Accounts domain.
//
if(!GetAccountsDomainName(NULL,AccountsDomainName,DOMAIN_NAME_MAX)) {
goto err1;
}
//
// Open the AccountDomain. First find the Sid for this
// in the Sam and then open the domain using this sid
//
//
// Open the LSA Policy object to set the account domain sid.
//
SetupLsaInitObjectAttributes(&ObjectAttributes,&SecurityQualityOfService);
Status = LsaOpenPolicy(NULL,&ObjectAttributes,MAXIMUM_ALLOWED,&PolicyHandle);
if(NT_SUCCESS(Status)) {
Status = LsaQueryInformationPolicy(
PolicyHandle,
PolicyAccountDomainInformation,
&PolicyCurrentAccountDomainInfo
);
if(NT_SUCCESS(Status)) {
Status = SamOpenDomain(
ServerHandle,
DOMAIN_READ | DOMAIN_LIST_ACCOUNTS | DOMAIN_LOOKUP |
DOMAIN_READ_PASSWORD_PARAMETERS | DOMAIN_CREATE_USER,
PolicyCurrentAccountDomainInfo->DomainSid,
&DomainHandle
);
}
LsaClose( PolicyHandle );
}
if (!NT_SUCCESS(Status)) {
goto err2;
}
//
// Use SamCreateUserInDomain to create a new user with the username
// specified. This user account is created disabled with the
// password not required.
//
RtlInitUnicodeString(&UnicodeString,UserName);
Status = SamCreateUserInDomain(
DomainHandle,
&UnicodeString,
//USER_READ_ACCOUNT | USER_WRITE_ACCOUNT | USER_FORCE_PASSWORD_CHANGE,
USER_ALL_ACCESS,
&UserHandle,
&User_RID
);
if(!NT_SUCCESS(Status)) {
goto err3;
}
//
// Query all the default control information about the user added
//
Status = SamQueryInformationUser(UserHandle,UserControlInformation,&UserControlInfo);
if(!NT_SUCCESS(Status)) {
goto err4;
}
//
// If the password is a Null password, make sure the
// password_not required bit is set before the null
// password is set.
//
if(!Password[0]) {
UserControlInfo->UserAccountControl |= USER_PASSWORD_NOT_REQUIRED;
Status = SamSetInformationUser(UserHandle,UserControlInformation,UserControlInfo);
if(!NT_SUCCESS(Status)) {
goto err5;
}
}
//
// Set the password ( NULL or non NULL )
//
RtlInitUnicodeString(&UserPasswordInfo.Password,Password);
UserPasswordInfo.PasswordExpired = FALSE;
Status = SamSetInformationUser(UserHandle,UserSetPasswordInformation,&UserPasswordInfo);
if(!NT_SUCCESS(Status)) {
goto err5;
}
//
// Set the information bits - User Password not required is cleared
// The normal account bit is enabled and the account disabled bit
// is also reset
//
UserControlInfo->UserAccountControl &= ~USER_PASSWORD_NOT_REQUIRED;
UserControlInfo->UserAccountControl &= ~USER_ACCOUNT_DISABLED;
UserControlInfo->UserAccountControl |= USER_NORMAL_ACCOUNT;
Status = SamSetInformationUser(UserHandle,UserControlInformation,UserControlInfo);
if(!NT_SUCCESS(Status)) {
goto err5;
}
// Set the description is one is given
//
if ( Description[0])
{
// Convert description to unicode string
//
RtlInitUnicodeString(&AdminCommentInfo.AdminComment,Description);
// We do not care if this fails and therefore will not set the status
//
SamSetInformationUser(UserHandle,UserAdminCommentInformation,&AdminCommentInfo);
}
//
// If this is a non-standlone server we're done.
//
if(ISDC(ProductType)) {
Status = STATUS_SUCCESS;
goto err5;
}
//
// Finally add this to the administrators alias in the BuiltIn Domain
//
RtlInitUnicodeString(&UnicodeString,L"Builtin");
Status = SamLookupDomainInSamServer(ServerHandle,&UnicodeString,&BuiltinDomainId);
if(!NT_SUCCESS(Status)) {
goto err5;
}
Status = SamOpenDomain(
ServerHandle,
DOMAIN_READ | DOMAIN_ADMINISTER_SERVER | DOMAIN_EXECUTE,
BuiltinDomainId,
&BuiltinDomainHandle
);
if(!NT_SUCCESS(Status)) {
goto err6;
}
UserSid = CreateSidFromSidAndRid(PolicyCurrentAccountDomainInfo->DomainSid,User_RID);
if(!UserSid) {
goto err7;
}
Status = SamOpenAlias(BuiltinDomainHandle,ALIAS_ADD_MEMBER,DOMAIN_ALIAS_RID_ADMINS,&AliasHandle);
if(!NT_SUCCESS(Status)) {
goto err8;
}
Status = SamAddMemberToAlias(AliasHandle,UserSid);
if(!NT_SUCCESS(Status)) {
goto err9;
}
MYASSERT(NT_SUCCESS(Status));
err9:
SamCloseHandle(AliasHandle);
err8:
if(NT_SUCCESS(Status) && (PointerToUserSid != NULL )) {
*PointerToUserSid = UserSid;
} else {
MyFree(UserSid);
}
err7:
SamCloseHandle(BuiltinDomainHandle);
err6:
SamFreeMemory(BuiltinDomainId);
err5:
SamFreeMemory(UserControlInfo);
err4:
SamCloseHandle(UserHandle);
err3:
SamCloseHandle(DomainHandle);
err2:
LsaFreeMemory( PolicyCurrentAccountDomainInfo );
err1:
SamCloseHandle(ServerHandle);
err0:
return(Status);
}
NTSTATUS
CreateLocalAdminAccount(
IN PCWSTR UserName,
IN PCWSTR Password,
IN PSID* PointerToUserSid OPTIONAL
)
/*++
Routine Description:
Please see CreateLocalAdminAccountEx description.
--*/
{
return ( CreateLocalAdminAccountEx(UserName, Password, L"", PointerToUserSid) );
}
BOOL
GetAccountsDomainName(
IN LSA_HANDLE PolicyHandle, OPTIONAL
OUT PWSTR Name,
IN DWORD NameBufferSize
)
{
POLICY_ACCOUNT_DOMAIN_INFO *pPadi;
NTSTATUS Status ;
BOOL PolicyOpened;
PolicyOpened = FALSE;
if(PolicyHandle == NULL) {
if((PolicyHandle = OpenLsaPolicy()) == NULL) {
return(FALSE);
}
PolicyOpened = TRUE;
}
Status = LsaQueryInformationPolicy(PolicyHandle,PolicyAccountDomainInformation,&pPadi);
if(NT_SUCCESS(Status)) {
if(NameBufferSize <= (pPadi->DomainName.Length/sizeof(WCHAR))) {
Status = STATUS_BUFFER_TOO_SMALL;
} else {
wcsncpy(Name,pPadi->DomainName.Buffer,pPadi->DomainName.Length/sizeof(WCHAR));
Name[pPadi->DomainName.Length/sizeof(WCHAR)] = 0;
}
LsaFreeMemory(pPadi);
}
if(PolicyOpened) {
LsaClose(PolicyHandle);
}
return(NT_SUCCESS(Status));
}
LSA_HANDLE
OpenLsaPolicy(
VOID
)
{
OBJECT_ATTRIBUTES ObjectAttributes;
SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
LSA_HANDLE PolicyHandle;
NTSTATUS Status;
PolicyHandle = NULL;
SetupLsaInitObjectAttributes(&ObjectAttributes,&SecurityQualityOfService);
Status = LsaOpenPolicy(NULL,&ObjectAttributes,GENERIC_EXECUTE,&PolicyHandle);
return(NT_SUCCESS(Status) ? PolicyHandle : NULL);
}
PSID
CreateSidFromSidAndRid(
IN PSID DomainSid,
IN DWORD Rid
)
/*++
Routine Description:
This function creates a domain account sid given a domain sid and
the relative id of the account within the domain.
Arguments:
DomainSid - supplies sid for domain of account
Rid - supplies relative id of account
Return Value:
Pointer to Sid, or NULL on failure.
The returned Sid must be freed with MyFree.
--*/
{
NTSTATUS Status;
PSID AccountSid;
UCHAR AccountSubAuthorityCount;
ULONG AccountSidLength;
PULONG RidLocation;
AccountSubAuthorityCount = *RtlSubAuthorityCountSid(DomainSid) + (UCHAR)1;
AccountSidLength = RtlLengthRequiredSid(AccountSubAuthorityCount);
if(AccountSid = (PSID)MyMalloc(AccountSidLength)) {
//
// Copy the domain sid into the first part of the account sid
//
Status = RtlCopySid(AccountSidLength, AccountSid, DomainSid);
//
// Increment the account sid sub-authority count
//
*RtlSubAuthorityCountSid(AccountSid) = AccountSubAuthorityCount;
//
// Add the rid as the final sub-authority
//
RidLocation = RtlSubAuthoritySid(AccountSid, AccountSubAuthorityCount - 1);
*RidLocation = Rid;
}
return(AccountSid);
}
BOOL
SetLocalUserPassword(
IN PCWSTR AccountName,
IN PCWSTR OldPassword,
IN PCWSTR NewPassword
)
/*++
Routine Description:
Change the password for the local user account.
Arguments:
Return value:
Boolean value indicating outcome.
--*/
{
NTSTATUS Status;
BOOL b;
UNICODE_STRING UnicodeString;
UNICODE_STRING OtherUnicodeString;
SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
OBJECT_ATTRIBUTES ObjectAttributes;
WCHAR AccountsDomainName[DOMAIN_NAME_MAX];
SAM_HANDLE ServerHandle;
SAM_HANDLE DomainHandle;
SAM_HANDLE UserHandle;
BOOL UserFound;
SAM_ENUMERATE_HANDLE EnumerationContext;
SAM_RID_ENUMERATION *SamRidEnumeration;
UINT i;
UINT CountOfEntries;
ULONG UserRid;
LSA_HANDLE PolicyHandle = NULL;
PPOLICY_ACCOUNT_DOMAIN_INFO PolicyCurrentAccountDomainInfo = NULL;
b = FALSE;
//
// Use SamConnect to connect to the local domain ("") and get a handle
// to the local sam server
//
SetupLsaInitObjectAttributes(&ObjectAttributes,&SecurityQualityOfService);
RtlInitUnicodeString(&UnicodeString,L"");
Status = SamConnect(
&UnicodeString,
&ServerHandle,
SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
&ObjectAttributes
);
if(!NT_SUCCESS(Status)) {
SetuplogError(
LogSevWarning,
SETUPLOG_USE_MESSAGEID,
MSG_LOG_CHANGING_PW_FAIL,
AccountName, NULL,
SETUPLOG_USE_MESSAGEID,
MSG_LOG_X_RETURNED_NTSTATUS,
szSamConnect,
Status,
NULL,NULL);
goto err0;
}
//
// Use the LSA to retrieve the name of the Accounts domain.
//
if(!GetAccountsDomainName(NULL,AccountsDomainName,DOMAIN_NAME_MAX)) {
SetuplogError(
LogSevWarning,
SETUPLOG_USE_MESSAGEID,
MSG_LOG_CHANGING_PW_FAIL,
AccountName, NULL,
SETUPLOG_USE_MESSAGEID,
MSG_LOG_X_RETURNED_STRING,
szGetAccountsDomainName,
szFALSE,
NULL,NULL);
goto err1;
}
//
// Open the AccountDomain. First find the Sid for this
// in the Sam and then open the domain using this sid.
//
//
// Get the AccountDomainSid from the Lsa
//
//
//
// Open the LSA Policy object to set the account domain sid.
//
SetupLsaInitObjectAttributes(&ObjectAttributes,&SecurityQualityOfService);
Status = LsaOpenPolicy(NULL,&ObjectAttributes,MAXIMUM_ALLOWED,&PolicyHandle);
if(NT_SUCCESS(Status)) {
Status = LsaQueryInformationPolicy(
PolicyHandle,
PolicyAccountDomainInformation,
&PolicyCurrentAccountDomainInfo
);
if(NT_SUCCESS(Status)) {
Status = SamOpenDomain(
ServerHandle,
DOMAIN_READ | DOMAIN_LIST_ACCOUNTS | DOMAIN_LOOKUP |
DOMAIN_READ_PASSWORD_PARAMETERS,
PolicyCurrentAccountDomainInfo->DomainSid,
&DomainHandle
);
LsaFreeMemory( PolicyCurrentAccountDomainInfo );
}
LsaClose( PolicyHandle );
}
if(!NT_SUCCESS(Status)) {
SetuplogError(
LogSevWarning,
SETUPLOG_USE_MESSAGEID,
MSG_LOG_CHANGING_PW_FAIL,
AccountName, NULL,
SETUPLOG_USE_MESSAGEID,
MSG_LOG_X_PARAM_RETURNED_NTSTATUS,
szSamOpenDomain,
Status,
AccountsDomainName,
NULL,NULL);
goto err2;
}
//
// Find the account name in this domain - and extract the rid.
//
UserFound = FALSE;
EnumerationContext = 0;
RtlInitUnicodeString(&UnicodeString,AccountName);
do {
Status = SamEnumerateUsersInDomain(
DomainHandle,
&EnumerationContext,
0L,
&SamRidEnumeration,
0L,
&CountOfEntries
);
if(!NT_SUCCESS(Status) && (Status != STATUS_MORE_ENTRIES)) {
SetuplogError(
LogSevWarning,
SETUPLOG_USE_MESSAGEID,
MSG_LOG_CHANGING_PW_FAIL,
AccountName, NULL,
SETUPLOG_USE_MESSAGEID,
MSG_LOG_X_RETURNED_NTSTATUS,
szSamEnumerateUsersInDomain,
Status,
NULL,NULL);
goto err3;
}
//
// go through the the SamRidEnumeration buffer for count entries.
//
for(i = 0; (i<CountOfEntries) && !UserFound; i++ ) {
if(RtlEqualUnicodeString(&UnicodeString,&SamRidEnumeration[i].Name,TRUE)) {
UserRid = SamRidEnumeration[i].RelativeId;
UserFound = TRUE;
}
}
SamFreeMemory(SamRidEnumeration);
} while((Status == STATUS_MORE_ENTRIES) && !UserFound);
if(!UserFound) {
SetuplogError(
LogSevWarning,
SETUPLOG_USE_MESSAGEID,
MSG_LOG_CHANGING_PW_FAIL,
AccountName,NULL,
SETUPLOG_USE_MESSAGEID,
MSG_LOG_USERNOTFOUND,
NULL,NULL);
goto err3;
}
//
// Open the user
//
Status = SamOpenUser(
DomainHandle,
USER_READ_ACCOUNT | USER_WRITE_ACCOUNT | USER_CHANGE_PASSWORD | USER_FORCE_PASSWORD_CHANGE,
UserRid,
&UserHandle
);
if(!NT_SUCCESS(Status)) {
SetuplogError(
LogSevWarning,
SETUPLOG_USE_MESSAGEID,
MSG_LOG_CHANGING_PW_FAIL,
AccountName, NULL,
SETUPLOG_USE_MESSAGEID,
MSG_LOG_X_RETURNED_NTSTATUS,
szSamOpenUser,
Status,
NULL,NULL);
goto err3;
}
//
// Use SAM API to change the password for this Account.
//
RtlInitUnicodeString(&UnicodeString,OldPassword);
RtlInitUnicodeString(&OtherUnicodeString,NewPassword);
Status = SamChangePasswordUser(UserHandle,&UnicodeString,&OtherUnicodeString);
if(!NT_SUCCESS(Status)) {
SetuplogError(
LogSevWarning,
SETUPLOG_USE_MESSAGEID,
MSG_LOG_CHANGING_PW_FAIL,
AccountName, NULL,
SETUPLOG_USE_MESSAGEID,
MSG_LOG_X_RETURNED_NTSTATUS,
szSamChangePasswordUser,
Status,
NULL,NULL);
goto err4;
}
b = TRUE;
err4:
SamCloseHandle(UserHandle);
err3:
SamCloseHandle(DomainHandle);
err2:
err1:
SamCloseHandle(ServerHandle);
err0:
return(b);
}
VOID
GenerateRandomPassword(
OUT PWSTR Password
)
{
static DWORD Seed = 98725757;
static PCWSTR UsableChars = L"ABCDEFGHIJKLMOPQRSTUVWYZabcdefghijklmopqrstuvwyz0123456789";
UINT UsableCount;
UINT i;
UsableCount = lstrlen(UsableChars);
Seed ^= GetCurrentTime();
for(i=0; i<PASSWORD_MAX; i++) {
Password[i] = UsableChars[RtlRandom(&Seed) % UsableCount];
}
Password[i] = 0;
}
NTSTATUS
MyAddLsaSecretObject(
IN PCWSTR Password
)
/*++
Routine Description:
Create the Secret Object necessary to support a machine account
on an NT domain.
Arguments:
Password - supplies password to machine account
Return value:
NT Status code indicating outcome.
--*/
{
UNICODE_STRING SecretName;
UNICODE_STRING UnicodePassword;
NTSTATUS Status;
LSA_HANDLE LsaHandle;
LSA_HANDLE SecretHandle;
OBJECT_ATTRIBUTES ObjAttr;
RtlInitUnicodeString(&SecretName,SsiSecretName) ;
RtlInitUnicodeString(&UnicodePassword,Password);
InitializeObjectAttributes(&ObjAttr,NULL,0,NULL,NULL);
Status = LsaOpenPolicy(NULL,&ObjAttr,MAXIMUM_ALLOWED,&LsaHandle);
if(NT_SUCCESS(Status)) {
Status = LsaCreateSecret(LsaHandle,&SecretName,SECRET_ALL_ACCESS,&SecretHandle);
if(NT_SUCCESS(Status)) {
Status = LsaSetSecret(SecretHandle,&UnicodePassword,&UnicodePassword);
LsaClose(SecretHandle);
}
LsaClose(LsaHandle);
}
return(Status);
}
BOOL
AdjustPrivilege(
IN PCWSTR Privilege,
IN BOOL Enable
)
/*++
Routine Description:
This routine enables or disable a priviliege of the current process.
Arguments:
Privilege - String with the name of the privilege to be adjusted.
Enable - TRUE if the privilege is to be enabled.
FALSE if the privilege is to be disabled.
Return Value:
Returns TRUE if the privilege could be adjusted.
Returns FALSE, otherwise.
--*/
{
HANDLE TokenHandle;
LUID_AND_ATTRIBUTES LuidAndAttributes;
TOKEN_PRIVILEGES TokenPrivileges;
if( !OpenProcessToken( GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
&TokenHandle ) ) {
SetupDebugPrint1(L"SYSSETUP: OpenProcessToken() failed. Error = %d \n", GetLastError() );
return( FALSE );
}
if( !LookupPrivilegeValue( NULL,
Privilege,
&( LuidAndAttributes.Luid ) ) ) {
SetupDebugPrint1(L"SYSSETUP: LookupPrivilegeValue failed, Error = %d \n", GetLastError() );
CloseHandle( TokenHandle );
return( FALSE );
}
if( Enable ) {
LuidAndAttributes.Attributes |= SE_PRIVILEGE_ENABLED;
} else {
LuidAndAttributes.Attributes &= ~SE_PRIVILEGE_ENABLED;
}
TokenPrivileges.PrivilegeCount = 1;
TokenPrivileges.Privileges[0] = LuidAndAttributes;
if( !AdjustTokenPrivileges( TokenHandle,
FALSE,
&TokenPrivileges,
0,
NULL,
NULL ) ) {
SetupDebugPrint1(L"SYSSETUP: AdjustTokenPrivileges failed, Error = %d \n", GetLastError() );
CloseHandle( TokenHandle );
return( FALSE );
}
CloseHandle( TokenHandle );
return( TRUE );
}
NTSTATUS
DisableLocalUserAccount(
PWSTR AccountName
)
/*++
Routine Description:
This routine disables the local administrator account.
Arguments:
AccountName - Name of the local account to be disabled.
Return Value:
NTSTATUS, depending on the outcome of the operations.
--*/
{
LONG rc;
PUSER_INFO_1 ui1;
// Get the info.
rc = NetUserGetInfo( NULL,
AccountName,
1,
(PBYTE *)(&ui1) );
if( rc == NO_ERROR ) {
// set the disable flag and store the info back out.
ui1->usri1_flags |= UF_ACCOUNTDISABLE;
rc = NetUserSetInfo( NULL,
AccountName,
1,
(PBYTE)ui1,
NULL );
NetApiBufferFree((PVOID)ui1);
}
return rc;
}
NTSTATUS
DisableLocalAdminAccount(
VOID
)
/*++
Routine Description:
This routine disables the local administrator account.
Arguments:
None.
Return Value:
NTSTATUS, depending on the outcome of the operations.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
WCHAR AdminAccountName[MAX_PATH];
GetAdminAccountName( AdminAccountName );
Status = DisableLocalUserAccount( AdminAccountName );
return Status;
}
DWORD
StorePasswordAsLsaSecret (
IN PCWSTR Password
)
{
LSA_OBJECT_ATTRIBUTES ObjectAttributes;
LSA_HANDLE LsaPolicyHandle;
LSA_UNICODE_STRING lusSecretName, lusSecretData;
USHORT SecretNameLength, SecretDataLength;
NTSTATUS ntsResult;
DWORD dwRetCode = ERROR_SUCCESS;
// Object attributes are reserved, so initialize to zeroes.
ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
// Get a handle to the Policy object.
ntsResult = LsaOpenPolicy(
NULL, //local machine
&ObjectAttributes,
POLICY_CREATE_SECRET,
&LsaPolicyHandle);
if( STATUS_SUCCESS != ntsResult )
{
// An error occurred. Return the win32 error code.
return LsaNtStatusToWinError(ntsResult);
}
//Initialize an LSA_UNICODE_STRING
SecretNameLength = (USHORT)wcslen(L"DefaultPassword");
lusSecretName.Buffer = L"DefaultPassword";
lusSecretName.Length = SecretNameLength * sizeof(WCHAR);
lusSecretName.MaximumLength = (SecretNameLength+1) * sizeof(WCHAR);
//Initialize the Password LSA_UNICODE_STRING
SecretDataLength = (USHORT)wcslen(Password);
lusSecretData.Buffer = (PWSTR)Password;
lusSecretData.Length = SecretDataLength * sizeof(WCHAR);
lusSecretData.MaximumLength = (SecretDataLength+1) * sizeof(WCHAR);
ntsResult = LsaStorePrivateData(
LsaPolicyHandle,
&lusSecretName,
&lusSecretData);
if( STATUS_SUCCESS != ntsResult ) {
dwRetCode = LsaNtStatusToWinError(ntsResult);
}
LsaClose(LsaPolicyHandle);
return dwRetCode;
}