578 lines
14 KiB
C++
578 lines
14 KiB
C++
/*---------------------------------------------------------------------------
|
|
File: LSAUtils.cpp
|
|
|
|
Comments: Code to change the domain membership of a workstation.
|
|
|
|
|
|
This file also contains some general helper functions, such as:
|
|
|
|
GetDomainDCName
|
|
EstablishNullSession
|
|
EstablishSession
|
|
EstablishShare // connects to a share
|
|
InitLsaString
|
|
GetDomainSid
|
|
|
|
|
|
(c) Copyright 1999, Mission Critical Software, Inc., All Rights Reserved
|
|
Proprietary and confidential to Mission Critical Software, Inc.
|
|
|
|
REVISION LOG ENTRY
|
|
Revision By: Christy Boles
|
|
Revised on 02/03/99 12:37:51
|
|
|
|
---------------------------------------------------------------------------
|
|
*/
|
|
|
|
//
|
|
|
|
//#include "stdafx.h"
|
|
#include <windows.h>
|
|
#include <process.h>
|
|
|
|
#ifndef UNICODE
|
|
#define UNICODE
|
|
#define _UNICODE
|
|
#endif
|
|
|
|
#include <lm.h> // for NetXxx API
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "LSAUtils.h"
|
|
#include "ErrDct.hpp"
|
|
#include "ResStr.h"
|
|
|
|
|
|
#define RTN_OK 0
|
|
#define RTN_USAGE 1
|
|
#define RTN_ERROR 13
|
|
|
|
extern TErrorDct err;
|
|
|
|
|
|
BOOL
|
|
GetDomainDCName(
|
|
LPWSTR Domain, // in - domain name
|
|
LPWSTR * pPrimaryDC // out- PDC name (must be freed with NetApiBufferFree)
|
|
)
|
|
{
|
|
NET_API_STATUS nas;
|
|
|
|
//
|
|
// get the name of the Primary Domain Controller
|
|
//
|
|
// we're using NetGetDCName instead of DsGetDCName so this can work on NT 3.51
|
|
|
|
nas = NetGetDCName(NULL, Domain, (LPBYTE *)pPrimaryDC);
|
|
|
|
if(nas != NERR_Success)
|
|
{
|
|
SetLastError(nas);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
EstablishNullSession(
|
|
LPCWSTR Server, // in - server name
|
|
BOOL bEstablish // in - TRUE=establish, FALSE=disconnect
|
|
)
|
|
{
|
|
return EstablishSession(Server,L"",L"",L"",bEstablish);
|
|
}
|
|
|
|
BOOL
|
|
EstablishSession(
|
|
LPCWSTR Server, // in - server name
|
|
LPWSTR Domain, // in - domain name for user credentials
|
|
LPWSTR UserName, // in - username for credentials to use
|
|
LPWSTR Password, // in - password for credentials
|
|
BOOL bEstablish // in - TRUE=establish, FALSE=disconnect
|
|
)
|
|
{
|
|
LPCWSTR szIpc = L"\\IPC$";
|
|
WCHAR RemoteResource[UNCLEN + 5 + 1]; // UNC len + \IPC$ + NULL
|
|
DWORD cchServer;
|
|
NET_API_STATUS nas;
|
|
|
|
//
|
|
// do not allow NULL or empty server name
|
|
//
|
|
if(Server == NULL || *Server == L'\0')
|
|
{
|
|
SetLastError(ERROR_INVALID_COMPUTERNAME);
|
|
return FALSE;
|
|
}
|
|
|
|
cchServer = lstrlenW( Server );
|
|
|
|
if( Server[0] != L'\\' && Server[1] != L'\\')
|
|
{
|
|
|
|
//
|
|
// prepend slashes and NULL terminate
|
|
//
|
|
RemoteResource[0] = L'\\';
|
|
RemoteResource[1] = L'\\';
|
|
RemoteResource[2] = L'\0';
|
|
}
|
|
else
|
|
{
|
|
cchServer -= 2; // drop slashes from count
|
|
|
|
RemoteResource[0] = L'\0';
|
|
}
|
|
|
|
if(cchServer > CNLEN)
|
|
{
|
|
SetLastError(ERROR_INVALID_COMPUTERNAME);
|
|
return FALSE;
|
|
}
|
|
|
|
if(lstrcatW(RemoteResource, Server) == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
if(lstrcatW(RemoteResource, szIpc) == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// disconnect or connect to the resource, based on bEstablish
|
|
//
|
|
if(bEstablish)
|
|
{
|
|
USE_INFO_2 ui2;
|
|
DWORD errParm;
|
|
|
|
ZeroMemory(&ui2, sizeof(ui2));
|
|
|
|
ui2.ui2_local = NULL;
|
|
ui2.ui2_remote = RemoteResource;
|
|
ui2.ui2_asg_type = USE_IPC;
|
|
ui2.ui2_domainname = Domain;
|
|
ui2.ui2_username = UserName;
|
|
ui2.ui2_password = Password;
|
|
|
|
// try establishing session for one minute
|
|
// if computer is not accepting any more connections
|
|
|
|
for (int i = 0; i < (60000 / 5000); i++)
|
|
{
|
|
nas = NetUseAdd(NULL, 2, (LPBYTE)&ui2, &errParm);
|
|
|
|
if (nas != ERROR_REQ_NOT_ACCEP)
|
|
{
|
|
break;
|
|
}
|
|
|
|
Sleep(5000);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
nas = NetUseDel(NULL, RemoteResource, 0);
|
|
}
|
|
|
|
if( nas == NERR_Success )
|
|
{
|
|
return TRUE; // indicate success
|
|
}
|
|
SetLastError(nas);
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
EstablishShare(
|
|
LPCWSTR Server, // in - server name
|
|
LPWSTR Share, // in - share name
|
|
LPWSTR Domain, // in - domain name for credentials to connect with
|
|
LPWSTR UserName, // in - user name to connect as
|
|
LPWSTR Password, // in - password for username
|
|
BOOL bEstablish // in - TRUE=connect, FALSE=disconnect
|
|
)
|
|
{
|
|
WCHAR RemoteResource[MAX_PATH];
|
|
DWORD cchServer;
|
|
NET_API_STATUS nas;
|
|
|
|
//
|
|
// do not allow NULL or empty server name
|
|
//
|
|
if(Server == NULL || *Server == L'\0')
|
|
{
|
|
SetLastError(ERROR_INVALID_COMPUTERNAME);
|
|
return FALSE;
|
|
}
|
|
|
|
cchServer = lstrlenW( Server );
|
|
|
|
if( Server[0] != L'\\' && Server[1] != L'\\')
|
|
{
|
|
|
|
//
|
|
// prepend slashes and NULL terminate
|
|
//
|
|
RemoteResource[0] = L'\\';
|
|
RemoteResource[1] = L'\\';
|
|
RemoteResource[2] = L'\0';
|
|
}
|
|
else
|
|
{
|
|
cchServer -= 2; // drop slashes from count
|
|
|
|
RemoteResource[0] = L'\0';
|
|
}
|
|
|
|
if(cchServer > CNLEN)
|
|
{
|
|
SetLastError(ERROR_INVALID_COMPUTERNAME);
|
|
return FALSE;
|
|
}
|
|
|
|
if(lstrcatW(RemoteResource, Server) == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
if(lstrcatW(RemoteResource, Share) == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// disconnect or connect to the resource, based on bEstablish
|
|
//
|
|
if(bEstablish)
|
|
{
|
|
USE_INFO_2 ui2;
|
|
DWORD errParm;
|
|
|
|
ZeroMemory(&ui2, sizeof(ui2));
|
|
|
|
ui2.ui2_local = NULL;
|
|
ui2.ui2_remote = RemoteResource;
|
|
ui2.ui2_asg_type = USE_DISKDEV;
|
|
ui2.ui2_domainname = Domain;
|
|
ui2.ui2_username = UserName;
|
|
ui2.ui2_password = Password;
|
|
|
|
// try establishing session for one minute
|
|
// if computer is not accepting any more connections
|
|
|
|
for (int i = 0; i < (60000 / 5000); i++)
|
|
{
|
|
nas = NetUseAdd(NULL, 2, (LPBYTE)&ui2, &errParm);
|
|
|
|
if (nas != ERROR_REQ_NOT_ACCEP)
|
|
{
|
|
break;
|
|
}
|
|
|
|
Sleep(5000);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
nas = NetUseDel(NULL, RemoteResource, 0);
|
|
}
|
|
|
|
if( nas == NERR_Success )
|
|
{
|
|
return TRUE; // indicate success
|
|
}
|
|
SetLastError(nas);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
void
|
|
InitLsaString(
|
|
PLSA_UNICODE_STRING LsaString, // i/o- pointer to LSA string to initialize
|
|
LPWSTR String // in - value to initialize LSA string to
|
|
)
|
|
{
|
|
DWORD StringLength;
|
|
|
|
if( String == NULL )
|
|
{
|
|
LsaString->Buffer = NULL;
|
|
LsaString->Length = 0;
|
|
LsaString->MaximumLength = 0;
|
|
}
|
|
else
|
|
{
|
|
StringLength = lstrlenW(String);
|
|
LsaString->Buffer = String;
|
|
LsaString->Length = (USHORT) StringLength * sizeof(WCHAR);
|
|
LsaString->MaximumLength = (USHORT) (StringLength + 1) * sizeof(WCHAR);
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
GetDomainSid(
|
|
LPWSTR PrimaryDC, // in - domain controller of domain to acquire Sid
|
|
PSID * pDomainSid // out- points to allocated Sid on success
|
|
)
|
|
{
|
|
NET_API_STATUS nas;
|
|
PUSER_MODALS_INFO_2 umi2 = NULL;
|
|
DWORD dwSidSize;
|
|
BOOL bSuccess = FALSE; // assume this function will fail
|
|
|
|
*pDomainSid = NULL; // invalidate pointer
|
|
|
|
__try {
|
|
|
|
//
|
|
// obtain the domain Sid from the PDC
|
|
//
|
|
nas = NetUserModalsGet(PrimaryDC, 2, (LPBYTE *)&umi2);
|
|
|
|
if(nas != NERR_Success) __leave;
|
|
//
|
|
// if the Sid is valid, obtain the size of the Sid
|
|
//
|
|
if(!IsValidSid(umi2->usrmod2_domain_id)) __leave;
|
|
|
|
dwSidSize = GetLengthSid(umi2->usrmod2_domain_id);
|
|
|
|
//
|
|
// allocate storage and copy the Sid
|
|
//
|
|
*pDomainSid = LocalAlloc(LPTR, dwSidSize);
|
|
|
|
if(*pDomainSid == NULL) __leave;
|
|
|
|
if(!CopySid(dwSidSize, *pDomainSid, umi2->usrmod2_domain_id)) __leave;
|
|
|
|
bSuccess = TRUE; // indicate success
|
|
|
|
} // try
|
|
|
|
__finally
|
|
{
|
|
|
|
if(umi2 != NULL)
|
|
{
|
|
NetApiBufferFree(umi2);
|
|
}
|
|
|
|
if(!bSuccess)
|
|
{
|
|
//
|
|
// if the function failed, free memory and indicate result code
|
|
//
|
|
|
|
if(*pDomainSid != NULL)
|
|
{
|
|
FreeSid(*pDomainSid);
|
|
*pDomainSid = NULL;
|
|
}
|
|
|
|
if( nas != NERR_Success )
|
|
{
|
|
SetLastError(nas);
|
|
}
|
|
}
|
|
|
|
} // finally
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
NTSTATUS
|
|
OpenPolicy(
|
|
LPWSTR ComputerName, // in - computer name
|
|
DWORD DesiredAccess, // in - access rights needed for policy
|
|
PLSA_HANDLE PolicyHandle // out- LSA handle
|
|
)
|
|
{
|
|
LSA_OBJECT_ATTRIBUTES ObjectAttributes;
|
|
LSA_UNICODE_STRING ComputerString;
|
|
PLSA_UNICODE_STRING Computer = NULL;
|
|
LPWSTR NewComputerName;
|
|
|
|
NewComputerName = (WCHAR*)LocalAlloc(LPTR,
|
|
(MAX_COMPUTERNAME_LENGTH+3)*sizeof(WCHAR));
|
|
if (!NewComputerName)
|
|
return STATUS_NO_MEMORY;
|
|
|
|
//
|
|
// Prepend some backslashes to the computer name so that
|
|
// this will work on NT 3.51
|
|
//
|
|
lstrcpy(NewComputerName,L"\\\\");
|
|
lstrcat(NewComputerName,ComputerName);
|
|
|
|
lstrcpy(NewComputerName,ComputerName);
|
|
|
|
//
|
|
// Always initialize the object attributes to all zeroes
|
|
//
|
|
ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
|
|
|
|
if(ComputerName != NULL)
|
|
{
|
|
//
|
|
// Make a LSA_UNICODE_STRING out of the LPWSTR passed in
|
|
//
|
|
InitLsaString(&ComputerString, NewComputerName);
|
|
|
|
Computer = &ComputerString;
|
|
}
|
|
|
|
//
|
|
// Attempt to open the policy
|
|
//
|
|
return LsaOpenPolicy(Computer,&ObjectAttributes,DesiredAccess,PolicyHandle);
|
|
}
|
|
|
|
/*++
|
|
This function sets the Primary Domain for the workstation.
|
|
|
|
To join the workstation to a Workgroup, ppdi.Name should be the name of
|
|
the Workgroup and ppdi.Sid should be NULL.
|
|
|
|
--*/
|
|
NTSTATUS
|
|
SetPrimaryDomain(
|
|
LSA_HANDLE PolicyHandle, // in -policy handle for computer
|
|
PSID DomainSid, // in - sid for new domain
|
|
LPWSTR TrustedDomainName // in - name of new domain
|
|
)
|
|
{
|
|
POLICY_PRIMARY_DOMAIN_INFO ppdi;
|
|
|
|
InitLsaString(&ppdi.Name, TrustedDomainName);
|
|
|
|
ppdi.Sid = DomainSid;
|
|
|
|
return LsaSetInformationPolicy(PolicyHandle,PolicyPrimaryDomainInformation,&ppdi);
|
|
}
|
|
|
|
|
|
// This function removes the information from the domain the computer used to
|
|
// be a member of
|
|
void
|
|
QueryWorkstationTrustedDomainInfo(
|
|
LSA_HANDLE PolicyHandle, // in - policy handle for computer
|
|
PSID DomainSid, // in - SID for new domain the computer is member of
|
|
BOOL bNoChange // in - flag indicating whether to write changes
|
|
)
|
|
{
|
|
// This function is not currently used.
|
|
NTSTATUS Status;
|
|
LSA_ENUMERATION_HANDLE h = 0;
|
|
LSA_TRUST_INFORMATION * ti = NULL;
|
|
ULONG count;
|
|
|
|
Status = LsaEnumerateTrustedDomains(PolicyHandle,&h,(void**)&ti,50000,&count);
|
|
|
|
if ( Status == STATUS_SUCCESS )
|
|
{
|
|
for ( UINT i = 0 ; i < count ; i++ )
|
|
{
|
|
if ( !bNoChange && !EqualSid(DomainSid,ti[i].Sid) )
|
|
{
|
|
// Remove the old trust
|
|
Status = LsaDeleteTrustedDomain(PolicyHandle,ti[i].Sid);
|
|
|
|
if ( Status != STATUS_SUCCESS )
|
|
{
|
|
|
|
}
|
|
}
|
|
}
|
|
LsaFreeMemory(ti);
|
|
}
|
|
else
|
|
{
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/*++
|
|
This function manipulates the trust associated with the supplied
|
|
DomainSid.
|
|
|
|
If the domain trust does not exist, it is created with the
|
|
specified password. In this case, the supplied PolicyHandle must
|
|
have been opened with POLICY_TRUST_ADMIN and POLICY_CREATE_SECRET
|
|
access to the policy object.
|
|
|
|
--*/
|
|
NTSTATUS
|
|
SetWorkstationTrustedDomainInfo(
|
|
LSA_HANDLE PolicyHandle, // in - policy handle
|
|
PSID DomainSid, // in - Sid of domain to manipulate
|
|
LPWSTR TrustedDomainName, // in - trusted domain name to add/update
|
|
LPWSTR Password, // in - new trust password for trusted domain
|
|
LPWSTR errOut // out- error text if function fails
|
|
)
|
|
{
|
|
LSA_UNICODE_STRING LsaPassword;
|
|
LSA_UNICODE_STRING KeyName;
|
|
LSA_UNICODE_STRING LsaDomainName;
|
|
DWORD cchDomainName; // number of chars in TrustedDomainName
|
|
NTSTATUS Status;
|
|
|
|
InitLsaString(&LsaDomainName, TrustedDomainName);
|
|
|
|
//
|
|
// ...convert TrustedDomainName to uppercase...
|
|
//
|
|
cchDomainName = LsaDomainName.Length / sizeof(WCHAR);
|
|
|
|
while(cchDomainName--)
|
|
{
|
|
LsaDomainName.Buffer[cchDomainName] = towupper(LsaDomainName.Buffer[cchDomainName]);
|
|
}
|
|
|
|
//
|
|
// ...create the trusted domain object
|
|
//
|
|
Status = LsaSetTrustedDomainInformation(
|
|
PolicyHandle,
|
|
DomainSid,
|
|
TrustedDomainNameInformation,
|
|
&LsaDomainName
|
|
);
|
|
|
|
if(Status == STATUS_OBJECT_NAME_COLLISION)
|
|
{
|
|
//printf("LsaSetTrustedDomainInformation: Name Collision (ok)\n");
|
|
}
|
|
else if (Status != STATUS_SUCCESS)
|
|
{
|
|
err.SysMsgWrite(ErrE,LsaNtStatusToWinError(Status),DCT_MSG_LSA_OPERATION_FAILED_SD,L"LsaSetTrustedDomainInformation", Status);
|
|
return RTN_ERROR;
|
|
}
|
|
|
|
InitLsaString(&KeyName, L"$MACHINE.ACC");
|
|
InitLsaString(&LsaPassword, Password);
|
|
|
|
//
|
|
// Set the machine password
|
|
//
|
|
Status = LsaStorePrivateData(
|
|
PolicyHandle,
|
|
&KeyName,
|
|
&LsaPassword
|
|
);
|
|
|
|
if(Status != STATUS_SUCCESS)
|
|
{
|
|
err.SysMsgWrite(ErrE,LsaNtStatusToWinError(Status),DCT_MSG_LSA_OPERATION_FAILED_SD,L"LsaStorePrivateData", Status);
|
|
return RTN_ERROR;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|