Windows2003-3790/base/remoteboot/admin/utils.cpp
2020-09-30 16:53:55 +02:00

1292 lines
33 KiB
C++

/************************************************************************
Copyright (c) Microsoft Corporation 1997-1999
All rights reserved
***************************************************************************/
//
// UTILS.CPP - Common non-class specific utility calls.
//
#include "pch.h"
#include <dsgetdc.h>
#include <lm.h>
#include "cenumsif.h"
#include "utils.h"
#include <dsadmin.h>
DEFINE_MODULE("IMADMUI")
#define SMALL_BUFFER_SIZE 256
#define OSVERSION_SIZE 30
#define IMAGETYPE_SIZE 30
#define FILTER_GUID_QUERY L"(&(objectClass=computer)(netbootGUID=%ws))"
WCHAR g_wszLDAPPrefix[] = L"LDAP://";
const LONG SIZEOF_g_wszLDAPPrefix = sizeof(g_wszLDAPPrefix);
//
// AddPagesEx()
//
// Creates and adds a property page.
//
HRESULT
AddPagesEx(
ITab ** pTab,
LPCREATEINST pfnCreateInstance,
LPFNADDPROPSHEETPAGE lpfnAddPage,
LPARAM lParam,
LPUNKNOWN punk )
{
TraceFunc( "AddPagesEx( ... )\n" );
HRESULT hr = S_OK;
ITab * lpv;
if ( pTab == NULL )
{
pTab = &lpv;
}
*pTab = (LPTAB) pfnCreateInstance( );
if ( !*pTab )
{
hr = E_OUTOFMEMORY;
goto Error;
}
hr = THR( (*pTab)->AddPages( lpfnAddPage, lParam, punk ) );
if (FAILED(hr)) {
goto Error;
}
Cleanup:
RETURN(hr);
Error:
if ( *pTab )
{
delete *pTab;
*pTab = NULL;
}
goto Cleanup;
}
//
// CheckClipboardFormats( )
//
HRESULT
CheckClipboardFormats( )
{
TraceFunc( "CheckClipboardFormats( )\n" );
HRESULT hr = S_OK;
if ( !g_cfDsObjectNames )
{
g_cfDsObjectNames = RegisterClipboardFormat( CFSTR_DSOBJECTNAMES );
if ( !g_cfDsObjectNames )
{
hr = E_FAIL;
}
}
if ( !g_cfDsDisplaySpecOptions && hr == S_OK )
{
g_cfDsDisplaySpecOptions = RegisterClipboardFormat( CFSTR_DS_DISPLAY_SPEC_OPTIONS );
if ( !g_cfDsDisplaySpecOptions )
{
hr = E_FAIL;
}
}
if ( !g_cfDsPropetyPageInfo && hr == S_OK )
{
g_cfDsPropetyPageInfo = RegisterClipboardFormat( CFSTR_DSPROPERTYPAGEINFO );
if ( !g_cfDsObjectNames )
{
hr = E_FAIL;
}
}
if ( !g_cfMMCGetNodeType && hr == S_OK )
{
g_cfMMCGetNodeType = RegisterClipboardFormat( CCF_NODETYPE );
if ( !g_cfMMCGetNodeType )
{
hr = E_FAIL;
}
}
RETURN(hr);
}
//
// DNtoFQDN( )
//
// Changes a MAO DN to and FQDN.
//
// Input: pszDN - string e.g cn=HP,cn=computers,dc=GPEASE,dc=DOM
//
// Output: *pszFQDN - LocalAlloc'ed string with the generated FQDN
//
HRESULT
DNtoFQDN(
IN LPWSTR pszDN,
OUT LPWSTR * pszFQDN )
{
TraceFunc( "DNtoFQDN( " );
TraceMsg( TF_FUNC, "pszDN = '%s', *pszFQDN = 0x%08x )\n", pszDN, (pszFQDN ? *pszFQDN : NULL) );
HRESULT hr = S_OK;
LPWSTR pszNext;
LPWSTR psz;
if (0 != StrCmpNI( pszDN, L"cn=", 3 ) ||
NULL == StrStrI( pszDN, L"dc=" )) {
Assert( pszDN ); // this shouldn't happen
hr = THR(E_INVALIDARG);
goto Error;
}
// skip the "cn=" and duplicate
*pszFQDN = (LPWSTR) TraceStrDup( &pszDN[3] );
if ( !*pszFQDN )
{
hr = THR(E_OUTOFMEMORY);
goto Error;
}
pszNext = *pszFQDN;
while ( pszNext && *pszNext )
{
psz = StrChr( pszNext, L',' );
if ( !psz ) {
break;
}
*psz = L'.';
pszNext = psz;
pszNext++;
psz = StrStrI( pszNext, L"dc=" );
Assert( psz ); // this shouldn't happen
if (!psz) {
break;
}
psz += 3;
StrCpy( pszNext, psz );
}
Error:
HRETURN(hr);
}
HRESULT
DNtoFQDNEx(
LPWSTR pszDN,
LPWSTR * pszFQDN )
/*++
Routine Description:
Given a DN for the RIS SCP, figure out the FQDN of the
RIS server. We do this by querying the DN for the
"dNSHostName" attribute. The caller can get the DN for the object
by reading the netbootserver attribute from the SCP.
Arguments:
pszDN - The server DN.
pszFQDN - receives the FQDN of the server. Must be freed via
TraceFree();
Return Value:
HRESULT indicating outcome.
--*/
{
PLDAP LdapHandle = NULL;
PWCHAR * Base;
DWORD LdapError;
DWORD entryCount;
HRESULT hresult = S_OK;
PLDAPMessage LdapMessage;
PWCHAR * DnsName;
PLDAPMessage CurrentEntry;
WCHAR Filter[128];
// Paramters we want from the Computer Object
PWCHAR ComputerAttrs[2];
//
// all we care about is the dNSHostName attribute.
//
ComputerAttrs[0] = &L"dNSHostName";
ComputerAttrs[1] = NULL;
//
// just computer objects
//
wsprintf( Filter, L"(objectClass=computer)" );
//
// initialize a valid ldap handle
//
LdapHandle = ldap_init( NULL, LDAP_PORT);
if (!LdapHandle ||
(LDAP_SUCCESS != ldap_connect(LdapHandle,0)) ||
(LDAP_SUCCESS != ldap_bind_s(LdapHandle, NULL, NULL, LDAP_AUTH_NEGOTIATE))) {
goto e0;
}
//
// search from the passed in DN.
//
LdapError = ldap_search_s(LdapHandle,
pszDN,
LDAP_SCOPE_BASE,
Filter,
ComputerAttrs,
FALSE,
&LdapMessage);
if ( LdapError != LDAP_SUCCESS ) {
hresult=E_FAIL;
goto e1;
}
// Did we get a Computer Object?
entryCount = ldap_count_entries( LdapHandle, LdapMessage );
if ( entryCount == 0 ) {
hresult=E_FAIL;
goto e1;
}
//
// we should really only get one hit, but... if we get more than more
// entry back, we will use only the first one.
//
CurrentEntry = ldap_first_entry( LdapHandle, LdapMessage );
//
// retreive the value.
//
DnsName = ldap_get_values( LdapHandle, CurrentEntry, L"dNSHostName");
if ( DnsName ) {
*pszFQDN = (LPWSTR) TraceStrDup( (LPWSTR)*DnsName );
if (!*pszFQDN) {
hresult=E_FAIL;
}
ldap_value_free( DnsName );
}
//
// cleanup and return
//
e1:
ldap_msgfree( LdapMessage );
e0:
if (LdapHandle) {
ldap_unbind_s(LdapHandle);
}
return(hresult);
}
HRESULT
GetDomainDN(
LPWSTR pszDN,
LPWSTR * pszDomainDn)
/*++
Routine Description:
Given a server name, we retrive the DN of the domain that machine
is in. This is done just by moving the the dc portion of the DN.
Arguments:
pszDN - the source DN
pszDomainDn - receives the domain DN. Must be freed via TraceFree().
Return Value:
HRESULT indicating outcome.
--*/
{
TraceFunc( "GetDomainDN( " );
TraceMsg( TF_FUNC, "pszDN = '%s', *pszFQDN = 0x%08x )\n", pszDN, (pszDomainDn ? *pszDomainDn : NULL) );
HRESULT hr = S_OK;
LPWSTR pszNext = StrStrI(pszDN, L"dc=");
if (pszNext) {
*pszDomainDn = (LPWSTR) TraceStrDup( pszNext );
if (!*pszDomainDn) {
hr = THR(E_OUTOFMEMORY);
}
} else {
hr = THR(E_INVALIDARG);
}
HRETURN(hr);
}
//
// PopulateListView( )
//
HRESULT
PopulateListView(
HWND hwndList,
IEnumIMSIFs * penum )
{
TraceFunc( "PopulateListView( ... )\n" );
HRESULT hr = S_OK;
INT iCount;
LV_ITEM lvI;
if ( !penum )
HRETURN(E_POINTER);
lvI.mask = LVIF_TEXT | LVIF_PARAM;
lvI.iSubItem = 0;
lvI.cchTextMax = REMOTE_INSTALL_MAX_DESCRIPTION_CHAR_COUNT;
ListView_DeleteAllItems( hwndList );
iCount = 0;
while ( hr == S_OK )
{
WIN32_FILE_ATTRIBUTE_DATA fda;
WCHAR szBuf[ MAX_PATH ];
LPSIFINFO pSIF;
LPWSTR pszFilePath;
LPWSTR pszBegin;
INT i; // general purpose
hr = penum->Next( 1, &pszFilePath, NULL );
if ( hr != S_OK )
{
if ( pszFilePath ) {
TraceFree( pszFilePath );
pszFilePath = NULL;
}
break; // abort
}
// Create private storage structure
pSIF = (LPSIFINFO) TraceAlloc( LPTR, sizeof(SIFINFO) );
if ( !pSIF )
{
if ( pszFilePath ) {
TraceFree( pszFilePath );
pszFilePath = NULL;
}
continue; // oh well, try again next OS
}
// Save this
pSIF->pszFilePath = pszFilePath;
// Get the description
pSIF->pszDescription = (LPWSTR) TraceAllocString( LMEM_FIXED, REMOTE_INSTALL_MAX_DESCRIPTION_CHAR_COUNT );
if ( !pSIF->pszDescription ) {
goto Cleanup;
}
GetPrivateProfileString( OSCHOOSER_SIF_SECTION,
OSCHOOSER_DESCRIPTION_ENTRY,
L"??",
pSIF->pszDescription,
REMOTE_INSTALL_MAX_DESCRIPTION_CHAR_COUNT, // doesn't need -1
pszFilePath );
// Grab any help text
pSIF->pszHelpText = (LPWSTR) TraceAllocString( LMEM_FIXED, REMOTE_INSTALL_MAX_HELPTEXT_CHAR_COUNT );
if ( !pSIF->pszHelpText ) {
goto Cleanup;
}
GetPrivateProfileString( OSCHOOSER_SIF_SECTION,
OSCHOOSER_HELPTEXT_ENTRY,
L"",
pSIF->pszHelpText,
REMOTE_INSTALL_MAX_HELPTEXT_CHAR_COUNT, // doesn't need -1
pszFilePath );
// Grab the OS Version
pSIF->pszVersion= (LPWSTR) TraceAllocString( LMEM_FIXED, OSVERSION_SIZE );
if ( !pSIF->pszVersion ) {
goto Cleanup;
}
GetPrivateProfileString( OSCHOOSER_SIF_SECTION,
OSCHOOSER_VERSION_ENTRY,
L"",
pSIF->pszVersion,
OSVERSION_SIZE,
pszFilePath );
// Grab the last modified Time/Date stamp
if ( GetFileAttributesEx( pszFilePath, GetFileExInfoStandard, &fda ) )
{
pSIF->ftLastWrite = fda.ftLastWriteTime;
} else {
ZeroMemory( &pSIF->ftLastWrite, sizeof(pSIF->ftLastWrite) );
}
// Figure out the language and architecture.
// These are retrieved from the FilePath.
// \\machine\REMINST\Setup\English\Images\nt50.wks\i386\templates\rbstndrd.sif
pszBegin = pSIF->pszFilePath;
for( i = 0; i < 5; i ++ )
{
pszBegin = StrChr( pszBegin, L'\\' );
if ( !pszBegin ) {
break;
}
pszBegin++;
}
if ( pszBegin )
{
LPWSTR pszEnd = StrChr( pszBegin, L'\\' );
if ( pszEnd ) {
*pszEnd = L'\0'; // terminate
//
// it's not fatal if we don't find this, but if we fail to
// allocate memory for it, it is fatal
//
pSIF->pszLanguage = (LPWSTR) TraceStrDup( pszBegin );
*pszEnd = L'\\'; // restore
if ( !pSIF->pszLanguage ) {
goto Cleanup;
}
}
}
Assert( pSIF->pszLanguage );
for( ; i < 7; i ++ )
{
pszBegin = StrChr( pszBegin, L'\\' );
if ( !pszBegin ) {
break;
}
pszBegin++;
}
if ( pszBegin )
{
LPWSTR pszEnd = StrChr( pszBegin, L'\\' );
if ( pszEnd )
{
*pszEnd = L'\0';
//
// it's not fatal if we don't find this, but if we fail to
// allocate memory for it, it is fatal
//
pSIF->pszDirectory = (LPWSTR) TraceStrDup( pszBegin );
*pszEnd = L'\\';
if ( !pSIF->pszDirectory ) {
goto Cleanup;
}
}
}
Assert( pSIF->pszDirectory );
for( ; i < 8; i ++ )
{
pszBegin = StrChr( pszBegin, L'\\' );
if ( !pszBegin ) {
break;
}
pszBegin++;
}
if ( pszBegin )
{
LPWSTR pszEnd = StrChr( pszBegin, L'\\' );
if ( pszEnd )
{
*pszEnd = L'\0';
//
// it's not fatal if we don't find this, but if we fail to
// allocate memory for it, it is fatal
//
pSIF->pszArchitecture = (LPWSTR) TraceStrDup( pszBegin );
*pszEnd = L'\\';
if ( !pSIF->pszArchitecture ) {
goto Cleanup;
}
}
}
// Figure out what kind of image it is
pSIF->pszImageType = (LPWSTR) TraceAllocString( LMEM_FIXED, IMAGETYPE_SIZE );
if ( !pSIF->pszImageType ) {
goto Cleanup;
}
GetPrivateProfileString( OSCHOOSER_SIF_SECTION,
OSCHOOSER_IMAGETYPE_ENTRY,
L"??",
pSIF->pszImageType,
IMAGETYPE_SIZE,
pszFilePath );
// Figure out what image it uses
GetPrivateProfileString( OSCHOOSER_SIF_SECTION,
OSCHOOSER_LAUNCHFILE_ENTRY,
L"??",
szBuf,
ARRAYSIZE( szBuf ),
pszFilePath );
pszBegin = StrRChr( szBuf, &szBuf[wcslen(szBuf)], L'\\' );
if ( pszBegin )
{
pszBegin++;
pSIF->pszImageFile = (LPWSTR) TraceStrDup( pszBegin );
if (!pSIF->pszImageFile) {
goto Cleanup;
}
}
// Add the item to list view
lvI.lParam = (LPARAM) pSIF;
lvI.iItem = iCount;
lvI.pszText = pSIF->pszDescription;
iCount = ListView_InsertItem( hwndList, &lvI );
Assert( iCount != -1 );
if ( iCount == -1 )
goto Cleanup;
if ( pSIF->pszArchitecture )
{
ListView_SetItemText( hwndList, iCount, 1, pSIF->pszArchitecture );
}
if ( pSIF->pszLanguage )
{
ListView_SetItemText( hwndList, iCount, 2, pSIF->pszLanguage );
}
if ( pSIF->pszVersion )
{
ListView_SetItemText( hwndList, iCount, 3, pSIF->pszVersion );
}
continue; // next!
Cleanup:
if ( pSIF )
{
if (pSIF->pszDescription != NULL) {
TraceFree( pSIF->pszDescription );
pSIF->pszDescription = NULL;
}
TraceFree( pSIF->pszFilePath );
pSIF->pszFilePath = NULL;
if (pSIF->pszHelpText != NULL) {
TraceFree( pSIF->pszHelpText );
pSIF->pszHelpText = NULL;
}
if (pSIF->pszImageType != NULL) {
TraceFree( pSIF->pszImageType );
pSIF->pszImageType = NULL;
}
TraceFree( pSIF->pszLanguage );
pSIF->pszLanguage = NULL;
if (pSIF->pszVersion != NULL) {
TraceFree( pSIF->pszVersion );
pSIF->pszVersion = NULL;
}
if (pSIF->pszImageFile) {
TraceFree( pSIF->pszImageFile );
pSIF->pszImageFile = NULL;
}
TraceFree( pSIF );
pSIF = NULL;
}
}
HRETURN(hr);
}
//
// LDAPPrefix( )
//
// Returns:
// E_OUTOFMEMORY - if out of memory
// S_OK - added LDAP:// to the pszObjDN
// S_FALSE - didn't have to add anything and copied the pszObjDN
// into ppszObjLDAPPath
HRESULT
LDAPPrefix(
PWSTR pszObjDN,
PWSTR * ppszObjLDAPPath)
{
TraceFunc( "LDAPPrefix( ... )\n" );
HRESULT hr;
const ULONG cchPrefix = ARRAYSIZE(g_wszLDAPPrefix) - 1;
ULONG cch = wcslen(pszObjDN);
if (wcsncmp(pszObjDN, g_wszLDAPPrefix, cchPrefix))
{
LPWSTR psz;
psz = (LPWSTR) TraceAllocString( LPTR, cch + cchPrefix + 1 );
if ( !psz ) {
hr = E_OUTOFMEMORY;
goto Error;
}
wcscpy(psz, g_wszLDAPPrefix);
wcscat(psz, pszObjDN);
*ppszObjLDAPPath = psz;
hr = S_OK;
}
else
{
*ppszObjLDAPPath = pszObjDN;
hr = S_FALSE;
}
Error:
HRETURN(hr);
}
//
// _FixObjectPath( )
//
HRESULT
FixObjectPath(
LPWSTR Object,
LPWSTR pszOldObjectPath,
LPWSTR *ppszNewObjectPath )
{
TraceFunc( "FixObjectPath()\n" );
HRESULT hr;
LPWSTR psz = NULL;
*ppszNewObjectPath = NULL;
// Try to parse the string to connect to the same server as the DSADMIN
if ( Object && StrCmpNI( Object, L"LDAP://", 7 ) == 0 )
{
psz = Object + 7;
}
else if ( Object && StrCmpNI( Object, L"GC://", 5 ) == 0 )
{
psz = Object + 5;
}
if ( psz )
{
psz = StrChr( psz, L'/' );
psz++;
INT_PTR uLen = psz - Object;
// get a chunk of memory, pre-zero'ed
psz = TraceAllocString( LPTR, (size_t) uLen + wcslen( pszOldObjectPath ) + 1 );
if ( !psz ) {
hr = E_OUTOFMEMORY;
goto Exit;
}
MoveMemory( psz, Object, uLen * sizeof(WCHAR) );
wcscat( psz, pszOldObjectPath);
*ppszNewObjectPath = psz;
}
else
{ // find another server
hr = THR( LDAPPrefix( pszOldObjectPath, ppszNewObjectPath ) );
}
Assert( ppszNewObjectPath || hr != S_OK );
Exit:
HRETURN(hr);
}
//
// Create a message box from resource strings.
//
int
MessageBoxFromStrings(
HWND hParent,
UINT idsCaption,
UINT idsText,
UINT uType )
{
WCHAR szText[ SMALL_BUFFER_SIZE * 2 ];
WCHAR szCaption[ SMALL_BUFFER_SIZE ];
DWORD dw;
szCaption[0] = L'\0';
szText[0] = L'\0';
dw = LoadString( g_hInstance, idsCaption, szCaption, ARRAYSIZE(szCaption) );
Assert( dw );
dw = LoadString( g_hInstance, idsText, szText, ARRAYSIZE(szText));
Assert( dw );
return MessageBox( hParent, szText, szCaption, uType );
}
//
// MessageBoxFromError( )
//
// Creates a error message box
//
void
MessageBoxFromError(
HWND hParent,
UINT idsCaption,
DWORD dwErr )
{
WCHAR szTitle[ SMALL_BUFFER_SIZE ];
LPWSTR lpMsgBuf = NULL;
DWORD dw;
if ( dwErr == ERROR_SUCCESS ) {
AssertMsg( dwErr, "Why was MessageBoxFromError() called when the dwErr == ERROR_SUCCES?" );
return;
}
if ( !idsCaption ) {
idsCaption = IDS_ERROR;
}
szTitle[0] = L'\0';
dw = LoadString( g_hInstance, idsCaption, szTitle, ARRAYSIZE(szTitle) );
Assert( dw );
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dwErr,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPWSTR) &lpMsgBuf,
0,
NULL
);
if (lpMsgBuf == NULL) {
AssertMsg( (lpMsgBuf != NULL), "MessageBoxFromError() called with unknown message." );
return;
}
MessageBox( hParent, lpMsgBuf, szTitle, MB_OK | MB_ICONERROR );
LocalFree( lpMsgBuf );
}
//
// MessageBoxFromError( )
//
// Creates a error message box
//
void
MessageBoxFromHResult(
HWND hParent,
UINT idsCaption,
HRESULT hr )
{
WCHAR szTitle[ SMALL_BUFFER_SIZE ];
LPWSTR lpMsgBuf = NULL;
DWORD dw;
if ( SUCCEEDED( hr ) ) {
AssertMsg( SUCCEEDED( hr ), "Why was MessageBoxFromHResult() called when the HR succeeded?" );
return;
}
if ( !idsCaption ) {
idsCaption = IDS_ERROR;
}
szTitle[0] = L'\0';
dw = LoadString( g_hInstance, idsCaption, szTitle, ARRAYSIZE(szTitle) );
Assert( dw );
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
hr,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPWSTR) &lpMsgBuf,
0,
NULL
);
if (lpMsgBuf == NULL) {
AssertMsg( (lpMsgBuf != NULL), "MessageBoxFromHResult() called with unknown message." );
return;
}
MessageBox( hParent, lpMsgBuf, szTitle, MB_OK | MB_ICONERROR );
LocalFree( lpMsgBuf );
}
//
// VerifySIFText( )
//
BOOL
VerifySIFText(
LPWSTR pszText )
{
TraceFunc( "VerifySIFText()\n" );
BOOL fReturn = FALSE;
while ( *pszText >= 32 && *pszText < 128 ) {
pszText++;
}
if ( *pszText == L'\0' )
{
fReturn = TRUE;
}
RETURN(fReturn);
}
//bugbug is this compiled or not?
#ifndef ADSI_DNS_SEARCH
//
// Ldap_InitializeConnection( )
//
DWORD
Ldap_InitializeConnection(
PLDAP * LdapHandle )
{
TraceFunc( "Ldap_InitializeConnection( ... )\n" );
PLDAPMessage OperationalAttributeLdapMessage;
PLDAPMessage CurrentEntry;
DWORD LdapError = LDAP_SUCCESS;
if ( !( *LdapHandle ) ) {
ULONG temp = DS_DIRECTORY_SERVICE_REQUIRED |
DS_IP_REQUIRED |
DS_GC_SERVER_REQUIRED;
*LdapHandle = ldap_init( NULL, LDAP_GC_PORT);
if ( !*LdapHandle )
{
LdapError = LDAP_UNAVAILABLE;
goto e0;
}
ldap_set_option( *LdapHandle, LDAP_OPT_GETDSNAME_FLAGS, &temp );
temp = LDAP_VERSION3;
ldap_set_option( *LdapHandle, LDAP_OPT_VERSION, &temp );
LdapError = ldap_connect( *LdapHandle, 0 );
if ( LdapError != LDAP_SUCCESS )
goto e1;
LdapError = ldap_bind_s( *LdapHandle, NULL, NULL, LDAP_AUTH_SSPI );
if ( LdapError != LDAP_SUCCESS )
goto e1;
}
e0:
RETURN( LdapError );
e1:
ldap_unbind( *LdapHandle );
*LdapHandle = NULL;
goto e0;
}
#endif // ADSI_DNS_SEARCH
//
// ValidateGuid( )
//
// Returns: S_OK if a complete, valid GUID is in pszGuid.
// S_FALSE if an valid but incomplete GUID is in pszGuid. "Valid but
// incomplete" is defined below.
// E_FAIL if an invalid character is encountered while parsing.
//
// Valid characters are 0-9, A-F, a-f and "{-}"s. All spaces are ignored.
// The GUID must appear in one of the following forms:
//
// 1. 00112233445566778899aabbccddeeff
// This corresponds to the actual in-memory storage order of a GUID.
// For example, it is the order in which GUID bytes appear in a
// network trace.
//
// 2. {33221100-5544-7766-8899-aabbccddeeff}
// This corresponds to the "standard" way of printing GUIDs. Note
// that the "pretty" GUID shown here is the same as the GUID shown
// above.
//
// Note that the DEFINE_GUID macro (see sdk\inc\objbase.h) for the above
// GUID would look like this:
// DEFINE_GUID(name,0x33221100,0x5544,0x7766,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff)
//
// "Valid but incomplete" means that the input consists of an even number
// of hex characters (no lone nibbles), and if the input is in "pretty"
// format, the input must terminate at one of the dashes or after the
// second-to-the-last dash.
//
// The following are valid but incomplete entries:
// 001122
// {33221100
// {33221100-5544
// {33221100-5544-7766-88
//
// The following are invalid incomplete entries:
// 00112
// {332211
// {33221100-5544-77
//
//
// In the xxxGuidCharacters arrays, values [0,31] indicate nibble positions within
// the in-memory representation of the GUID. Value 32 indicates the end of the
// GUID string. Values 33 and up indicate special characters (nul,'-','{','}') and
// are used to index into an array containing those characters.
//
#define VG_DONE 32
#define VG_NULL 33
#define VG_DASH 34
#define VG_LBRACK 35
#define VG_RBRACK 36
CHAR InMemoryFormatGuidCharacters[] = {
1, 0, 3, 2, 5, 4, 7, 6,
9, 8, 11, 10, 13, 12, 15, 14,
17, 16, 19, 18, 21, 20, 23, 22,
25, 24, 27, 26, 29, 28, 31, 30,
VG_NULL, VG_DONE };
CHAR PrettyFormatGuidCharacters[] = {
VG_LBRACK, 7, 6, 5, 4, 3, 2, 1,
0, VG_DASH, 11, 10, 9, 8, VG_DASH, 15,
14, 13, 12, VG_DASH, 17, 16, 19, 18,
VG_DASH, 21, 20, 23, 22, 25, 24, 27,
26, 29, 28, 31, 30, VG_RBRACK, VG_NULL, VG_DONE };
WCHAR SpecialCharacters[] = {
0, // VG_NULL
L'-', // VG_DASH
L'{', // VG_LBRACK
L'}', // VG_RBRACK
};
PWSTR ByteToHex = L"0123456789ABCDEF";
HRESULT
ValidateGuid(
IN LPWSTR pszGuid,
OUT LPGUID Guid OPTIONAL,
OUT LPDWORD puGuidLength OPTIONAL )
{
TraceFunc( "ValidateGuid( " );
TraceMsg( TF_FUNC, "pszGuid = '%s'\n", pszGuid );
HRESULT hr;
LPBYTE uGuid = (LPBYTE)Guid;
PCHAR expectedCharacter;
CHAR e;
WCHAR g;
BOOL parsingPrettyFormat;
DWORD numberOfHexDigitsParsed;
#ifdef DEBUG
if ( uGuid != NULL ) {
for ( e = 0; e < 16; e++ ) {
uGuid[e] = 0;
}
}
#endif
if ( *pszGuid == L'{' ) {
expectedCharacter = PrettyFormatGuidCharacters;
parsingPrettyFormat = TRUE;
} else {
expectedCharacter = InMemoryFormatGuidCharacters;
parsingPrettyFormat = FALSE;
}
numberOfHexDigitsParsed = 0;
do {
e = *expectedCharacter++;
do {
g = *pszGuid++;
} while (iswspace(g));
switch ( e ) {
case VG_NULL:
case VG_DASH:
case VG_LBRACK:
case VG_RBRACK:
if ( g != SpecialCharacters[e - VG_NULL] ) {
if ( g == 0 ) {
// valid but incomplete
hr = S_FALSE;
} else {
hr = E_FAIL;
}
goto done;
}
break;
default:
Assert( (e >= 0) && (e < VG_DONE) );
g = towlower( g );
if ( ((g >= L'0') && (g <= L'9')) ||
((g >= L'a') && (g <= L'f')) ) {
if ( uGuid != NULL ) {
BYTE n = (BYTE)((g > L'9') ? (g - L'a' + 10) : (g - '0'));
if ( e & 1 ) {
Assert( uGuid[e/2] == 0 );
uGuid[e/2] = n << 4;
} else {
uGuid[e/2] += n;
}
}
numberOfHexDigitsParsed++;
} else {
if ( (g == 0) &&
(!parsingPrettyFormat ||
(parsingPrettyFormat && (numberOfHexDigitsParsed >= 16))) ) {
hr = S_FALSE;
} else {
hr = E_FAIL;
}
goto done;
}
break;
}
} while ( *expectedCharacter != VG_DONE );
hr = S_OK;
done:
if ( puGuidLength != NULL ) {
*puGuidLength = numberOfHexDigitsParsed / 2;
}
HRETURN(hr);
}
//
// PrettyPrintGuid( )
//
LPWSTR
PrettyPrintGuid(
LPGUID pGuid )
{
TraceFunc( "PrettyPrintGuid( " );
LPBYTE uGuid = (LPBYTE)pGuid;
LPWSTR pszPrettyString = (LPWSTR) TraceAlloc( LMEM_FIXED, PRETTY_GUID_STRING_BUFFER_SIZE );
if ( pszPrettyString )
{
PCHAR characterType = PrettyFormatGuidCharacters;
LPWSTR pszDest = pszPrettyString;
CHAR ct;
BYTE n;
do {
ct = *characterType++;
switch ( ct ) {
case VG_NULL:
case VG_DASH:
case VG_LBRACK:
case VG_RBRACK:
*pszDest = SpecialCharacters[ct - VG_NULL];
break;
default:
if ( ct & 1 ) {
n = uGuid[ct/2] >> 4;
} else {
n = uGuid[ct/2] & 0xf;
}
*pszDest = ByteToHex[n];
break;
}
pszDest++;
} while ( *characterType != VG_DONE );
}
RETURN(pszPrettyString);
}
//
// CheckForDuplicateGuid( )
//
// Returns: S_OK if no duplicates found
// S_FALSE if a duplicate was found
// E_FAIL if the query failed
//
HRESULT
CheckForDuplicateGuid(
LPGUID pGuid )
{
TraceFunc( "CheckForDuplicateGuid( " );
HRESULT hr = S_OK;
WCHAR szGuid[ MAX_INPUT_GUID_STRING * 2 ]; // room for escaped GUID
WCHAR szFilter[ARRAYSIZE(szGuid)+ARRAYSIZE(FILTER_GUID_QUERY)];
PLDAP LdapHandle = NULL;
LPWSTR ComputerAttrs[2];
DWORD LdapError;
DWORD count;
PLDAPMessage LdapMessage = NULL;
LdapError = Ldap_InitializeConnection( &LdapHandle );
Assert( LdapError == LDAP_SUCCESS );
if ( LdapError != LDAP_SUCCESS )
{
hr = THR( HRESULT_FROM_WIN32( LdapMapErrorToWin32( LdapError ) ) );
goto e0;
}
ZeroMemory( szGuid, sizeof(szGuid) );
ldap_escape_filter_element( (PCHAR)pGuid, sizeof(GUID), szGuid, sizeof(szGuid) );
wsprintf( szFilter, FILTER_GUID_QUERY, szGuid );
DebugMsg( "Dup Guid Filter: %s\n", szFilter );
ComputerAttrs[0] = DISTINGUISHEDNAME;
ComputerAttrs[1] = NULL;
LdapError = ldap_search_ext_s( LdapHandle,
NULL,
LDAP_SCOPE_SUBTREE,
szFilter,
ComputerAttrs,
FALSE,
NULL,
NULL,
NULL,
0,
&LdapMessage);
Assert( LdapError == LDAP_SUCCESS );
if ( LdapError != LDAP_SUCCESS )
{
hr = THR( HRESULT_FROM_WIN32( LdapMapErrorToWin32( LdapError ) ) );
goto e1;
}
count = ldap_count_entries( LdapHandle, LdapMessage );
if ( count != 0 )
{
hr = S_FALSE;
}
else
{
hr = S_OK;
}
e1:
if (LdapMessage) {
ldap_msgfree( LdapMessage );
}
Assert( LdapHandle );
ldap_unbind( LdapHandle );
e0:
HRETURN(hr);
}
//
// AddWizardPage( )
//
// Adds a page to the wizard.
//
void
AddWizardPage(
LPPROPSHEETHEADER ppsh,
UINT id,
DLGPROC pfn,
UINT idTitle,
UINT idSubtitle,
LPARAM lParam )
{
PROPSHEETPAGE psp;
WCHAR szTitle[ SMALL_BUFFER_SIZE ];
WCHAR szSubTitle[ SMALL_BUFFER_SIZE ];
ZeroMemory( &psp, sizeof(psp) );
psp.dwSize = sizeof(psp);
psp.dwFlags = PSP_DEFAULT | PSP_USETITLE;
psp.pszTitle = MAKEINTRESOURCE( IDS_ADD_DOT_DOT_DOT );
psp.hInstance = ppsh->hInstance;
psp.pszTemplate = MAKEINTRESOURCE(id);
psp.pfnDlgProc = pfn;
psp.lParam = lParam;
psp.pszHeaderTitle = NULL;
if ( idTitle &&
LoadString( g_hInstance, idTitle, szTitle, ARRAYSIZE(szTitle))) {
psp.pszHeaderTitle = szTitle;
psp.dwFlags |= PSP_USEHEADERTITLE;
}
psp.pszHeaderSubTitle = NULL;
if ( idSubtitle &&
LoadString( g_hInstance, idSubtitle , szSubTitle, ARRAYSIZE(szSubTitle))) {
psp.pszHeaderSubTitle = szSubTitle;
psp.dwFlags |= PSP_USEHEADERSUBTITLE;
}
ppsh->phpage[ ppsh->nPages ] = CreatePropertySheetPage( &psp );
if ( ppsh->phpage[ ppsh->nPages ] ) {
ppsh->nPages++;
}
}