windows-nt/Source/XPSP1/NT/base/cluster/service/nm/nmfixup.c

800 lines
22 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1996-1999 Microsoft Corporation
Module Name:
node.c
Abstract:
Fix up Routines for Upgrade and Rolling Upgrades
Author:
Sunita Shrivastava(sunitas) 18-Mar-1998
Revision History:
--*/
/****
@doc EXTERNAL INTERFACES CLUSSVC DM
****/
#define UNICODE 1
#include "nmp.h"
//
// Cluster registry API function pointers.
//
CLUSTER_REG_APIS
NmpFixupRegApis = {
(PFNCLRTLCREATEKEY) DmRtlCreateKey,
(PFNCLRTLOPENKEY) DmRtlOpenKey,
(PFNCLRTLCLOSEKEY) DmCloseKey,
(PFNCLRTLSETVALUE) DmSetValue,
(PFNCLRTLQUERYVALUE) DmQueryValue,
(PFNCLRTLENUMVALUE) DmEnumValue,
(PFNCLRTLDELETEVALUE) DmDeleteValue,
(PFNCLRTLLOCALCREATEKEY) DmRtlLocalCreateKey,
(PFNCLRTLLOCALSETVALUE) DmLocalSetValue,
(PFNCLRTLLOCALDELETEVALUE) DmLocalDeleteValue,
};
//
// Data
//
RESUTIL_PROPERTY_ITEM
NmJoinFixupSDProperties[]=
{
{
CLUSREG_NAME_CLUS_SD, NULL, CLUSPROP_FORMAT_BINARY,
0, 0, 0,
0,
0
},
{
0
}
};
// Fixup Table for WINS
RESUTIL_PROPERTY_ITEM
NmJoinFixupWINSProperties[]=
{
{
CLUSREG_NAME_RESTYPE_IS_ALIVE, CLUS_RESTYPE_NAME_WINS , CLUSPROP_FORMAT_DWORD,
0,CLUSTER_RESTYPE_MINIMUM_IS_ALIVE ,CLUSTER_RESTYPE_MAXIMUM_IS_ALIVE ,
0,
0
},
{
CLUSREG_NAME_RESTYPE_LOOKS_ALIVE,CLUS_RESTYPE_NAME_WINS ,CLUSPROP_FORMAT_DWORD,
0,CLUSTER_RESTYPE_MINIMUM_LOOKS_ALIVE ,CLUSTER_RESTYPE_MAXIMUM_LOOKS_ALIVE ,
0,
sizeof(DWORD)
},
{
CLUSREG_NAME_RESTYPE_DLL_NAME,CLUS_RESTYPE_NAME_WINS ,CLUSPROP_FORMAT_SZ,
0,0,0,
0,
2*sizeof(DWORD)
},
{
CLUSREG_NAME_RESTYPE_NAME,CLUS_RESTYPE_NAME_WINS ,CLUSPROP_FORMAT_SZ,
0,0,0,
0,
2*sizeof(DWORD)+sizeof(LPWSTR*)
},
{
CLUSREG_NAME_RESTYPE_ADMIN_EXTENSIONS,CLUS_RESTYPE_NAME_WINS,CLUSPROP_FORMAT_MULTI_SZ,
0,0,0,
0,
2*sizeof(DWORD)+2*sizeof(LPWSTR*)
},
{
0
}
}; //NmJoinFixupWINSProperties
//Fixup Table for DHCP
RESUTIL_PROPERTY_ITEM
NmJoinFixupDHCPProperties[]=
{
{
CLUSREG_NAME_RESTYPE_IS_ALIVE, CLUS_RESTYPE_NAME_DHCP , CLUSPROP_FORMAT_DWORD,
0,CLUSTER_RESTYPE_MINIMUM_IS_ALIVE ,CLUSTER_RESTYPE_MAXIMUM_IS_ALIVE ,
0,
0
},
{
CLUSREG_NAME_RESTYPE_LOOKS_ALIVE,CLUS_RESTYPE_NAME_DHCP ,CLUSPROP_FORMAT_DWORD,
0,CLUSTER_RESTYPE_MINIMUM_LOOKS_ALIVE ,CLUSTER_RESTYPE_MAXIMUM_LOOKS_ALIVE ,
0,
sizeof(DWORD)
},
{
CLUSREG_NAME_RESTYPE_DLL_NAME,CLUS_RESTYPE_NAME_DHCP ,CLUSPROP_FORMAT_SZ,
0,0,0,
0,
2*sizeof(DWORD)
},
{
CLUSREG_NAME_RESTYPE_NAME,CLUS_RESTYPE_NAME_DHCP ,CLUSPROP_FORMAT_SZ,
0,0,0,
0,
2*sizeof(DWORD)+sizeof(LPWSTR*)
},
{
CLUSREG_NAME_RESTYPE_ADMIN_EXTENSIONS,CLUS_RESTYPE_NAME_DHCP,CLUSPROP_FORMAT_MULTI_SZ,
0,0,0,
0,
2*sizeof(DWORD)+2*sizeof(LPWSTR*)
},
{
0
}
};//NmJoinFixupDHCPProperties
RESUTIL_PROPERTY_ITEM
NmJoinFixupNewMSMQProperties[]=
{
{
CLUSREG_NAME_RESTYPE_IS_ALIVE, CLUS_RESTYPE_NAME_NEW_MSMQ,CLUSPROP_FORMAT_DWORD,
0,CLUSTER_RESTYPE_MINIMUM_IS_ALIVE ,CLUSTER_RESTYPE_MAXIMUM_IS_ALIVE ,
0,
0
},
{
CLUSREG_NAME_RESTYPE_LOOKS_ALIVE,CLUS_RESTYPE_NAME_NEW_MSMQ,CLUSPROP_FORMAT_DWORD,
0,CLUSTER_RESTYPE_MINIMUM_LOOKS_ALIVE ,CLUSTER_RESTYPE_MAXIMUM_LOOKS_ALIVE ,
0,
sizeof(DWORD)
},
{
CLUSREG_NAME_RESTYPE_DLL_NAME,CLUS_RESTYPE_NAME_NEW_MSMQ,CLUSPROP_FORMAT_SZ,
0,0,0,
0,
2*sizeof(DWORD)
},
{
CLUSREG_NAME_RESTYPE_NAME,CLUS_RESTYPE_NAME_NEW_MSMQ,CLUSPROP_FORMAT_SZ,
0,0,0,
0,
2*sizeof(DWORD)+sizeof(LPWSTR*)
},
{
0
}
};//NmJoinFixupNewMSMQProperties
//Fixup Table for changing thr dl name of MSDTC resource type
RESUTIL_PROPERTY_ITEM
NmJoinFixupMSDTCProperties[]=
{
{
CLUSREG_NAME_RESTYPE_DLL_NAME,CLUS_RESTYPE_NAME_MSDTC,CLUSPROP_FORMAT_SZ,
0,0,0,
0,
0
},
{
0
}
};//NmJoinFixupMSDTCProperties
//Fixup table for node version info
RESUTIL_PROPERTY_ITEM
NmFixupVersionInfo[]=
{
{
CLUSREG_NAME_NODE_MAJOR_VERSION,NULL,CLUSPROP_FORMAT_DWORD,
0,0,((DWORD)-1),
0,
0
},
{
CLUSREG_NAME_NODE_MINOR_VERSION,NULL,CLUSPROP_FORMAT_DWORD,
0,0,((DWORD)-1),
0,
sizeof(DWORD)
},
{
CLUSREG_NAME_NODE_BUILD_NUMBER,NULL,CLUSPROP_FORMAT_DWORD,
0,0,((DWORD)-1),
0,
2*sizeof(DWORD)
},
{
CLUSREG_NAME_NODE_CSDVERSION,NULL,CLUSPROP_FORMAT_SZ,
0,0,0,
0,
3*sizeof(DWORD)
},
{
CLUSREG_NAME_NODE_PRODUCT_SUITE,NULL,CLUSPROP_FORMAT_DWORD,
0,0,((DWORD)-1),
0,
3*sizeof(DWORD) + sizeof(LPWSTR*)
},
{
0
}
}; //NmFixupVersionInfo
RESUTIL_PROPERTY_ITEM
NmFixupClusterProperties[] =
{
{
CLUSREG_NAME_ADMIN_EXT, NULL, CLUSPROP_FORMAT_MULTI_SZ,
0, 0, 0,
0,
0
},
{
0
}
};
//Used by NmUpdatePerformFixups update
RESUTIL_PROPERTY_ITEM
NmpJoinFixupProperties[] =
{
{
CLUSREG_NAME_CLUS_SD, NULL, CLUSPROP_FORMAT_BINARY,
0, 0, 0,
0,
0
},
{
0
}
};
RESUTIL_PROPERTY_ITEM
NmpFormFixupProperties[] =
{
{
CLUSREG_NAME_CLUS_SD, NULL, CLUSPROP_FORMAT_BINARY,
0, 0, 0,
0,
0
},
{
0
}
};
NM_FIXUP_CB_RECORD FixupTable[]=
{
{ ApiFixupNotifyCb, NM_FORM_FIXUP|NM_JOIN_FIXUP}
};
// Fixup Table used for NmUpdatePerformFixups2 update type
NM_FIXUP_CB_RECORD2 FixupTable2[]=
{
{ ApiFixupNotifyCb, NM_FORM_FIXUP|NM_JOIN_FIXUP, NmpJoinFixupProperties},
{ FmBuildWINS, NM_FORM_FIXUP|NM_JOIN_FIXUP, NmJoinFixupWINSProperties,},
{ FmBuildDHCP, NM_FORM_FIXUP|NM_JOIN_FIXUP, NmJoinFixupDHCPProperties},
{ FmBuildNewMSMQ, NM_FORM_FIXUP|NM_JOIN_FIXUP, NmJoinFixupNewMSMQProperties},
{ FmBuildMSDTC, NM_FORM_FIXUP|NM_JOIN_FIXUP, NmJoinFixupMSDTCProperties},
{ NmpBuildVersionInfo, NM_JOIN_FIXUP|NM_FORM_FIXUP, NmFixupVersionInfo},
{ FmBuildClusterProp, NM_FORM_FIXUP|NM_JOIN_FIXUP,NmFixupClusterProperties}
};
NM_POST_FIXUP_CB PostFixupCbTable[]=
{
NULL,
FmFixupNotifyCb,
FmFixupNotifyCb,
FmFixupNotifyCb,
FmFixupNotifyCb,
NmFixupNotifyCb,
NULL
};
/****
@func DWORD | NmPerformFixups| This is called when a cluster is being
formed/or joining. Issues NmUpdateperforfixups GUM update
for registry fixups of SECURITY_DESCRIPTOR when NT5 node joins
NT4 node.Also issues NmUpdateperforfixups2 GUM update for
WINS and DHCP fixups when NT5 joins NT4. This update type can
be extended in future to do more fixups for postNT5 and NT5 scenario.
If later it is guaranteed that there is no NT4 node in cluster,
NmUpdatePerformFixups update type won't be needed and hence can
be taken out.
@comm The first time the cluster service forms a cluster after an
upgrade, it might have registry fixups it wants to make to the
existing cluster registry. Also, when an uplevel node
joins a downlevel node, join fixups can be performed.
Note that this is called on every form/join
@rdesc Returns a result code. ERROR_SUCCESS on success.
@xref <f NmpUpdatePerformFixups> <f NmpUpdatePerformFixups2>
****/
DWORD NmPerformFixups(
IN DWORD dwFixupType)
{
DWORD dwCount = sizeof(FixupTable)/sizeof(NM_FIXUP_CB_RECORD);
DWORD dwStatus = ERROR_SUCCESS;
PNM_FIXUP_CB_RECORD pFixupCbRec;
PNM_FIXUP_CB_RECORD2 pFixupCbRec2;
PVOID pPropertyList = NULL;
DWORD dwPropertyListSize;
DWORD i,j;
DWORD dwSize;
DWORD Required;
LPWSTR szKeyName=NULL;
LPBYTE pBuffer=NULL;
PRESUTIL_PROPERTY_ITEM pPropertyItem;
ClRtlLogPrint(LOG_NOISE,"[NM] NmPerformFixups Entry, dwFixupType=%1!u!\r\n",
dwFixupType);
// using old gum update handler - this is needed to maintain compataility
// with NT4, can be discarded later. See comments above.
//
for (i=0; i < dwCount ; i++)
{
pFixupCbRec = &FixupTable[i];
//if this fixup doesnt need to be applied, skip it
if (!(pFixupCbRec->dwFixupMask & dwFixupType))
continue;
dwStatus = (pFixupCbRec->pfnFixupNotifyCb)(dwFixupType, &pPropertyList,
&dwPropertyListSize,&szKeyName);
if (dwStatus != ERROR_SUCCESS)
{
goto FnExit;
}
if (pPropertyList && dwPropertyListSize)
{
//
// Issue a global update
//
dwStatus = GumSendUpdateEx(
GumUpdateMembership,
NmUpdatePerformFixups,
2,
dwPropertyListSize,
pPropertyList,
sizeof(DWORD),
&dwPropertyListSize
);
LocalFree(pPropertyList);
pPropertyList = NULL;
if(szKeyName)
{
LocalFree(szKeyName);
szKeyName=NULL;
}
}
if (dwStatus != ERROR_SUCCESS)
goto FnExit;
}
// Rohit (rjain): introduced new update type to fix the registry and
// in-memory structures after a node with a higher version of clustering
// service joins a node with a lower version. To make it extensible in future
// all the information needed for a fixup is passed as arguments to the fixup
// function. Any new fix can be added by adding suitable record to FixupTable2 and
// a postfixup function callback to PostfixupCbTable.
dwCount= sizeof(FixupTable2)/sizeof(NM_FIXUP_CB_RECORD2);
for (i=0; i < dwCount ; i++)
{
pFixupCbRec2 = &FixupTable2[i];
//if this fixup doesnt need to be applied, skip it
if (!(pFixupCbRec2->dwFixupMask & dwFixupType))
continue;
dwStatus = (pFixupCbRec2->pfnFixupNotifyCb)(dwFixupType, &pPropertyList,
&dwPropertyListSize,&szKeyName);
if (dwStatus != ERROR_SUCCESS)
{
goto FnExit;
}
if (pPropertyList && dwPropertyListSize)
{
// Marshall PropertyTable into byte array
Required=sizeof(DWORD);
AllocMem:
pBuffer=(LPBYTE)LocalAlloc(LMEM_FIXED,Required);
if (pBuffer==NULL)
{
dwStatus=GetLastError();
goto FnExit;
}
dwSize=Required;
dwStatus=ClRtlMarshallPropertyTable(pFixupCbRec2->pPropertyTable,dwSize,pBuffer,&Required);
if(dwStatus!= ERROR_SUCCESS)
{
LocalFree(pBuffer);
pBuffer=NULL;
// ClRtlLogPrint(LOG_NOISE,"[NM] NmPerformFixups - Memory Required=%1!u!\r\n",
// Required);
goto AllocMem;
}
//
// Issue a global update
//
dwStatus = GumSendUpdateEx(
GumUpdateMembership,
NmUpdatePerformFixups2,
5,
dwPropertyListSize,
pPropertyList,
sizeof(DWORD),
&dwPropertyListSize,
sizeof(DWORD),
&i,
(lstrlenW(szKeyName)+1)*sizeof(WCHAR),
szKeyName,
Required,
pBuffer
);
LocalFree(pPropertyList);
pPropertyList = NULL;
LocalFree(pBuffer);
pBuffer= NULL;
if(szKeyName)
{
LocalFree(szKeyName);
szKeyName= NULL;
}
}
if (dwStatus != ERROR_SUCCESS)
break;
}
FnExit:
if(szKeyName)
{
LocalFree(szKeyName);
szKeyName=NULL;
}
ClRtlLogPrint(LOG_NOISE,"[NM] NmPerformFixups Exit, dwStatus=%1!u!\r\n",
dwStatus);
return(dwStatus);
} //NmPerformFixups
/****
@func DWORD | NmpUpdatePerformFixups| The gum update handler for
doing the registry fixups.
@parm IN DWORD | IsSourceNode| If the gum request originated at this
node.
@parm IN PVOID| pPropertyList| Pointer to a property list structure.
@parm IN DWORD | pdwPropertyListSize | A pointer to a DWORD containing
the size of the property list structure.
@comm The gum update handler commits this fixup to the cluster registry
as a transaction.
@rdesc Returns a result code. ERROR_SUCCESS on success.
@xref <f NmJoinFixup> <f NmFormFixup>
****/
DWORD NmpUpdatePerformFixups(
IN BOOL IsSourceNode,
IN PVOID pPropertyList,
IN LPDWORD pdwPropertyListSize
)
{
DWORD dwStatus = ERROR_SUCCESS;
HLOCALXSACTION hXaction;
if (!NmpEnterApi(NmStateOnline)) {
ClRtlLogPrint(LOG_NOISE,
"[NM] Not in valid state to process PerformFixups update. "
"update.\n"
);
return(ERROR_NODE_NOT_AVAILABLE);
}
//
// Begin a transaction
//
hXaction = DmBeginLocalUpdate();
if (hXaction != NULL) {
dwStatus = ClRtlSetPropertyTable(
hXaction,
DmClusterParametersKey,
&NmpFixupRegApis,
NmpJoinFixupProperties,
NULL,
FALSE,
pPropertyList,
*pdwPropertyListSize,
FALSE /*bForceWrite*/,
NULL
);
if (dwStatus == ERROR_SUCCESS) {
DmCommitLocalUpdate(hXaction);
}
else {
DmAbortLocalUpdate(hXaction);
}
}
else {
dwStatus = GetLastError();
ClRtlLogPrint(LOG_CRITICAL, "[NM] Failed to begin a transaction "
"to perform fixups, status %1!u!\n",
dwStatus
);
}
NmpLeaveApi();
return(dwStatus);
} // NmpUpdatePerformFixups
/****
@func DWORD | NmpUpdatePerformFixups2| The gum update handler for
doing the registry fixups and updating in-memory fixups.New fixups
can be added by adding suitable record to FixupTable2. However,
for these new fixups only registry fixup will be carried out.
@parm IN DWORD | IsSourceNode| If the gum request originated at this node.
@parm IN PVOID| pPropertyList| Pointer to a property list structure.
@parm IN DWORD | pdwPropertyListSize | Pointer to a DWORD containing
the size of the property list structure.
@parm IN LPDWORD | lpdeFixupNum | Pointer to DWORD which specifies the
the index in NmpJoinFixupProperties table.
@parm IN PVOID | lpKeyName | Registry Key which needs to be updated
@parm IN PVOID | pPropertyBuffer| Registry update table in marshalled form
@comm The gum update handler commits this fixup to the cluster registry
as a transaction.
@rdesc Returns a result code. ERROR_SUCCESS on success.
@xref <f NmJoinFixup> <f NmFormFixup> <f PostFixupCbTable>
****/
DWORD NmpUpdatePerformFixups2(
IN BOOL IsSourceNode,
IN PVOID pPropertyList,
IN LPDWORD pdwPropertyListSize,
IN LPDWORD lpdwFixupNum,
IN PVOID lpKeyName,
IN PVOID pPropertyBuffer
)
{
DWORD dwStatus = ERROR_SUCCESS;
HLOCALXSACTION hXaction = NULL;
HDMKEY hdmKey;
PRESUTIL_PROPERTY_ITEM pPropertyTable=NULL;
PRESUTIL_PROPERTY_ITEM propertyItem;
if (!NmpEnterApi(NmStateOnline)) {
ClRtlLogPrint(LOG_NOISE,
"[NM] Not in valid state to process PerformFixups2 update. "
"update.\n"
);
return(ERROR_NODE_NOT_AVAILABLE);
}
if(pPropertyBuffer == NULL)
{
ClRtlLogPrint(LOG_CRITICAL,
"[NM] NmpUpdatePerformJoinFixups2: Bad Arguments\n"
);
dwStatus = ERROR_BAD_ARGUMENTS;
goto FnExit;
}
// Begin a transaction
//
hXaction = DmBeginLocalUpdate();
if (hXaction == NULL) {
dwStatus = GetLastError();
ClRtlLogPrint(LOG_CRITICAL,
"[NM] NmpUpdatePerformJoinFixups2: Failed to begin a transaction, "
"status %1!u!\n",
dwStatus
);
goto FnExit;
}
// special case - if fixup is for the property of key "Cluster"
if(!lstrcmpW((LPCWSTR)lpKeyName,CLUSREG_KEYNAME_CLUSTER))
{
hdmKey=DmClusterParametersKey;
}
else
{
hdmKey=DmOpenKey(DmClusterParametersKey,
(LPCWSTR)lpKeyName,
KEY_ALL_ACCESS
);
if (hdmKey == NULL)
{
dwStatus = GetLastError();
ClRtlLogPrint(LOG_CRITICAL,
"[NM] NmpUpdatePerformJoinFixups2: DmOpenKey failed to "
"open key %1!ws! : error %2!u!\n",
lpKeyName,dwStatus);
goto FnExit;
}
}
//unmarshall pPropertyBuffer into a RESUTIL_PROPERTY_ITEM table
//
dwStatus=ClRtlUnmarshallPropertyTable(&pPropertyTable,pPropertyBuffer);
if(dwStatus != ERROR_SUCCESS)
goto FnExit;
dwStatus=ClRtlSetPropertyTable(
hXaction,
hdmKey,
&NmpFixupRegApis,
pPropertyTable,
NULL,
FALSE,
pPropertyList,
*pdwPropertyListSize,
FALSE, // bForceWrite
NULL
);
if (dwStatus != ERROR_SUCCESS) {
goto FnExit;
}
// callback function to update in-memory structures
// for any new fixup introduced in later version,
// the in-memory fixups will not be applied.
if (*lpdwFixupNum < (sizeof(PostFixupCbTable)/sizeof(NM_POST_FIXUP_CB)))
{
if (PostFixupCbTable[*lpdwFixupNum] !=NULL){
dwStatus=(PostFixupCbTable[*lpdwFixupNum])();
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] NmpUpdatePerformJoinFixups2: called postfixup "
"notifycb function with status %1!u!\n",
dwStatus
);
}
}
FnExit:
if (hXaction != NULL)
{
if (dwStatus == ERROR_SUCCESS){
DmCommitLocalUpdate(hXaction);
}
else {
DmAbortLocalUpdate(hXaction);
}
}
if((hdmKey!= DmClusterParametersKey) && (hdmKey!= NULL)) {
DmCloseKey(hdmKey);
}
if (pPropertyTable != NULL) {
// Free pPropertyTable structure
propertyItem=pPropertyTable;
if(propertyItem!=NULL){
while(propertyItem->Name != NULL)
{
LocalFree(propertyItem->Name);
if(propertyItem->KeyName!=NULL)
LocalFree(propertyItem->KeyName);
propertyItem++;
}
LocalFree(pPropertyTable);
}
}
NmpLeaveApi();
return(dwStatus);
} // NmpUpdatePerformFixups2
DWORD NmFixupNotifyCb(VOID)
{
ClRtlLogPrint(LOG_NOISE,
"[NM] NmFixupNotifyCb: Calculating Cluster Node Limit\r\n");
//update the product suite information
//when the node objects are created we assume that the suite
//type is Enterprise.
//Here after a node has joined and informed us about its suite
//type by making fixups to the registry, we read the registry
//and update the node structure
NmpRefreshNodeObjects();
//recalc the cluster node limit
NmpResetClusterNodeLimit();
//SS: This is ugly---we should pass in the product suits early on
//also the fixup interface needs to to be richer so that the postcallback
//function nodes whether it is a form fixup or a join fixup and if it
//is a join fixup, which node is joining. This could certainly optimize
//some of the fixup processing
return(ERROR_SUCCESS);
}