/**********************************************************************/
/**                       Microsoft Windows NT                       **/
/**             Copyright(c) Microsoft Corp., 1991-1996              **/
/**********************************************************************/

/*
    WelcomeDlg.cpp

	CPropertyPage support for User management wizard

    FILE HISTORY:
        jony     Apr-1996     created
*/

#include "stdafx.h"
#include "Speckle.h"
#include "wizbased.h"
#include "Welcome.h"
#include "trstlist.h"

#include <winreg.h>
#include <lmerr.h>
#include <lmapibuf.h>

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CWelcomeDlg property page

IMPLEMENT_DYNCREATE(CWelcomeDlg, CWizBaseDlg)

CWelcomeDlg::CWelcomeDlg() : CWizBaseDlg(CWelcomeDlg::IDD)
{
	//{{AFX_DATA_INIT(CWelcomeDlg)
	//}}AFX_DATA_INIT

	m_pFont = NULL;
}

CWelcomeDlg::~CWelcomeDlg()
{
	if (m_pFont != NULL) delete m_pFont;
}

void CWelcomeDlg::DoDataExchange(CDataExchange* pDX)
{
	CPropertyPage::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CWelcomeDlg)
	DDX_Control(pDX, IDC_DOMAIN_LIST, m_cbDomainList);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CWelcomeDlg, CPropertyPage)
	//{{AFX_MSG_MAP(CWelcomeDlg)
	ON_WM_SHOWWINDOW()
	//}}AFX_MSG_MAP

END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CWelcomeDlg message handlers
BOOL CWelcomeDlg::OnInitDialog() 
{
	CPropertyPage::OnInitDialog();
	CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
// read cached domain list from registry
	DWORD dwRet;
	HKEY hKey;
	DWORD cbProv = 0;
	TCHAR* lpProv = NULL;

	BOOL bFoundOne = FALSE;

	long lRet = RegConnectRegistry(
		(LPTSTR)pApp->m_csServer.GetBuffer(pApp->m_csServer.GetLength()), 
		HKEY_LOCAL_MACHINE,
		&hKey);
	
    dwRet = RegOpenKey(hKey,
		TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"), &hKey );

	TCHAR* lpPrimaryDomain = NULL;
	if ((dwRet = RegQueryValueEx( hKey, TEXT(/*"CachePrimaryDomain"*/"DefaultDomainName"), NULL, NULL, NULL, &cbProv )) == ERROR_SUCCESS)
		{
		lpPrimaryDomain = (TCHAR*)malloc(cbProv);
		if (lpPrimaryDomain == NULL)
			{
			AfxMessageBox(IDS_GENERIC_NO_HEAP, MB_ICONEXCLAMATION);
			ExitProcess(1);
			}
		dwRet = RegQueryValueEx( hKey, TEXT(/*"CachePrimaryDomain"*/"DefaultDomainName"), NULL, NULL, (LPBYTE) lpPrimaryDomain, &cbProv );
		bFoundOne = TRUE;
		}

	m_csPrimaryDomain = lpPrimaryDomain;
	free(lpPrimaryDomain);
	RegCloseKey(hKey);

	CString csMachineName;
	DWORD dwSize = MAX_COMPUTERNAME_LENGTH + 1;
	GetComputerName(csMachineName.GetBufferSetLength(MAX_COMPUTERNAME_LENGTH + 1), &dwSize);

	pApp->m_csCurrentMachine = csMachineName;

// read the list of trusted domains
	CTrustList pList;
	if (!pList.BuildTrustList((LPTSTR)pApp->m_csServer.GetBuffer(pApp->m_csServer.GetLength()))) 
		{					 
/* if this fails its probably because they are running the wizard 
	from a machine account that doesn't exist on the domain level. 
	Add only the local machine and select it.*/
		m_cbDomainList.AddString(pApp->m_csCurrentMachine);
		m_cbDomainList.SelectString(-1, pApp->m_csCurrentMachine);
		}

	else
		{
		UINT i;
		for(i = 0 ; i < pList.m_dwTrustCount ; i++)
			m_cbDomainList.AddString(pList.m_ppszTrustList[i]);

// remove the current machine from the list
//	if ((i = m_cbDomainList.FindStringExact(-1, pApp->m_csCurrentMachine)) != LB_ERR)
//		m_cbDomainList.DeleteString(i);

// now select the default domain into view
		int nSel = m_cbDomainList.SelectString(-1, m_csPrimaryDomain);
		m_cbDomainList.GetWindowText(m_csDomain);
		UpdateData(FALSE);	 
		}

// welcome text
	m_pFont = new CFont;
	LOGFONT lf;

	memset(&lf, 0, sizeof(LOGFONT));   // Clear out structure.
	lf.lfHeight = 15;                  
	_tcscpy(lf.lfFaceName, L"MS Sans Serif");  
	lf.lfWeight = 700;
	m_pFont->CreateFontIndirect(&lf);    // Create the font.

	CString cs;
	cs.LoadString(IDS_WELCOME_STRING);
	CWnd* pWnd = GetDlgItem(IDC_STATIC1);
	pWnd->SetWindowText(cs);
	pWnd->SetFont(m_pFont);

	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

LRESULT CWelcomeDlg::OnWizardNext()
{
	UpdateData(TRUE);
	CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();

// get the DC of the selected domain
	m_cbDomainList.GetWindowText(m_csDomain);

// same as last time? no need to check again.
	if (m_csLastDomain == m_csDomain) return CPropertyPage::OnWizardNext();

	CWaitCursor wait;

	pApp->m_csDomain = m_csDomain;
	pApp->m_bDomain = FALSE;
	TCHAR* pDomain = m_csDomain.GetBuffer(m_csDomain.GetLength());
	m_csDomain.ReleaseBuffer();	

	TCHAR* pDC;
	NET_API_STATUS nApi;

// local machine?
	if (m_csDomain == pApp->m_csCurrentMachine)
		{
		pApp->m_csServer = CString(L"\\\\") + pApp->m_csCurrentMachine;
		pDC = pApp->m_csServer.GetBuffer(pApp->m_csServer.GetLength());
		}

	else
		{
		nApi = NetGetDCName(NULL, 
			pDomain, 
			(LPBYTE*)&pDC);

		if (nApi != NERR_Success)
			{
			AfxMessageBox(IDS_NODC, MB_ICONSTOP);
			return -1;
			}
		pApp->m_csServer = pDC;
		pApp->m_bDomain = TRUE;
		}

// we really shouldn't proceed until we know we are an admin on the remote machine
	BYTE sidBuffer[100];
	PSID pSID = (PSID)&sidBuffer;
	BOOL bRet;		
					 
// create a SID for the Administrators group
	SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;
	bRet = AllocateAndInitializeSid(&SIDAuth,
		2,
		SECURITY_BUILTIN_DOMAIN_RID,
		DOMAIN_ALIAS_RID_ADMINS,
		0,
		0,
		0,
		0,
		0,
		0,
		&pSID);

	if (!bRet) 
		{
		DWORD dw = GetLastError();
		ASSERT(0);
		}

	TCHAR pName[256];
	DWORD dwNameLen = 256;
	TCHAR pDomainName[256];
	DWORD dwDomainNameLen = 256;
	SID_NAME_USE SNU;

	bRet = LookupAccountSid(pDC,
		pSID,
		pName,
		&dwNameLen,
		pDomainName,
		&dwDomainNameLen,
		&SNU);

// get the users name and domain from the reg for comparison
	DWORD dwRet;							   
	HKEY hKey;
	DWORD cbProv = 0;

	CString csUsername;
	CString csDomainName;
    dwRet = RegOpenKey(HKEY_LOCAL_MACHINE,
		TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"), &hKey );
	
	if ((dwRet = RegQueryValueEx( hKey, TEXT("DefaultDomainName"), NULL, NULL, NULL, &cbProv )) == ERROR_SUCCESS)
		{
		dwRet = RegQueryValueEx( hKey, TEXT("DefaultDomainName"), 
			NULL, 
			NULL, 
			(LPBYTE)csDomainName.GetBufferSetLength(cbProv), 
			&cbProv );
		}

	TCHAR* lpDefaultUserName = NULL;
	if ((dwRet = RegQueryValueEx( hKey, TEXT("DefaultUserName"), NULL, NULL, NULL, &cbProv )) == ERROR_SUCCESS)
		{
		dwRet = RegQueryValueEx( hKey, TEXT("DefaultUserName"), 
			NULL, 
			NULL, 
			(LPBYTE)csUsername.GetBufferSetLength(cbProv), 
			&cbProv );
		}

	RegCloseKey(hKey);

// now enumerate the members of the admin group to see if we are a member
	BOOL bAdmin = FALSE;
	PLOCALGROUP_MEMBERS_INFO_1 pMembers;
	DWORD dwEntriesRead, dwTotalEntries;
	DWORD dwResumeHandle = 0;
	nApi = NetLocalGroupGetMembers(pDC,
		pName,
		1,
		(LPBYTE*)&pMembers,
		5000,
		&dwEntriesRead,
		&dwTotalEntries,
		&dwResumeHandle);

	if (nApi == NERR_Success)
		{
		USHORT sIndex = 0;
		while (sIndex < dwEntriesRead)	
			{
			TCHAR pName[50];
			DWORD dwNameSize = 50;
			TCHAR pDomain[50];
			DWORD dwDomainNameSize = 50;
			SID_NAME_USE pUse;
			LookupAccountSid(pDC, pMembers[sIndex].lgrmi1_sid,
				pName, &dwNameSize,
				pDomain, &dwDomainNameSize,
				&pUse);
			
			if (((pUse == SidTypeGroup) && (bParseGlobalGroup(pName, csUsername, csDomainName))) ||
				((!csUsername.CompareNoCase(pName)) && (!csDomainName.CompareNoCase(pDomain)))) 
				{
				bAdmin = TRUE;
				break;
				}

			sIndex++;
			}

		NetApiBufferFree(pMembers);

		while ((dwResumeHandle != 0) && (!bAdmin))
			{
			nApi = NetLocalGroupGetMembers(pDC,
				pName,
				1,
				(LPBYTE*)&pMembers,
				5000,
				&dwEntriesRead,
				&dwTotalEntries,
				&dwResumeHandle);

			if (nApi == NERR_Success)
				{
				USHORT sIndex = 0;
				while (sIndex < dwEntriesRead)
					{
					TCHAR pName[50];
					DWORD dwNameSize = 50;
					TCHAR pDomain[50];
					DWORD dwDomainNameSize = 50;
					SID_NAME_USE pUse;
					LookupAccountSid(pDC, pMembers[sIndex].lgrmi1_sid,
						pName, &dwNameSize,
						pDomain, &dwDomainNameSize,
						&pUse);
					
					if (((pUse == SidTypeGroup) && (bParseGlobalGroup(pName, csUsername, csDomainName))) ||
						((!csUsername.CompareNoCase(pName)) && (!csDomainName.CompareNoCase(pDomain)))) 
						{
						bAdmin = TRUE;
						break;
						}

					sIndex++;
					}
				}
			NetApiBufferFree(pMembers);
			}
		}
			  
	if (!bAdmin) // not in the administrators group - check the account ops group
		{
		BYTE sidBuffer[100];
		PSID pSID = (PSID)&sidBuffer;
		BOOL bRet;		

// create a SID for the Account Operators group
		SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;
		bRet = AllocateAndInitializeSid(&SIDAuth,
			2,
			SECURITY_BUILTIN_DOMAIN_RID,
			DOMAIN_ALIAS_RID_ACCOUNT_OPS,
			0,
			0,
			0,
			0,
			0,
			0,
			&pSID);

		if (!bRet) 
			{
			DWORD dw = GetLastError();
			ASSERT(0);
			}

		TCHAR pName[256];
		DWORD dwNameLen = 256;
		TCHAR pDomainName[256];
		DWORD dwDomainNameLen = 256;
		SID_NAME_USE SNU;

		bRet = LookupAccountSid(pDC,
			pSID,
			pName,
			&dwNameLen,
			pDomainName,
			&dwDomainNameLen,
			&SNU);

// now enumerate the members of the group to see if we are a member
		PLOCALGROUP_MEMBERS_INFO_1 pMembers;
		DWORD dwEntriesRead, dwTotalEntries;
		DWORD dwResumeHandle = 0;
		nApi = NetLocalGroupGetMembers(pDC,
			pName,
			1,
			(LPBYTE*)&pMembers,
			5000,
			&dwEntriesRead,
			&dwTotalEntries,
			&dwResumeHandle);

		if (nApi == NERR_Success)
			{
			USHORT sIndex = 0;
			while (sIndex < dwEntriesRead)	
				{
				TCHAR pName[50];
				DWORD dwNameSize = 50;
				TCHAR pDomain[50];
				DWORD dwDomainNameSize = 50;
				SID_NAME_USE pUse;
				LookupAccountSid(pDC, pMembers[sIndex].lgrmi1_sid,
					pName, &dwNameSize,
					pDomain, &dwDomainNameSize,
					&pUse);
				
				if (((pUse == SidTypeGroup) && (bParseGlobalGroup(pName, csUsername, csDomainName))) ||
					((!csUsername.CompareNoCase(pName)) && (!csDomainName.CompareNoCase(pDomain)))) 
					{
					bAdmin = TRUE;
					break;
					}

				sIndex++;
				}

			NetApiBufferFree(pMembers);

			while ((dwResumeHandle != 0) && (!bAdmin))
				{
				nApi = NetLocalGroupGetMembers(pDC,
					pName,
					1,
					(LPBYTE*)&pMembers,
					5000,
					&dwEntriesRead,
					&dwTotalEntries,
					&dwResumeHandle);

				if (nApi == NERR_Success)
					{
					USHORT sIndex = 0;
					while (sIndex < dwEntriesRead)
						{
						TCHAR pName[50];
						DWORD dwNameSize = 50;
						TCHAR pDomain[50];
						DWORD dwDomainNameSize = 50;
						SID_NAME_USE pUse;
						LookupAccountSid(pDC, pMembers[sIndex].lgrmi1_sid,
							pName, &dwNameSize,
							pDomain, &dwDomainNameSize,
							&pUse);
						
						if (((pUse == SidTypeGroup) && (bParseGlobalGroup(pName, csUsername, csDomainName))) ||
							((!csUsername.CompareNoCase(pName)) && (!csDomainName.CompareNoCase(pDomain)))) 
							{
							bAdmin = TRUE;
							break;
							}

						sIndex++;
						}
					}
				NetApiBufferFree(pMembers);
				}
			}

		}

// not an admin? don't continue
	if (!bAdmin)
		{
		AfxMessageBox(IDS_NOT_ADMIN);
		return -1;
		}

// store the domain name for a possible rerun.
	m_csLastDomain = m_csDomain;
		
	return CPropertyPage::OnWizardNext();

}	

// this gets called to look into a global group which is included in the admin or account ops local group.
// these groups live on the DC of the domain passed in.
BOOL CWelcomeDlg::bParseGlobalGroup(LPTSTR lpGroupName, CString& lpName, CString& lpDomain)
{
	DWORD dwEntriesRead;
	DWORD dwTotalEntries;
	DWORD dwResumeHandle = 0;
	CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();

	TCHAR* pDomain = lpDomain.GetBuffer(lpDomain.GetLength());
	lpDomain.ReleaseBuffer();	

	TCHAR* pServer;
	NET_API_STATUS nApi = NetGetDCName(NULL, 
		pDomain, 
		(LPBYTE*)&pServer);

	if (nApi != NERR_Success)
		{
		AfxMessageBox(IDS_NODC, MB_ICONSTOP);
		return FALSE;
		}
	
	PGROUP_USERS_INFO_1 pMembers;
	nApi = NetGroupGetUsers(pServer,
		lpGroupName,
		1,
		(LPBYTE*)&pMembers,
		5000,
		&dwEntriesRead,
		&dwTotalEntries, 
		&dwResumeHandle);

	if (nApi != ERROR_SUCCESS) 
		{
		NetApiBufferFree(pServer);
		return FALSE;
		}

	USHORT sIndex;
	for (sIndex = 0; sIndex < dwEntriesRead; sIndex++)
		{
		if (!lpName.CompareNoCase(pMembers[sIndex].grui1_name)) 
			{
			NetApiBufferFree(pServer);
			return TRUE;
			}
		}

	while (dwResumeHandle != 0)
		{
		nApi = NetGroupGetUsers(pServer,
			lpGroupName,
			1,
			(LPBYTE*)&pMembers,
			5000,
			&dwEntriesRead,
			&dwTotalEntries, 
			&dwResumeHandle);

		if (nApi != ERROR_SUCCESS) 
			{
			NetApiBufferFree(pServer);
			return FALSE;
			}

		for (sIndex = 0; sIndex < dwEntriesRead; sIndex++)
			{
			if (!lpName.CompareNoCase(pMembers[sIndex].grui1_name)) 
				{
				NetApiBufferFree(pServer);
				return TRUE;
				}
			}
		}

	NetApiBufferFree(pServer);
	return FALSE;
}


void CWelcomeDlg::OnShowWindow(BOOL bShow, UINT nStatus) 
{
	CPropertyPage::OnShowWindow(bShow, nStatus);
	
	CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();

	if (bShow) pApp->m_cps1.SetWizardButtons(PSWIZB_NEXT);
	else pApp->m_cps1.SetWizardButtons(PSWIZB_BACK | PSWIZB_NEXT);
	
}