NT4/private/newsam2/client/tmachine.c
2020-09-30 17:12:29 +02:00

903 lines
22 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
tmachine.c
Abstract:
This module tests the machine account creation facilities
of SAM.
Author:
Jim Kelly (JimK) 7-Feb-1994
Environment:
User Mode - Win32
Revision History:
--*/
///////////////////////////////////////////////////////////////////////////////
// //
// Includes //
// //
///////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <nt.h>
#include <ntsam.h>
#include <ntsamp.h>
#include <ntlsa.h>
#include <ntrpcp.h> // prototypes for MIDL user functions
#include <seopaque.h>
#include <string.h>
///////////////////////////////////////////////////////////////////////////////
// //
// Macros //
// //
///////////////////////////////////////////////////////////////////////////////
#ifndef SHIFT
#define SHIFT(c,v) {c--; v++;}
#endif //SHIFT
///////////////////////////////////////////////////////////////////////////////
// //
// Routines //
// //
///////////////////////////////////////////////////////////////////////////////
NTSTATUS
TSampGetLsaDomainInfo(
IN PUNICODE_STRING ServerName,
OUT PPOLICY_ACCOUNT_DOMAIN_INFO *PolicyAccountDomainInfo
)
/*++
Routine Description:
This routine retrieves ACCOUNT domain information from the LSA
policy database.
Arguments:
ServerName - name of machine to get account domain information
from.
PolicyAccountDomainInfo - Receives a pointer to a
POLICY_ACCOUNT_DOMAIN_INFO structure containing the account
domain info.
Return Value:
STATUS_SUCCESS - Succeeded.
Other status values that may be returned from:
LsaOpenPolicy()
LsaQueryInformationPolicy()
--*/
{
NTSTATUS
NtStatus,
IgnoreStatus;
LSA_HANDLE
PolicyHandle;
OBJECT_ATTRIBUTES
PolicyObjectAttributes;
//
// Open the policy database
//
InitializeObjectAttributes( &PolicyObjectAttributes,
NULL, // Name
0, // Attributes
NULL, // Root
NULL ); // Security Descriptor
NtStatus = LsaOpenPolicy( ServerName,
&PolicyObjectAttributes,
POLICY_VIEW_LOCAL_INFORMATION,
&PolicyHandle );
if ( NT_SUCCESS(NtStatus) ) {
//
// Query the account domain information
//
NtStatus = LsaQueryInformationPolicy( PolicyHandle,
PolicyAccountDomainInformation,
(PVOID *)PolicyAccountDomainInfo );
IgnoreStatus = LsaClose( PolicyHandle );
ASSERT(NT_SUCCESS(IgnoreStatus));
}
return(NtStatus);
}
NTSTATUS
TSampConnectToServer(
IN PUNICODE_STRING ServerName,
IN ACCESS_MASK DomainAccess,
OUT PHANDLE ServerHandle,
OUT PHANDLE DomainHandle,
OUT PSID *DomainSid
)
/*++
Routine Description:
Open a handle to the SAM server on the specified server
and then open the account domain on that same server.
Arguments:
ServerName - Name of server to connect to.
DomainAccess - accesses needed to the account domain.
ServerHandle - Receives a handle to the SAM server on the specified
system.
DomainHandle - Receives a handle to the account domain.
DomainSid - Receives a pointer to the SID of the account domain.
Return Value:
--*/
{
NTSTATUS
NtStatus;
OBJECT_ATTRIBUTES
ObjectAttributes;
PPOLICY_ACCOUNT_DOMAIN_INFO
AccountDomainInfo;
//
// get account domain info
//
NtStatus = TSampGetLsaDomainInfo( ServerName,
&AccountDomainInfo);
if (!NT_SUCCESS(NtStatus)) {
printf("SAM TEST: Failed to get lsa domain info...\n"
" Completion status is 0x%lx\n", NtStatus);
return(NtStatus);
}
printf("SAM TEST: Target domain is %wZ\n", &AccountDomainInfo->DomainName);
(*DomainSid) = AccountDomainInfo->DomainSid;
InitializeObjectAttributes( &ObjectAttributes, NULL, 0, 0, NULL );
NtStatus = SamConnect(
ServerName,
ServerHandle,
SAM_SERVER_READ | SAM_SERVER_EXECUTE,
&ObjectAttributes
);
if (!NT_SUCCESS(NtStatus)) {
printf("SAM TEST: Failed to connect...\n"
" Completion status is 0x%lx\n", NtStatus);
return(NtStatus);
}
NtStatus = SamOpenDomain(
(*ServerHandle),
DomainAccess,
*DomainSid,
DomainHandle
);
if (!NT_SUCCESS(NtStatus)) {
printf("Failed account domain open\n"
" Completion status is 0x%lx\n", NtStatus);
return(NtStatus);
}
return(STATUS_SUCCESS);
}
BOOLEAN
TSampEnableMachinePrivilege( VOID )
/*++
Routine Description:
This function enabled the SeMachineAccountPrivilege privilege.
Arguments:
None.
Return Value:
TRUE if privilege successfully enabled.
FALSE if not successfully enabled.
--*/
{
NTSTATUS Status;
HANDLE Token;
LUID SecurityPrivilege;
PTOKEN_PRIVILEGES NewState;
ULONG ReturnLength;
//
// Open our own token
//
Status = NtOpenProcessToken(
NtCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES,
&Token
);
if (!NT_SUCCESS(Status)) {
printf("SAM TEST: Can't open process token to enable Privilege.\n"
" Completion status of NtOpenProcessToken() is: 0x%lx\n", Status);
return(FALSE);
}
//
// Initialize the adjustment structure
//
SecurityPrivilege =
RtlConvertLongToLargeInteger(SE_MACHINE_ACCOUNT_PRIVILEGE);
ASSERT( (sizeof(TOKEN_PRIVILEGES) + sizeof(LUID_AND_ATTRIBUTES)) < 100);
NewState = RtlAllocateHeap( RtlProcessHeap(), 0, 100 );
NewState->PrivilegeCount = 1;
NewState->Privileges[0].Luid = SecurityPrivilege;
NewState->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
//
// Set the state of the privilege to ENABLED.
//
Status = NtAdjustPrivilegesToken(
Token, // TokenHandle
FALSE, // DisableAllPrivileges
NewState, // NewState
0, // BufferLength
NULL, // PreviousState (OPTIONAL)
&ReturnLength // ReturnLength
);
// don't use NT_SUCCESS here because STATUS_NOT_ALL_ASSIGNED is a success status
if (Status != STATUS_SUCCESS) {
return(FALSE);
}
//
// Clean up some stuff before returning
//
RtlFreeHeap( RtlProcessHeap(), 0, NewState );
Status = NtClose( Token );
ASSERT(NT_SUCCESS(Status));
return TRUE;
}
NTSTATUS
TSampCreateMachine(
IN SAM_HANDLE DomainHandle,
IN PUNICODE_STRING AccountName
)
/*++
Routine Description:
This routine attempts to create a machine account.
One of two cases may be tested:
1) DomainHandle is open for DOMAIN_CREATE_USER,
or
2) DomainHandle is open for DOMAIN_LOOKUP and
the SeMachineAccountPrivilege privilege is
enabled.
It is the caller's responsibility to establish the
correct case criteria before calling.
Arguments:
DomainHandle - handle to domain to create account in.
AccountName - Name of the account to create.
Return Value:
--*/
{
NTSTATUS
NtStatus,
IgnoreStatus;
SAM_HANDLE
UserHandle;
ACCESS_MASK
GrantedAccess;
ULONG
Rid;
NtStatus = SamCreateUser2InDomain( DomainHandle,
AccountName,
USER_WORKSTATION_TRUST_ACCOUNT,
MAXIMUM_ALLOWED,
&UserHandle,
&GrantedAccess,
&Rid);
if (NT_SUCCESS(NtStatus)) {
IgnoreStatus = SamCloseHandle( UserHandle );
ASSERT(NT_SUCCESS(IgnoreStatus));
printf("SAM TEST: Machine account created.\n"
" GrantedAccess: 0x%lx\n"
" Rid: %d (0x%lx)\n",
GrantedAccess, Rid, Rid);
} else {
printf("SAM TEST: Machine account creation failed.\n"
" Status: 0x%lx\n", NtStatus);
}
return(NtStatus);
}
NTSTATUS
TSampSetPasswordMachine(
IN SAM_HANDLE DomainHandle,
IN PUNICODE_STRING AccountName,
IN PUNICODE_STRING Password
)
/*++
Routine Description:
This routine attempts to set the password of a machine account.
Arguments:
DomainHandle - handle to domain account is in.
AccountName - Name of the account to set password.
Password - New password.
Return Value:
--*/
{
NTSTATUS
NtStatus;
SAM_HANDLE
UserHandle;
PULONG
RelativeIds;
PSID_NAME_USE
Use;
USER_SET_PASSWORD_INFORMATION
PasswordInfo;
PasswordInfo.Password = (*Password);
PasswordInfo.PasswordExpired = FALSE;
NtStatus = SamLookupNamesInDomain( DomainHandle,
1,
AccountName,
&RelativeIds,
&Use);
if (!NT_SUCCESS(NtStatus)) {
printf("SAM TEST: Couldn't find account to set password.\n"
" Lookup status: 0x%lx\n", NtStatus);
return(NtStatus);
}
NtStatus = SamOpenUser( DomainHandle,
USER_FORCE_PASSWORD_CHANGE,
RelativeIds[0],
&UserHandle);
if (!NT_SUCCESS(NtStatus)) {
printf("SAM TEST: Couldn't open user account for FORCE_PASSWORD_CHANGE.\n"
" Lookup status: 0x%lx\n", NtStatus);
return(NtStatus);
}
NtStatus = SamSetInformationUser( UserHandle,
UserSetPasswordInformation,
&PasswordInfo
);
if (!NT_SUCCESS(NtStatus)) {
printf("SAM TEST: Couldn't set password on user account.\n"
" Set Info status: 0x%lx\n", NtStatus);
return(NtStatus);
}
return(STATUS_SUCCESS);
}
NTSTATUS
TSampDeleteMachine(
IN SAM_HANDLE DomainHandle,
IN PUNICODE_STRING AccountName
)
/*++
Routine Description:
This routine attempts to delete a machine account.
Arguments:
DomainHandle - handle to domain to delete account from.
AccountName - Name of the account to delete.
Return Value:
--*/
{
NTSTATUS
NtStatus;
SAM_HANDLE
UserHandle;
PULONG
RelativeIds;
PSID_NAME_USE
Use;
NtStatus = SamLookupNamesInDomain( DomainHandle,
1,
AccountName,
&RelativeIds,
&Use);
if (!NT_SUCCESS(NtStatus)) {
printf("SAM TEST: Couldn't find account to delete.\n"
" Lookup status: 0x%lx\n", NtStatus);
return(NtStatus);
}
NtStatus = SamOpenUser( DomainHandle,
DELETE,
RelativeIds[0],
&UserHandle);
if (!NT_SUCCESS(NtStatus)) {
printf("SAM TEST: Couldn't open user account for delete.\n"
" Open status: 0x%lx\n", NtStatus);
return(NtStatus);
}
NtStatus = SamDeleteUser( UserHandle );
if (!NT_SUCCESS(NtStatus)) {
printf("SAM TEST: Couldn't delete user account.\n"
" DeleteUser status: 0x%lx\n", NtStatus);
return(NtStatus);
}
return(STATUS_SUCCESS);
}
VOID
TSampPrintYesOrNo(
IN BOOLEAN b
)
{
if (b) {
printf("Yes\n");
} else {
printf("No\n");
}
}
VOID
TSampUsage( VOID )
{
printf("\n\n Command format:\n");
printf(" tmachine [/c] [/p] [/d] <account-name> <machine> [<password>]\n");
printf("\n");
printf(" Switches\n");
printf(" /c - create account\n");
printf(" /p - set password on account\n");
printf(" /d - delete account\n");
printf("\n");
printf(" if multiple switches are specified, they are attempted in\n");
printf(" the order listed above. An error in any attempt will prevent\n");
printf(" any further attempts.\n");
printf("\n");
return;
}
VOID
main (c,v)
int c;
char **v;
/*++
Routine Description:
This is the main entry routine for this test.
Arguments:
Argv[1] - account name to create or delete
Argv[2] - domain controller machine name
Argv[3] - 'D' to delete account, otherwise account is created.
Return Value:
--*/
{
NTSTATUS
NtStatus,
IgnoreStatus;
UNICODE_STRING
AccountName,
ControllerName,
Password;
WCHAR
AccountNameBuffer[80],
ControllerNameBuffer[80],
PasswordBuffer[80];
ANSI_STRING
AnsiString;
SAM_HANDLE
ServerHandle,
ServerHandle2,
DomainHandle,
DomainHandle2;
PSID
DomainSid;
BOOLEAN
Create = FALSE,
SetPassword = FALSE,
Delete = FALSE;
ULONG
ArgNum = 0;
PCHAR
p;
CHAR
ch;
AccountName.Length = 0;
ControllerName.Length = 0;
Password.Length = 0;
//
// Command format:
//
// tmachine [/c] [/p] [/d] <account-name> <machine> [<password>]
//
// Switches
// /c - create account
// /p - set password on account
// /d - delete account
//
// if multiple switches are specified, they are attempted in
// the order listed above. An error in any attempt will prevent
// any further attempts.
//
SHIFT (c,v);
while ((c > 0) && ((ch = *v[0]))) {
p = *v;
if (ch == '/') {
while (*++p != '\0') {
if ((*p == 'c') || (*p == 'C')) {
Create = TRUE;
// printf("Create\n");
} else if ((*p == 'p') || (*p == 'P')) {
SetPassword = TRUE;
// printf("SetPassword\n");
} else if ((*p == 'd') || (*p == 'D')) {
Delete = TRUE;
// printf("Delete\n");
} else {
TSampUsage();
return;
}
}
} else {
switch (ArgNum) {
case 0:
//
// collecting account name
//
AccountName.Buffer = AccountNameBuffer;
AccountName.MaximumLength = sizeof(AccountNameBuffer);
RtlInitAnsiString(&AnsiString, (*v));
RtlAnsiStringToUnicodeString(&AccountName, &AnsiString, FALSE);
// printf("account: %wZ\n", &AccountName);
break;
case 1:
//
// collecting machine name
//
ControllerName.Buffer = ControllerNameBuffer;
ControllerName.MaximumLength = sizeof(ControllerNameBuffer);
RtlInitAnsiString(&AnsiString, (*v));
RtlAnsiStringToUnicodeString(&ControllerName, &AnsiString, FALSE);
// printf("machine: %wZ\n", &ControllerName);
break;
case 2:
//
// collecting password name
//
Password.Buffer = PasswordBuffer;
Password.MaximumLength = sizeof(PasswordBuffer);
RtlInitAnsiString(&AnsiString, (*v));
RtlAnsiStringToUnicodeString(&Password, &AnsiString, FALSE);
// printf("password: %wZ\n", &Password);
break;
default:
//
// collecting garbage.
//
break;
}
ArgNum++;
}
SHIFT(c,v);
}
printf("parameters:\n");
printf(" Create Account: "); TSampPrintYesOrNo( Create );
printf(" Set Password : "); TSampPrintYesOrNo( SetPassword );
printf(" Delete Account: "); TSampPrintYesOrNo( Delete );
printf(" Account : *%wZ*\n", &AccountName);
printf(" Machine : *%wZ*\n", &ControllerName);
printf(" Password : *%wZ*\n", &Password);
//
// Make sure we don't have conflicting parameters
//
// Rules:
//
// 1) account name is always required.
// 2) password and machine are required if /P was specified.
// 3) machine is optional if /P not specified.
//
//
if ( (AccountName.Length == 0) ||
( SetPassword && (ControllerName.Length == 0) ) ||
( SetPassword && (Password.Length == 0) ) ) {
TSampUsage();
return;
}
//
// Open the server and the account domain
//
NtStatus = TSampConnectToServer(&ControllerName,
DOMAIN_LOOKUP | DOMAIN_READ_PASSWORD_PARAMETERS,
&ServerHandle,
&DomainHandle,
&DomainSid);
if (Create) {
//
// try to create the machine account with privilege.
//
printf("SAM TEST: Creating machine account with privilege.\n");
TSampEnableMachinePrivilege();
NtStatus = TSampCreateMachine( DomainHandle, &AccountName );
if (NT_SUCCESS(NtStatus)) {
printf(" Status: successful\n");
} else {
if (NtStatus == STATUS_ACCESS_DENIED) {
//
// We didn't have the privilege, and didn't have
// the domain open so that it would work without
// the privilege.
//
printf(" Couldn't create account with privilege (0x%lx)\n"
" Attempting normal creation (without privilege)\n"
, NtStatus);
NtStatus = TSampConnectToServer(&ControllerName,
DOMAIN_LOOKUP |
DOMAIN_READ_PASSWORD_PARAMETERS |
DOMAIN_CREATE_USER,
&ServerHandle2,
&DomainHandle2,
&DomainSid);
if (!NT_SUCCESS(NtStatus)) {
printf(" Can't open domain for CREATE_USER access (0x%lx)\n", NtStatus);
} else {
NtStatus = TSampCreateMachine( DomainHandle2,
&AccountName );
if (NT_SUCCESS(NtStatus)) {
printf(" Status: successful\n");
} else {
printf(" Failed: 0x%lx\n", NtStatus);
}
IgnoreStatus = SamCloseHandle( DomainHandle2 );
}
}
if (!NT_SUCCESS(NtStatus)) {
printf(" Status: 0x%lx", NtStatus);
return;
}
}
}
if (SetPassword) {
//
// Try to set the password on the account
//
printf("SAM TEST: Setting password of account ...\n");
NtStatus = TSampSetPasswordMachine( DomainHandle, &AccountName, &Password );
if (NT_SUCCESS(NtStatus)) {
printf(" Status: successful\n");
} else {
printf(" Status: 0x%lx", NtStatus);
return;
}
}
if (Delete) {
printf("SAM TEST: Deleting account ...\n");
NtStatus = TSampDeleteMachine( DomainHandle, &AccountName );
if (NT_SUCCESS(NtStatus)) {
printf(" Status: successful\n");
} else {
printf(" Status: 0x%lx", NtStatus);
return;
}
}
return;
}