//================================================================================ // Copyright (C) 1997 Microsoft Corporation // Author: RameshV // Description: This file has the functions relating to downloading stuff from // off the DS in a safe way onto the registry. The solution adopted is actually // to dowload onto the "Config.DS" key rather than to the "Configuration" key // itself. Then if the full download is successful, backup this key and restore it // onto the "Configuration" key -- so if anything fails, atleast the old configuration // would be intact. //================================================================================ #include #include #include #define FreeArray1(X) Error = LoopThruArray((X), DestroyString, NULL, NULL);Require(ERROR_SUCCESS == Error); #define FreeArray2(X) Error = MemArrayCleanup((X)); Require(ERROR_SUCCESS == Error); #define FreeArray(X) do{ DWORD Error; FreeArray1(X); FreeArray2(X); }while(0) typedef DWORD (*ARRAY_FN)(PREG_HANDLE, LPWSTR ArrayString, LPVOID MemObject); extern DWORD DestroyString( // defined in regread.c IN PREG_HANDLE Unused, IN LPWSTR StringToFree, IN LPVOID Unused2 ); extern DWORD LoopThruArray( // defined in regread.c IN PARRAY Array, IN ARRAY_FN ArrayFn, IN PREG_HANDLE Hdl, IN LPVOID MemObject ); DWORD // need to include headers.. DhcpDsGetEnterpriseServers( // defined in dhcpds\dhcpread.h. IN DWORD Reserved, IN LPWSTR ServerName, IN OUT PARRAY Servers ) ; //================================================================================ // module files //================================================================================ REG_HANDLE DsConfig = { NULL, NULL, NULL }; // DsConfig key is stored here PM_SERVER CurrentServer; static const DWORD ZeroReserved = 0; DWORD PrepareRegistryForDsDownload( // make reg changes to download VOID ) { DWORD Err, Disposition; REG_HANDLE DsConfigParent; if( NULL != DsConfig.Key ) return ERROR_INVALID_PARAMETER; memset(&DsConfigParent,0, sizeof(DsConfigParent)); Err = RegOpenKeyEx( // open the parent key for DsConfig. HKEY_LOCAL_MACHINE, REG_THIS_SERVER_DS_PARENT, ZeroReserved, REG_ACCESS, &DsConfigParent.Key ); if( ERROR_SUCCESS != Err ) return Err; // cant do much if server key aint there. Err = DhcpRegRecurseDelete(&DsConfigParent, REG_THIS_SERVER_DS_VALUE); RegCloseKey(DsConfigParent.Key); // this is all the parent is needed for if( ERROR_SUCCESS != Err && ERROR_FILE_NOT_FOUND != Err ) { return Err; // could not delete the "config_ds" trash? } Err = RegCreateKeyEx( // now create a fresh "config_ds" key HKEY_LOCAL_MACHINE, REG_THIS_SERVER_DS, ZeroReserved, REG_CLASS, REG_OPTION_NON_VOLATILE, REG_ACCESS, NULL, &DsConfig.Key, &Disposition ); if( ERROR_SUCCESS != Err ) return Err; // could not create the key, nowhere to store.. return DhcpRegSetCurrentServer(&DsConfig); // now set this as the default server loc to use.. } VOID CleanupAfterDownload( // keep stuff clean for other modules VOID ) { if( NULL != DsConfig.Key ) RegCloseKey(DsConfig.Key); DsConfig.Key = NULL; // close the config_ds key and, DhcpRegSetCurrentServer(NULL); // forget abt the config_ds key.. //remote the Ds cache no matter what... } DWORD CopyRegKeys( // copy between reg keys IN HKEY SrcKey, // copy tree rooted at this key IN LPWSTR DestKeyLoc, // onto registry key located here IN LPWSTR FileName // using this as the temp file ) { DWORD Err, Disposition; HKEY DestKey; BOOLEAN HadBackup; NTSTATUS NtStatus; NtStatus = RtlAdjustPrivilege (SE_BACKUP_PRIVILEGE, TRUE, FALSE, &HadBackup); if( ERROR_SUCCESS != NtStatus ) { // could not request backup priv.. return RtlNtStatusToDosError(NtStatus); } NtStatus = RtlAdjustPrivilege (SE_RESTORE_PRIVILEGE, TRUE, FALSE, &HadBackup); if( ERROR_SUCCESS != NtStatus ) { return RtlNtStatusToDosError(NtStatus); } Err = RegSaveKey(SrcKey, FileName, NULL); // NULL ==> no security on file if( ERROR_SUCCESS != Err ) return Err; // if key cant be saved, cant restore. Err = RegCreateKeyEx( // now create a fresh "config_ds" key HKEY_LOCAL_MACHINE, DestKeyLoc, ZeroReserved, REG_CLASS, REG_OPTION_NON_VOLATILE, REG_ACCESS, NULL, &DestKey, &Disposition ); if( ERROR_SUCCESS != Err ) return Err; // could not create the key, nowhere to store.. Err = RegRestoreKey(DestKey, FileName, 0 ); // 0 ==> no flags, in particular, not volatile. RegCloseKey(DestKey); // dont need this key anyways. return Err; } DWORD FixSpecificClusters( // this fixes a specific cluster IN HKEY NewCfgKey, // root cfg where to copy over IN LPWSTR Subnet, // the subnet to copy to IN LPWSTR Range, // the range to copy to IN LPBYTE InUseClusters, // in use cluster value IN ULONG InUseSize, IN LPBYTE UsedClusters, // used clusters value IN ULONG UsedSize ) { return ERROR_CALL_NOT_IMPLEMENTED; // not done yet... // just concat REG_SUBNETS Subnet REG_RANGES Range and try to open that. // if it fails, quit, other wise just set the given values over... } DWORD FixAllClusters1( // copy cluster info frm old to new cfg IN HKEY NewCfgKey, IN HKEY OldCfgKey ) { REG_HANDLE Cfg, Tmp1, Tmp2; DWORD Err; ARRAY Subnets, Ranges; LPWSTR ThisSubnet, ThisRange; ARRAY_LOCATION Loc1, Loc2; Cfg.Key = OldCfgKey; // Should not poke inside directly MemArrayInit(&Subnets); Err = DhcpRegServerGetList(&Cfg, NULL, NULL, &Subnets, NULL, NULL, NULL); if( ERROR_SUCCESS != Err ) { MemArrayCleanup(&Subnets); return Err; } for( Err = MemArrayInitLoc(&Subnets, &Loc1) ; ERROR_FILE_NOT_FOUND != Err ; Err = MemArrayNextLoc(&Subnets, &Loc1) ) { // for each subnet, look for ranges Err = MemArrayGetElement(&Subnets, &Loc1, &ThisSubnet); Err = DhcpRegServerGetSubnetHdl(&Cfg, ThisSubnet, &Tmp1); if( ERROR_SUCCESS != Err ) { // what do we do? just ignore it I think continue; } Err = DhcpRegSubnetGetList(&Tmp1, NULL, &Ranges, NULL, NULL, NULL, NULL ); if( ERROR_SUCCESS != Err ) { DhcpRegCloseHdl(&Tmp1); continue; } for( Err = MemArrayInitLoc(&Ranges, &Loc2) ; ERROR_FILE_NOT_FOUND != Err ; Err = MemArrayNextLoc(&Ranges, &Loc2) ) { // for each range try to copy it over.. LPBYTE InUseClusters = NULL, UsedClusters = NULL; ULONG InUseClustersSize = 0, UsedClustersSize = 0; Err = MemArrayGetElement(&Ranges, &Loc2, &ThisRange); Err = DhcpRegSubnetGetRangeHdl(&Tmp1, ThisRange, &Tmp2); if( ERROR_SUCCESS != Err ) continue; Err = DhcpRegRangeGetAttributes( &Tmp2, NULL /* no name */, NULL /* no comm */, NULL /* no flags */, NULL /* no bootp alloc */, NULL /* no max boop allowed */, NULL /* no start addr */, NULL /* no end addr */, &InUseClusters, &InUseClustersSize, &UsedClusters, &UsedClustersSize ); if( ERROR_SUCCESS == Err ) { Err = FixSpecificClusters( NewCfgKey, ThisSubnet, ThisRange, InUseClusters, InUseClustersSize, UsedClusters, UsedClustersSize ); if( InUseClusters ) MemFree(InUseClusters); if( UsedClusters ) MemFree(UsedClusters); } DhcpRegCloseHdl(&Tmp2); } FreeArray(&Ranges); DhcpRegCloseHdl(&Tmp1); } FreeArray(&Subnets); return ERROR_SUCCESS; } DWORD FixAllClusters( // copy the clusters over frm existing to DS_CONFIG IN HKEY DsKey // so that when it is copied back nothing is lost ) { HKEY OldCfgKey; ULONG Disposition, Err; return ERROR_SUCCESS; // Need to fix this.. Err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, REG_THIS_SERVER, ZeroReserved, REG_CLASS, REG_OPTION_NON_VOLATILE, REG_ACCESS, NULL, &OldCfgKey, &Disposition ); if( ERROR_SUCCESS != Err ) { return Err; // ugh? this should not happen } Err = FixAllClusters1(DsKey, OldCfgKey); RegCloseKey(OldCfgKey); return Err; } VOID CopyDsConfigToNormalConfig( // copy downloaded config to normal config VOID ) { BOOL Status; DWORD Err; Status = DeleteFile(L"TempDhcpFile.Reg" ); // this file will be used for temp. storage if( !Status ) { // could not delete this file? Err = GetLastError(); if( ERROR_FILE_NOT_FOUND != Err && // the file does exist? ERROR_PATH_NOT_FOUND != Err ) { // this could also happen? return; // the nwe wont be able to do the copy! } } FixAllClusters(DsConfig.Key); // copy the ranges values over from old to new.. CopyRegKeys(DsConfig.Key, REG_THIS_SERVER, L"TempDhcpFile.Reg"); DeleteFile(L"TempDhcpFile.Reg" ); // dont need this file anymore.. } #if 0 DWORD SaveServerClasses( // save all class info onto registry IN PREG_HANDLE Server, // registry handle to server config. IN PM_CLASSDEFLIST Classes // list of defined classes ) { DWORD Err, Err2; REG_HANDLE Hdl; ARRAY_LOCATION Loc; PM_CLASSDEF ThisClass; for( // save each class definition Err = MemArrayInitLoc(&Classes->ClassDefArray, &Loc) ; ERROR_FILE_NOT_FOUND != Err ; Err = MemArrayNextLoc(&Classes->ClassDefArray, &Loc) ) { //= require ERROR_SUCCESS == Err Err = MemArrayGetElement(&Classes->ClassDefArray, &Loc, &ThisClass); //= require ERROR_SUCCESS == Err && NULL != ThisClass Err = DhcpRegServerGetClassDefHdl(Server,ThisClass->Name,&Hdl); if( ERROR_SUCCESS != Err ) return Err; // registry error? Err = DhcpRegClassDefSetAttributes // save this class information ( /* Hdl */ &Hdl, /* Name */ &ThisClass->Name, /* Comment */ &ThisClass->Comment, /* Flags */ &ThisClass->Type, /* Value */ &ThisClass->ActualBytes, /* ValueSize */ ThisClass->nBytes ); Err2 = DhcpRegCloseHdl(&Hdl); //= require ERROR_SUCCESS == Err2 if( ERROR_SUCCESS != Err) return Err; // could not set-attribs in reg. } return ERROR_SUCCESS; // everything went fine. } DWORD SaveServerOptDefs1( // save some option definition IN PREG_HANDLE Server, // registry handle to server config. IN LPWSTR ClassName, // name of the class of option IN PM_OPTDEFLIST OptDefList // list of option definitions ) { DWORD Err, Err2; ARRAY_LOCATION Loc; PM_OPTDEF ThisOptDef; for( // save each opt definition Err = MemArrayInitLoc(&OptDefList->OptDefArray, &Loc) ; ERROR_FILE_NOT_FOUND != Err ; Err = MemArrayNextLoc(&OptDefList->OptDefArray, &Loc) ) { //= require ERROR_SUCCESS == Err Err = MemArrayGetElement(&OptDefList->OptDefArray, &Loc, &ThisOptDef); //= require ERROR_SUCCESS == Err && NULL != ThisOptDef Err = DhcpRegSaveOptDef // save the option def ( /* OptId */ ThisOptDef->OptId, /* ClassName */ ClassName, /* Name */ ThisOptDef->OptName, /* Comment */ ThisOptDef->OptComment, /* OptType */ ThisOptDef->Type, /* OptVal */ ThisOptDef->OptVal, /* OptLen */ ThisOptDef->OptValLen ); if( ERROR_SUCCESS != Err ) return Err; // reg. err saving opt def } return ERROR_SUCCESS; // everything went fine. } DWORD SaveServerOptdefs( // save all the opt def's onto registry IN PREG_HANDLE Server, // registry handle to server config. IN PM_OPTCLASSDEFLIST Optdefs ) { DWORD Err, Err2; ARRAY_LOCATION Loc; PM_OPTCLASSDEFL_ONE ThisOptClass; LPWSTR ClassName; PM_CLASSDEF ClassDef; for( // save each opt definition Err = MemArrayInitLoc(&Optdefs->Array, &Loc) ; ERROR_FILE_NOT_FOUND != Err ; Err = MemArrayNextLoc(&Optdefs->Array, &Loc) ) { //= require ERROR_SUCCESS == Err Err = MemArrayGetElement(&Optdefs->Array, &Loc, &ThisOptClass); //= require ERROR_SUCCESS == Err && NULL != ThisClass if( 0 == ThisOptClass->ClassId ) { // no class for this option ClassName = NULL; } else { // lookup class in this server struct Err = MemServerGetClassDef( CurrentServer, // need to pass this as param ThisOptClass->ClassId, NULL, 0, NULL, &ClassDef ); if( ERROR_SUCCESS != Err) return Err; // could not find the class? invalid struct ClassName = ClassDef->Name; // found the class, use this name } Err = SaveServerOptDefs1(Server, ClassName, &ThisOptClass->OptDefList); if( ERROR_SUCCESS != Err) return Err; // could not save some opt definition.. } return ERROR_SUCCESS; // everything went fine. } DWORD SaveServerOptions1( // save some option IN PREG_HANDLE Server, // registry handle to server config. IN LPWSTR ClassName, // name of the class of option IN PM_OPTLIST OptList // list of options ) { DWORD Err, Err2; ARRAY_LOCATION Loc; PM_OPTION ThisOpt; for( // save each option Err = MemArrayInitLoc(OptList, &Loc) ; ERROR_FILE_NOT_FOUND != Err ; Err = MemArrayNextLoc(OptList, &Loc) ) { //= require ERROR_SUCCESS == Err Err = MemArrayGetElement(OptList, &Loc, &ThisOpt); //= require ERROR_SUCCESS == Err && NULL != ThisOpt Err = DhcpRegSaveGlobalOption // save the option ( /* OptId */ ThisOpt->OptId, /* ClassName */ ClassName, /* Value */ ThisOpt->Val, /* ValueSize */ ThisOpt->Len ); if( ERROR_SUCCESS != Err ) return Err; // reg. err saving option } return ERROR_SUCCESS; // everything went fine. } DWORD SaveServerOptions( // save all options onto registry IN PREG_HANDLE Server, // registry handle to server config. IN PM_OPTCLASS Options ) { DWORD Err, Err2; ARRAY_LOCATION Loc; PM_ONECLASS_OPTLIST ThisOptClass; LPWSTR ClassName; PM_CLASSDEF ClassDef; for( // save each class definition Err = MemArrayInitLoc(&Options->Array, &Loc) ; ERROR_FILE_NOT_FOUND != Err ; Err = MemArrayNextLoc(&Options->Array, &Loc) ) { //= require ERROR_SUCCESS == Err Err = MemArrayGetElement(&Options->Array, &Loc, &ThisOptClass); //= require ERROR_SUCCESS == Err && NULL != ThisOptClass if( 0 == ThisOptClass->ClassId ) { // no class for this option ClassName = NULL; } else { // lookup class in this server struct Err = MemServerGetClassDef( CurrentServer, // need to pass this as param ThisOptClass->ClassId, NULL, 0, NULL, &ClassDef ); if( ERROR_SUCCESS != Err) return Err; // could not find the class? invalid struct ClassName = ClassDef->Name; // found the class, use this name } Err = SaveServerOptions1(Server, ClassName, &ThisOptClass->OptList); if( ERROR_SUCCESS != Err) return Err; // could not save some option.. } return ERROR_SUCCESS; // everything went fine. } DWORD SaveServerScope( // save unicast-or-mcast scope onto reg. IN PREG_HANDLE ServerHdl, // registry handle to server config IN PM_SERVER MemServer, // server object in memory IN LPVOID Scope, // either PM_SUBNET or PM_MSCOPE object IN BOOL fSubnet // TRUE ==> Subnet type, FALSE ==> MScope type. ) { DWORD Err; PM_SUBNET Subnet = Scope; PM_MSCOPE Subnet = MScope; PM_SSCOPE SScope; if( fSubnet ) { // if subnet, need to add it to superscope.. if( 0 != Subnet->SuperScopeId ) { // this belongs to superscope? Err = MemServerFindSScope(MemServer, Subnet->SuperScopeId, NULL, &SScope); if( ERROR_SUCCESS != Err ) { // wrong superscope? invlaid data return Err; } Err = DhcpRegSScopeSaveSubnet(SScope->Name, Subnet->Address); if( ERROR_SUCCESS != Err ) return Err;// could not add subnet to superscope? } } if( fSubnet ) { Err = DhcpRegSaveSubnet // save this subnet ( /* SubnetAddress */ Subnet->Address, /* SubnetMask */ Subnet->Mask, /* SubnetState */ Subnet->State, /* SubnetName */ Subnet->Name /* SubnetComment */ Subnet->Description ); } else { Err = DhcpRegSaveMScope // save this mcast scope ( /* MScopeId */ MScope->MScopeId, /* SubnetState */ MScope->State, /* AddressPolicy */ MScope->Policy, /* TTL */ MScope->TTL, /* pMScopeName */ MScope->Name, /* pMScopeComment */ MScope->Description, /* LangTag */ MScope->LangTag, /* ExpiryTime */ &MScope->ExpiryTime ); } if( ERROR_SUCCESS != Err ) return Err; // could not save subnet info? } DWORD SaveServerScopes( // save unicast-or-mcast scopes onto reg. IN PREG_HANDLE Server, // registry handle to server config. IN PARRAY Scopes, // array of PM_SUBNET or PM_MSCOPE types IN BOOL fSubnet // TRUE ==> Subnet type, FALSE ==> MScope type. ) { DWORD Err; ARRAY_LOCATION Loc; PM_SUBNET Subnet; for( // save each scope.. Err = MemArrayInitLoc(Scopes, &Loc) ; ERROR_FILE_NOT_FOUND != Err ; Err = MemArrayNextLoc(Scopes, &Loc) ) { //= require ERROR_SUCCESS == Err Err = MemArrayGetElement(Scopes, &Loc, &Subnet); //= require ERROR_SUCCESS == Err && NULL != Subnet Err = SaveServerScope(Server, CurrentServer, Subnet, fSubnet); if( ERROR_SUCCESS != Err ) return Err; // could not save the subnet/m-scope.. } return ERROR_SUCCESS; } DWORD SaveServerSubnets( // save all subnet info onto reg. IN PREG_HANDLE Server, // registry handle to server config. IN PARRAY Subnets // array of type PM_SUBNET elements ) { return SaveServerScopes(Server, Subnets, TRUE); // call common routine } DWORD SaveServerMScopes( // save all the m-cast scopes onto reg. IN PREG_HANDLE Server, // registry handle to server config. IN PARRAY MScopes // array of type PM_MSCOPE elements ) { return SaveServerScopes(Server, MScopes, FALSE); // call common routine } DWORD DownloadServerInfoFromDs( // save the server info onto registry IN PM_SERVER Server // the server to save onto registry ) { DWORD Err; REG_HANDLE Hdl, Hdl2; ARRAY_LOCATION Loc; CurrentServer = Server; // this global used by several funcs above.. Err = DhcpRegGetThisServer(&Hdl); // get current server hdl if( ERROR_SUCCESS != Err ) return Err; Err = DhcpRegServerSetAttributes // set server attributes ( /* PREG_HANDLE Hdl */ &Hdl, /* LPWSTR *Name */ &Server->Name, /* LPWSTR *Comment */ &Server->Comment, /* DWORD *Flags */ &Server->State ); // ignore errors.. Err = SaveServerClasses(&Hdl, &Server->ClassDefs); if( ERROR_SUCCESS == Err ) { // saved classes? save optdefs.. Err = SaveServerOptdefs(&Hdl, &Server->OptDefs); } if( ERROR_SUCCESS == Err ) { // saved optdefs? save options.. Err = SaveServerOptions(&Hdl, &Server->Options); } if( ERROR_SUCCESS == Err ) { // saved options? save subnets.. Err = SaveServerSubnets(&Hdl, &Server->Subnets); } if( ERROR_SUCCESS == Err ) { // saved subnets? save mcast scopes Err = SaveServerMScopes(&Hdl, &Server->MScopes); } (void)DhcpRegCloseHdl(&Hdl); // free resource return Err; } #endif 0 DWORD DownloadServerInfoFromDs( // save the server info onto registry IN PM_SERVER Server // the server to save onto registry ) { return DhcpRegServerSave(Server); } DWORD DownloadFromDsForReal( // really try to downlaod from DS IN LPWSTR ServerName ) { DWORD Err, Err2; ARRAY Servers; ARRAY_LOCATION Loc; PM_SERVER ThisServer; Err = MemArrayInit(&Servers); // initialize array if( ERROR_SUCCESS != Err ) return Err; Err = DhcpDsGetEnterpriseServers // fetch the server info from DS ( /* Reserved */ ZeroReserved, /* ServerName */ ServerName, /* Servers */ &Servers ); Err2 = ERROR_SUCCESS; // init return value for( // process all the information Err = MemArrayInitLoc(&Servers, &Loc) ; ERROR_FILE_NOT_FOUND != Err ; Err = MemArrayNextLoc(&Servers, &Loc) ) { //= require ERROR_SUCCESS == Err Err = MemArrayGetElement(&Servers, &Loc, &ThisServer); //= require ERROR_SUCCESS == Err && NULL != ThisServer Err = DownloadServerInfoFromDs(ThisServer); if( ERROR_SUCCESS != Err ) { // oops.. could not do it? Err2 = Err; // store error.. } MemServerFree(ThisServer); // free all this memory. } Err = MemArrayCleanup(&Servers); // free mem allcoated for array if( ERROR_SUCCESS != Err ) Err2 = Err; // something went wrong? return Err2; } //================================================================================ // the only exported function is this. //================================================================================ VOID DhcpRegDownloadDs( // safe download of stuff onto registry IN LPWSTR ServerName // name of dhcp servre to download for ) { DWORD Err; Err = PrepareRegistryForDsDownload(); // prepare the Config.DS key and stuff.. if( ERROR_SUCCESS != Err ) return; // oops, could not even do this? Err = DownloadFromDsForReal(ServerName); // actually try to download from DS. if( ERROR_SUCCESS == Err ) { // could actually download successfully CopyDsConfigToNormalConfig(); // now copy this configuration to nrml loc. } CleanupAfterDownload(); // now cleanup the regsitry handles etc.. DhcpRegUpdateTime(); // fix the time stamp to now.. } //================================================================================ // end of file //================================================================================