Leaked source code of windows server 2003
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.
 
 
 
 
 
 

803 lines
21 KiB

/*---------------------------------------------------------------------------
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 <RpcDce.h>
#include <stdio.h>
#include "LSAUtils.h"
#include "ErrDct.hpp"
#include "ResStr.h"
#include "ealen.hpp"
#define RTN_OK 0
#define RTN_USAGE 1
#define RTN_ERROR 13
extern TErrorDct err;
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[2 + LEN_Computer + 5 + 1]; // \\ + computername + \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 > LEN_Computer)
{
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 dwArraySizeOfRemoteResource = sizeof(RemoteResource)/sizeof(RemoteResource[0]);
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;
}
// assume that Share has to be non-NULL
if(Share == NULL
|| wcslen(RemoteResource) + wcslen(Share) >= dwArraySizeOfRemoteResource
|| 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;
//
// 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, ComputerName);
Computer = &ComputerString;
}
//
// Attempt to open the policy
//
NTSTATUS status = LsaOpenPolicy(Computer,&ObjectAttributes,DesiredAccess,PolicyHandle);
return status;
}
/*++
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
NTSTATUS
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);
return Status;
}
}
}
LsaFreeMemory(ti);
}
else
{
return Status;
}
return STATUS_SUCCESS;
}
/*++
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;
}
//------------------------------------------------------------------------------
// StorePassword Function
//
// Synopsis
// Stores a password in LSA secret.
//
// Arguments
// IN pszIdentifier - the key name to store the password under
// IN pszPassword - the clear-text password to be stored
//
// Return
// Returns Win32 error code.
//------------------------------------------------------------------------------
DWORD __stdcall StorePassword(PCWSTR pszIdentifier, PCWSTR pszPassword)
{
DWORD dwError = ERROR_SUCCESS;
//
// The identifier parameter must specify a pointer to a non-zero length string. Note
// that a null password parameter is valid as this will delete the data and the key
// named by the identifier parameter.
//
if (pszIdentifier && *pszIdentifier)
{
//
// Open policy object with create secret access right.
//
LSA_HANDLE hPolicy = NULL;
LSA_OBJECT_ATTRIBUTES oa = { sizeof(LSA_OBJECT_ATTRIBUTES), NULL, NULL, 0, NULL, NULL };
NTSTATUS ntsStatus = LsaOpenPolicy(NULL, &oa, POLICY_CREATE_SECRET, &hPolicy);
if (LSA_SUCCESS(ntsStatus))
{
//
// Store specified password under key named by the identifier parameter.
//
PWSTR pszKey = const_cast<PWSTR>(pszIdentifier);
USHORT cbKey = wcslen(pszIdentifier) * sizeof(WCHAR);
LSA_UNICODE_STRING usKey = { cbKey, cbKey, pszKey };
if (pszPassword)
{
PWSTR pszData = const_cast<PWSTR>(pszPassword);
USHORT cbData = wcslen(pszPassword) * sizeof(WCHAR);
LSA_UNICODE_STRING usData = { cbData, cbData, pszData };
ntsStatus = LsaStorePrivateData(hPolicy, &usKey, &usData);
}
else
{
ntsStatus = LsaStorePrivateData(hPolicy, &usKey, NULL);
}
if (!LSA_SUCCESS(ntsStatus))
{
dwError = LsaNtStatusToWinError(ntsStatus);
}
//
// Close policy object.
//
LsaClose(hPolicy);
}
else
{
dwError = LsaNtStatusToWinError(ntsStatus);
}
}
else
{
dwError = ERROR_INVALID_PARAMETER;
}
return dwError;
}
//------------------------------------------------------------------------------
// RetrievePassword Function
//
// Synopsis
// Retrieves a password from LSA secret.
//
// Arguments
// IN pszIdentifier - the key name to retrieve the password from
// OUT pszPassword - the address of a buffer to return the clear-text password
// IN cchPassword - the size of the buffer in characters
//
// Return
// Returns Win32 error code.
//------------------------------------------------------------------------------
DWORD __stdcall RetrievePassword(PCWSTR pszIdentifier, PWSTR pszPassword, size_t cchPassword)
{
DWORD dwError = ERROR_SUCCESS;
//
// The identifier parameter must specify a pointer to a non-zero length string. The
// password parameters must specify a pointer to a buffer with length greater than
// zero.
//
if (pszIdentifier && *pszIdentifier && pszPassword && (cchPassword > 0))
{
memset(pszPassword, 0, cchPassword * sizeof(pszPassword[0]));
//
// Open policy object with get private information access right.
//
LSA_HANDLE hPolicy = NULL;
LSA_OBJECT_ATTRIBUTES oa = { sizeof(LSA_OBJECT_ATTRIBUTES), NULL, NULL, 0, NULL, NULL };
NTSTATUS ntsStatus = LsaOpenPolicy(NULL, &oa, POLICY_GET_PRIVATE_INFORMATION, &hPolicy);
if (LSA_SUCCESS(ntsStatus))
{
//
// Retrieve password from key named by specified identifier.
//
PWSTR pszKey = const_cast<PWSTR>(pszIdentifier);
USHORT cbKey = wcslen(pszIdentifier) * sizeof(pszIdentifier[0]);
LSA_UNICODE_STRING usKey = { cbKey, cbKey, pszKey };
PLSA_UNICODE_STRING pusData;
ntsStatus = LsaRetrievePrivateData(hPolicy, &usKey, &pusData);
if (LSA_SUCCESS(ntsStatus))
{
size_t cch = pusData->Length / sizeof(WCHAR);
if (cch < cchPassword)
{
wcsncpy(pszPassword, pusData->Buffer, cch);
pszPassword[cch] = 0;
}
else
{
dwError = ERROR_INSUFFICIENT_BUFFER;
}
SecureZeroMemory(pusData->Buffer, pusData->Length);
LsaFreeMemory(pusData);
}
else
{
dwError = LsaNtStatusToWinError(ntsStatus);
}
//
// Close policy object.
//
LsaClose(hPolicy);
}
else
{
dwError = LsaNtStatusToWinError(ntsStatus);
}
}
else
{
dwError = ERROR_INVALID_PARAMETER;
}
return dwError;
}
//------------------------------------------------------------------------------
// GeneratePasswordIdentifier Function
//
// Synopsis
// Generates a key name used to store a password under.
//
// Note that is important to delete the key after use as the system only allows
// 2048 LSA secrets to be stored by all applications on a given machine.
//
// Arguments
// IN pszIdentifier - the key name to retrieve the password from
// OUT pszPassword - the address of a buffer to return the clear-text password
// IN cchPassword - the size of the buffer in characters
//
// Return
// Returns Win32 error code.
//------------------------------------------------------------------------------
DWORD __stdcall GeneratePasswordIdentifier(PWSTR pszIdentifier, size_t cchIdentifier)
{
DWORD dwError = ERROR_SUCCESS;
//
// The identifier parameter must specify a pointer to a buffer with a length
// greater than or equal to the length of the password identifier.
//
if (pszIdentifier && (cchIdentifier > 0))
{
memset(pszIdentifier, 0, cchIdentifier * sizeof(pszIdentifier[0]));
//
// Generate unique identifier.
//
UUID uuid;
UuidCreate(&uuid);
PWSTR pszUuid;
RPC_STATUS rsStatus = UuidToString(&uuid, &pszUuid);
if (rsStatus == RPC_S_OK)
{
//
// Concatenate prefix and unique identifier. This makes
// it possible to identify keys generated by ADMT.
//
static const WCHAR IDENTIFIER_PREFIX[] = L"L$ADMT_PI_";
if ((wcslen(IDENTIFIER_PREFIX) + wcslen(pszUuid)) < cchIdentifier)
{
wcscpy(pszIdentifier, IDENTIFIER_PREFIX);
wcscat(pszIdentifier, pszUuid);
}
else
{
dwError = ERROR_INSUFFICIENT_BUFFER;
}
RpcStringFree(&pszUuid);
}
else
{
dwError = rsStatus;
}
}
else
{
dwError = ERROR_INVALID_PARAMETER;
}
return dwError;
}