1210 lines
30 KiB
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;
|
|
}
|