/*++ Copyright (c) 1990 Microsoft Corporation Module Name: winscnf.c Abstract: This module contains functions that deal with the configuration information for the WINS Portability: This module is portable Author: Pradeep Bahl (PradeepB) Dec-1992 Revision History: Modification date Person Description of modification ----------------- ------- ---------------------------- --*/ /* * Includes */ #include "wins.h" #include #include #include #include #include #include "comm.h" #include "winreg.h" #include "winsevt.h" #include "winsmsc.h" #include "winscnf.h" #include "nms.h" #include "nmsnmh.h" #include "rpl.h" #include "rplpush.h" #include "winsintf.h" #include "nmfilter.h" #include /* * Local Macro Declarations */ // // Size of max string that a user can input in a REG_SZ field // #define MAX_SZ_SIZE 80 #define REG_M(fn, evt, exc) \ { \ if((fn) != ERROR_SUCCESS) \ { \ WINSEVT_LOG_M( \ WINS_FATAL_ERR, \ (evt) \ ); \ WINS_RAISE_EXC_M((exc)); \ } \ } // // pointer to default path for log file. If you change this to a NON NULL // value, make sure you don't try to free the memory in SetSystemParam // in nmsdb.c // #define DEFAULT_LOG_PATH NULL #define _WINS_CFG_KEY \ TEXT("System\\CurrentControlSet\\Services\\Wins") #define _WINS_CFG_PARAMETERS_KEY TEXT("Parameters") #define _WINS_CFG_PARTNERS_KEY TEXT("Partners") #define _WINS_CFG_CC_KEY TEXT("Parameters\\ConsistencyCheck") #define _WINS_CFG_PULL_KEY TEXT("Partners\\Pull") #define _WINS_CFG_PUSH_KEY TEXT("Partners\\Push") #define _WINS_CFG_DATAFILES_KEY TEXT("Parameters\\Datafiles") #define _WINS_CFG_SPEC_GRP_MASKS_KEY TEXT("Parameters\\InternetGrpMasks") #define _WINS_LOG_KEY \ TEXT("System\\CurrentControlSet\\Services\\EventLog\\Application\\WinsInt") #define _WINS_MSGFILE_SKEY TEXT("EventMessageFile") #define _WINS_LOG_FILE_NAME TEXT("%SystemRoot%\\System32\\winsevnt.dll") #define _RPL_CLASS TEXT("RplClass")//class for Rpl Pull and Push //keys // // The start version number should never be allowed to go above this number // This will avoid a wrap around. // #define MAX_START_VERS_NO 0x0FFFFFFF // // Names of event variables used for notification purposes // #ifdef WINSDBG #define WINS_KEY_CHG_EVT_NM TEXT("WinsKChgEvt") #define PARAMETERS_KEY_CHG_EVT_NM TEXT("WinsParamatersKChgEvt") #define PARTNERS_KEY_CHG_EVT_NM TEXT("WinsPartenersKChgEvt") #define CNF_CHG_EVT_NM TEXT("WinsConfigChangeEvt") #else #define WINS_KEY_CHG_EVT_NM NULL #define PARAMETERS_KEY_CHG_EVT_NM NULL #define PARTNERS_KEY_CHG_EVT_NM NULL #define CNF_CHG_EVT_NM NULL #endif // // Values for the fStaticInit field of the configuration data structure // #define DO_STATIC_INIT TRUE #define DONT_DO_STATIC_INIT FALSE // // defines for the InitTimeRpl and InitTimePush fields of WinsCnf // #define DO_INIT_TIME_RPL 1 #define NO_INIT_TIME_RPL 0 // // NO_LIMIT_CHK_FLAG - for easing the task of testers // // If this flag is set in LogDetailedEvts DWORD, WINS skips all // checks for the min. values of the time intervals and Update Count. // This kind of operation of WINS is unsupported and is being provided // only to help out testers // #define NO_LIMIT_CHK_FLAG 0x80000000 //MSB is set. // // If ErrEvt passed is 0, we don't log any message. NOTE: a WINS event // can never have 0 as its value (checkout winsevnt.mc) // #define QUERY_VALUE_M(Key, Str, ValTyp, Var, ErrEvt, DefVal) \ { \ DWORD Sz = sizeof((Var)); \ if (RegQueryValueEx( \ (Key), \ (Str), \ NULL, \ &(ValTyp), \ (LPBYTE)&(Var), \ &Sz \ ) != ERROR_SUCCESS \ ) \ { \ if ((ErrEvt) != 0) \ { \ WINSEVT_LOG_INFO_M( \ WINS_SUCCESS, \ (ErrEvt) \ ); \ } \ Var = DefVal; \ } \ } /* * Local Typedef Declarations */ /* * Global Variable Definitions */ CRITICAL_SECTION WinsCnfCnfCrtSec; //used for reinitialization //of certain fields of the //WinsCnf structure BOOL fWinsCnfRplEnabled = TRUE; //replication is enabled BOOL fWinsCnfScvEnabled = TRUE; //scavenging is enabled FUTURES("use #ifdef PERF around the following three perf. mon. vars") BOOL fWinsCnfPerfMonEnabled = FALSE; //perf. mon is disabled BOOL fWinsCnfHighResPerfCntr = FALSE; //indicates whether the //hardware supports a high //performance counter LARGE_INTEGER LiWinsCnfPerfCntrFreq; //indicates the frequency of //the counter BOOL fWinsCnfReadNextTimeVersNo = FALSE; DWORD WinsCnfCnfMagicNo = WINSCNF_INITIAL_CNF_MAGIC_NO; BOOL fWinsCnfInitStatePaused; //TCHAR WinsCnfDb[WINS_MAX_FILENAME_SZ]; //db file to hold tables BOOL WinsCnfRegUpdThdExists = FALSE; //#define MAX_PATH_SIZE 200 PTCHAR pWinsCnfNbtPath; BOOL sfNoLimitChk = FALSE; //to override the limit checks // // NetBt handle // HANDLE WinsCnfNbtHandle = NULL; // // // Init the configuration structure with default values // WINSCNF_CNF_T WinsCnf = { WINSCNF_INITIAL_CNF_MAGIC_NO, //id NOTE("Change 1 to 0 before production") 0, //Log detailed evts 1, //default number of processors 200, //default no. of db buffers { 0, NULL}, //Spec.grp mask WINSCNF_E_INITING, //state WINSCNF_DEF_REFRESH_INTERVAL, WINSCNF_MIN_TOMBSTONE_INTERVAL, WINSCNF_MIN_TOMBSTONE_TIMEOUT, WINSCNF_MIN_VERIFY_INTERVAL, WINSCNF_SCV_CHUNK, WINSCNF_DEF_CHL_MAX_RETRIES, WINSCNF_DEF_INIT_CHL_RETRY_INTVL, WINSCNF_DB_NAME_ASCII, //db file name 0, //no of STATIC files NULL, //ptr to file names DONT_DO_STATIC_INIT, (HANDLE)0, //notify event handle (WINS) (HANDLE)0, //not. evt hdl (PARAMETSRS) (HANDLE)0, //not. evt hdl (PARTNERS) (HANDLE)0, //Config change handle (HANDLE)0, //log event handle (DWORD)WINSINTF_E_NORMAL, WINSTHD_DEF_NO_NBT_THDS, WINSCNF_SCV_PRIORITY_LVL, WINSCNF_MIN_VALID_RPL_INTVL,//max Rpl //Time Intvl TRUE, //rpl. only with cnf partners TRUE, //add 1B to responses to 1C name queries #if MCAST > 0 FALSE, //no rpl. with self found pnrs WINSCNF_DEF_MCAST_TTL, WINSCNF_DEF_MCAST_INTVL, #endif TRUE, //logging is on NULL, //current directory NULL, //no backup directory FALSE, //Do backup on term flg FALSE, //PStatic flag 0, //type of persona list (0 = non-grata) 0, //number of addresses in persona list NULL, //persona list WINSCNF_RPL_DEFAULT_TYPE, //def. rpl TRUE, //No rpl on error TRUE, //no persistent connections // // CC initialization // MAXULONG, //CC Time Int FALSE, //SpTime Set MAXULONG, //Sp Time WINSCNF_CC_DEF_RECS_AAT, WINSCNF_CC_DEF_USE_RPL_PNRS, FALSE, //no spoofing FALSE, // no randomization of 1C list. // //PullInfo initialization // WINSCNF_MAX_COMM_RETRIES, //comm. //failure //retries 0, //no of Push Pnrs NULL,//ptr to Pull Pnrs records DO_INIT_TIME_RPL, //do init time //pulling WINSCNF_RPL_DEFAULT_TYPE, TRUE, // persistent connections // // PushInfo initialization // TRUE, // trigger on address change //of owned entry 0, //no of Pull Pnrs 0, //no of Push recs with valid //update count NULL,//ptr to Push Pnrs records DO_INIT_TIME_RPL, //init time //pushing disabled DO_PROP_NET_UPD_NTF, //prop net upd //ntfs. WINSCNF_RPL_DEFAULT_TYPE, TRUE // persistent connections }; /* * Local Variable Definitions */ STATIC BOOL sfVersNoUpdThdExists = FALSE; STATIC BOOL sfVersNoChanged = FALSE; STATIC HKEY sConfigRoot; //HKEY for the WINS root STATIC HKEY sParametersKey; //HKEY for the PARAMETERS subkey STATIC HKEY sCCKey; //HKEY for the CC subkey STATIC HKEY sPartnersKey; //HKEY for PARTNERS subkey STATIC HKEY sLogRoot; //HKEY for the log root FUTURES("Might want to change these to auto variables later") STATIC TCHAR sWinsCfgKey[] = _WINS_CFG_KEY; STATIC TCHAR sWinsLogKey[] = _WINS_LOG_KEY; STATIC TCHAR sWinsMsgFileSKey[] = _WINS_MSGFILE_SKEY; // // flags that indicate to WinsCnfOpenSubKeys() whether the corresponding keys // exist. // STATIC BOOL sfParametersKeyExists = FALSE; STATIC BOOL sfPartnersKeyExists = FALSE; STATIC BOOL sfParametersKeyOpen = FALSE; STATIC BOOL sfPartnersKeyOpen = FALSE; TCHAR sLogFilePath[WINS_MAX_FILENAME_SZ]; //path to log file /* * Local Function Prototype Declarations */ /* prototypes for functions local to this module go here */ STATIC VOID LnkWSameMetricValRecs( PWINSCNF_CNF_T pWinsCnf, PRPL_CONFIG_REC_T pCnfRec ); STATIC int __cdecl CompUpdCnt( CONST LPVOID pElem1, CONST LPVOID pElem2 ); STATIC VOID GetPnrInfo( RPL_RR_TYPE_E RRType_e, PWINSCNF_CNF_T pWinsCnf ); STATIC VOID GetKeyInfo( IN HKEY Key, IN WINSCNF_KEY_E KeyTyp_e, OUT LPDWORD pNoOfSubKeys, OUT LPDWORD pNoOfVals ); STATIC BOOL SanityChkParam( PWINSCNF_CNF_T pWinsCnf ); STATIC VOID ChkWinsSubKeys( VOID ); STATIC VOID GetSpTimeData( HKEY SubKey, LPSYSTEMTIME pCurrTime, LPBOOL pfSpTime, LPDWORD pSpTimeIntvl ); STATIC VOID ReadSpecGrpMasks( PWINSCNF_CNF_T pWinsCnf ); VOID GetOwnerList( PWINSCNF_CNF_T pWinsCnf ); VOID ReadCCInfo( PWINSCNF_CNF_T pWinsCnf ); #if MCAST > 0 STATIC DWORD SetVal( HKEY RootKey, LPWSTR pName, DWORD ValType, LPWSTR pVal, DWORD ValSize ); #endif #ifdef WINSDBG STATIC VOID PrintRecs( RPL_RR_TYPE_E RRType_e, PWINSCNF_CNF_T pWinsCnf ); #endif /*function defs*/ STATUS WinsCnfInitConfig( VOID ) /*++ Routine Description: This function opens the registry and reads in all the configuration information from it. Arguments: None Externals Used: WinsCnf Called by: Init() in nms.c Comments: None Return Value: Success status codes -- Error status codes -- --*/ { DWORD NewKeyInd; LONG RetVal; /* First and foremost, open (or create if non-existent) the log file */ #if 0 InitLog(); #endif RetVal = RegCreateKeyEx( HKEY_LOCAL_MACHINE, //predefined key value sWinsCfgKey, //subkey for WINS 0, //must be zero (reserved) TEXT("Class"), //class -- may change in future REG_OPTION_NON_VOLATILE, //non-volatile information KEY_ALL_ACCESS, //we desire all access to the keyo NULL, //let key have default sec. attributes &sConfigRoot, //handle to key &NewKeyInd //is it a new key (out arg) ); if (RetVal != ERROR_SUCCESS) { WINSEVT_LOG_N_RET_M( WINS_FATAL_ERR, WINS_EVT_CANT_OPEN_WINS_KEY, WINS_FATAL_ERR ); } // // Initialize the critical section that guards the fields used // by Scavenger thread // InitializeCriticalSection(&WinsCnfCnfCrtSec); InitializeCriticalSection(&g_cs1BFilter); /* First create the events that will be passed to the RegNotifyChangeKeyValue function */ try { WinsMscCreateEvt( WINS_KEY_CHG_EVT_NM, FALSE, //auto reset event &WinsCnf.WinsKChgEvtHdl ); WinsMscCreateEvt( PARAMETERS_KEY_CHG_EVT_NM, FALSE, //auto reset event &WinsCnf.ParametersKChgEvtHdl ); WinsMscCreateEvt( PARTNERS_KEY_CHG_EVT_NM, FALSE, //auto reset event &WinsCnf.PartnersKChgEvtHdl ); } except(EXCEPTION_EXECUTE_HANDLER) { DBGPRINTEXC("WinsCnfInitConfig"); WINSEVT_LOG_M(WINS_FATAL_ERR, WINS_EVT_CANT_CREATE_REG_EVT); return(WINS_FAILURE); } // // Create the event that this main thread will set when configuration changes // The main thread sets this event to notify the scavenger thread (for now) // about the changes // WinsMscCreateEvt( CNF_CHG_EVT_NM, FALSE, //auto reset event &WinsCnf.CnfChgEvtHdl ); // // Opens the Partners and Parameters keys // WinsCnfOpenSubKeys(); // // Read in the registry information // WinsCnfReadRegInfo(&WinsCnf); /* Ask to be notified when the Configuration key or any of the subkeys change */ WinsCnfAskToBeNotified(WINSCNF_E_WINS_KEY); return(WINS_SUCCESS); } VOID WinsCnfReadPartnerInfo( PWINSCNF_CNF_T pWinsCnf ) /*++ Routine Description: This function gets all the information pertaining to the Partners of this WINS. Under the configuration key above, there are two Keys PULL and PUSH. Under each key, there can be one or more keys (IP addresses). The values for each IP address key are: Time Interval (for both Pull and Push IP address keys) Update Count (for Push IP address keys) Arguments: pWinsCnf - Address of Wins Configuration structure Externals Used: None Return Value: None Error Handling: Called by: Init function of the Replicator. Side Effects: Comments: Note: This function should never be called when inside the NmsNmhNamRegCrtSec, otherwise a deadlock can occur with the Pull thread (check out Reconfig in rplpull.c) --*/ { DWORD ValTyp; // // Initialize the MaxRplTimeInterval field to 0. After we have read // both the PULL and PUSH key information from the registry, the above // field will contain the max. replication time interval specified for // pulling and pushing replicas // pWinsCnf->MaxRplTimeInterval = 0; pWinsCnf->PullInfo.NoOfPushPnrs = 0; pWinsCnf->PullInfo.pPullCnfRecs = NULL; pWinsCnf->PullInfo.RplType = WINSCNF_RPL_DEFAULT_TYPE; pWinsCnf->PushInfo.NoOfPullPnrs = 0; pWinsCnf->PushInfo.pPushCnfRecs = NULL; pWinsCnf->PushInfo.fAddChgTrigger = FALSE; pWinsCnf->PushInfo.RplType = WINSCNF_RPL_DEFAULT_TYPE; // // Since we are again reading the info about the Partners key, increment // the magic no. No other thread increments this no. The thread that // looks at this no is the Pull thread. // EnterCriticalSection(&WinsCnfCnfCrtSec); pWinsCnf->MagicNo = ++WinsCnfCnfMagicNo; LeaveCriticalSection(&WinsCnfCnfCrtSec); try { GetOwnerList(pWinsCnf); // get list of persona (grata / non-grata) // // Read in the RplType DWORD. Even if no partners are defined, we do this // in case this WINS is open to all partners (i.e. fOnlyWCnfPnrs is FALSE) // QUERY_VALUE_M( sPartnersKey, WINSCNF_RPL_TYPE_NM, ValTyp, pWinsCnf->RplType, 0, // no logging WINSCNF_RPL_DEFAULT_TYPE ); GetPnrInfo(RPL_E_PULL, pWinsCnf); GetPnrInfo(RPL_E_PUSH, pWinsCnf); } except(EXCEPTION_EXECUTE_HANDLER) { DWORD ExcCode = GetExceptionCode(); // // If there is some problem with the registry, we don't want // to bugcheck WINS. It can proceed with default values. // Since we have already logged the errors, the administrator // can take corrective action if necessary // if ( (ExcCode != WINS_EXC_CANT_OPEN_KEY) && (ExcCode != WINS_EXC_CANT_QUERY_KEY) && (ExcCode != WINS_EXC_CANT_CLOSE_KEY) ) { WINS_RERAISE_EXC_M(); } } return; } STATUS WinsCnfInitLog( VOID ) /*++ Routine Description: This function open (or creates) a log file for registering events Arguments: None Externals Used: None Return Value: Success status codes -- WINS_SUCCESS Error status codes -- WINS_FAILURE Error Handling: Called by: WinsCnfInitConfig Side Effects: Comments: None --*/ { LONG RetVal = ERROR_SUCCESS; STATUS RetStat = WINS_SUCCESS; #ifdef WINS_INTERACTIVE DWORD NewKeyInd; TCHAR Buff[160]; DWORD dwData; RetVal = RegCreateKeyEx( HKEY_LOCAL_MACHINE, //predefined key value sWinsLogKey, //subkey for WINS 0, //must be zero (reserved) TEXT("Class"), //class -- may change in future REG_OPTION_NON_VOLATILE, //non-volatile information KEY_ALL_ACCESS, //we desire all access to the keyo NULL, //let key have default sec. attributes &sLogRoot, //handle to key &NewKeyInd //is it a new key (out arg) -- not //looked at ); if (RetVal != ERROR_SUCCESS) { return(WINS_FAILURE); } /* Set the event id message file name */ lstrcpy(Buff, _WINS_LOG_FILE_NAME); /* Add the Event-ID message-file name to the subkey */ RetVal = RegSetValueEx( sLogRoot, //key handle sWinsMsgFileSKey, //value name 0, //must be zero REG_EXPAND_SZ, //value type (LPBYTE)Buff, (lstrlen(Buff) + 1) * sizeof(TCHAR) //length of value data ); if (RetVal != ERROR_SUCCESS) { return(WINS_FAILURE); } /* Set the supported data types flags */ dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE; RetVal = RegSetValueEx ( sLogRoot, //subkey handle TEXT("TypesSupported"), //value name 0, //must be zero REG_DWORD, //value type (LPBYTE)&dwData, //Address of value data sizeof(DWORD) //length of value data ); if (RetVal != ERROR_SUCCESS) { return(WINS_FAILURE); } /* * Done with the key. Close it */ RetVal = RegCloseKey(sLogRoot); if (RetVal != ERROR_SUCCESS) { return(WINS_FAILURE); } #endif WinsCnf.LogHdl = RegisterEventSource( (LPCTSTR)NULL, //use local machine TEXT("Wins") ); if (WinsCnf.LogHdl == NULL) { DBGPRINT1(ERR, "InitLog: RegisterEventSource error = (%x)\n", GetLastError()); return(WINS_FAILURE); } WINSEVT_LOG_INFO_D_M(WINS_SUCCESS, WINS_EVT_LOG_INITED); return(RetStat); } VOID LnkWSameMetricValRecs( PWINSCNF_CNF_T pWinsCnf, PRPL_CONFIG_REC_T pCnfRec ) /*++ Routine Description: This function is called to link a configuration record with all other configuration records with the same metric value. The metric to use depends upon the type of the record. If it is a PULL record, the metric is "Time Interval". If the record is a PUSH record, the metric is "Update Count" Arguments: pWinsCnf - Address of configuration block pCnfRec - Configuration Record to link. Externals Used: None Return Value: None Error Handling: Called by: WinsCnfReadPartnerInfo Side Effects: Comments: The record to be linked is the last record in the buffer of records of the same type. --*/ { PRPL_CONFIG_REC_T pTmp; DWORD OffMetricToComp; LONG MetricVal; // // Set the variables used later based on the record type // if (pCnfRec->RRTyp_e == RPL_E_PULL) { pTmp = pWinsCnf->PullInfo.pPullCnfRecs; MetricVal = pCnfRec->TimeInterval; OffMetricToComp = offsetof(RPL_CONFIG_REC_T, TimeInterval); } else //it is a PUSH record { pTmp = pWinsCnf->PushInfo.pPushCnfRecs; MetricVal = pCnfRec->UpdateCount; OffMetricToComp = offsetof(RPL_CONFIG_REC_T, UpdateCount); } // // Link in this record at the end of the linked list of // records with the same metric value in the buffer pointed by // the starting value of pTmp (set above). // for ( ; pTmp != pCnfRec; //until we reach this record pTmp = (PRPL_CONFIG_REC_T)((LPBYTE)pTmp + RPL_CONFIG_REC_SIZE) ) { // // If Metric Value is same, go to end of linked list and // link in the record // if (*((LONG *)((LPBYTE)pTmp + OffMetricToComp)) == MetricVal) { // // Note: if the metric is UpdateCount (Push records) // then, the following if will fail. // // // If both records have a specific time for replication, // that time must agree too // if (pTmp->fSpTime && pCnfRec->fSpTime) { // // If specific time is not the same, go to the // next record in the array // if (pTmp->SpTimeIntvl != pCnfRec->SpTimeIntvl) { continue; } } for( ; pTmp->pNext != NULL; pTmp = pTmp->pNext ) ; //NULL body pTmp->pNext = pCnfRec; // // Set flag to indicate that this record has // been linked. Used in SubmitTimerReqs in rplpull.c // pCnfRec->fLinked = TRUE; break; //record is linked. break out of the loop } } //end of for { .. } for looping over all records in the buffer // // Make pNext to NULL since this is the last record in the buffer // buffer of Config Records (also in the chain if records with // the same metric) // pCnfRec->pNext = NULL; return; } VOID WinsCnfSetLastUpdCnt( PWINSCNF_CNF_T pWinsCnf ) /*++ Routine Description: This function is called at initialization/reinitialization time if InitTimePush registry variable is set to 1) to set the LastVersNo field of all Push Configuration records to the value of the NmsNmhMyMAxVersNo counter. This is done to avoid Push Notifications to be sent at Init time. Arguments: pWinsCnf - Wins Configuration Info Externals Used: NmsNmhMyMaxVersNo Return Value: None Error Handling: Called by: NmsDbInit, Reinit (in nms.c) Side Effects: Comments: This function is called only after the local Database Name-Address mapping table has been read and NmsNmhMyMaxVersNo counter initialized (see GetMaxVersNos in nmsdb.c). Also, this function is called only if the counter value is > 0 --*/ { PRPL_CONFIG_REC_T pCnfRec = pWinsCnf->PushInfo.pPushCnfRecs; for ( ; //null expr 1 pCnfRec->WinsAdd.Add.IPAdd != INADDR_NONE; pCnfRec = (PRPL_CONFIG_REC_T)( (LPBYTE) pCnfRec + RPL_CONFIG_REC_SIZE ) ) { // // If the Update count field is invalid, go to the next record // if (pCnfRec->UpdateCount == RPL_INVALID_METRIC) { continue; } pCnfRec->LastVersNo = NmsNmhMyMaxVersNo; } return; } VOID GetPnrInfo( RPL_RR_TYPE_E RRType_e, PWINSCNF_CNF_T pWinsCnf ) /*++ Routine Description: This function is called to read PULL/PUSH records Arguments: RRType_e - Type of Information to read (PULL or PUSH records) pWinsCnf - Configuration structure Externals Used: None Return Value: None Error Handling: Called by: WinsCnfReadPartnerInfo Side Effects: Comments: None --*/ { LONG RetVal; HKEY CnfKey; TCHAR KeyName[20]; // will hold name of subkey of // PULL/PUSH records. These keys are IP // addresses for which 20 is a // big enough size CHAR AscKeyName[20]; DWORD KeyNameSz; FILETIME LastWrite; DWORD BuffSize; HKEY SubKey; DWORD ValTyp; DWORD Sz; PRPL_CONFIG_REC_T paCnfRecs; DWORD NoOfPnrs = 0; //# of valid PULL or PUSH pnrs DWORD NoOfPnrsSv; //# of valid PULL or PUSH pnrs saved DWORD NoOfVals; DWORD InitTime; DWORD IndexOfPnr = 0; //total # of pnrs DWORD RplType; SYSTEMTIME CurrTime; // // Get the current time. It may be needed if we have partners with SpTime // specified. // if (RRType_e == RPL_E_PULL) { GetLocalTime(&CurrTime); } /* * Open the key (PULL/PUSH) */ RetVal = RegOpenKeyEx( sConfigRoot, //predefined key value RRType_e == RPL_E_PULL ? _WINS_CFG_PULL_KEY : _WINS_CFG_PUSH_KEY, //subkey for WINS 0, //must be zero (reserved) KEY_READ, //we desire read access to the keyo &CnfKey //handle to key ); if (RetVal != ERROR_SUCCESS) { CHECK("Is there any need to log this") WINSEVT_LOG_INFO_M( WINS_SUCCESS, RRType_e == RPL_E_PULL ? WINS_EVT_CANT_OPEN_PULL_KEY : WINS_EVT_CANT_OPEN_PUSH_KEY ); } else //key was successfully opened { /* * Query the key. The subkeys are IP addresses of PULL * partners. */ GetKeyInfo( CnfKey, (RRType_e == RPL_E_PULL ? WINSCNF_E_PULL_KEY : WINSCNF_E_PUSH_KEY), &NoOfPnrs, &NoOfVals //ignored ); if (NoOfPnrs == 0) { WINSEVT_LOG_INFO_D_M( WINS_SUCCESS, RRType_e == RPL_E_PULL ? WINS_EVT_NO_SUBKEYS_UNDER_PULL : WINS_EVT_NO_SUBKEYS_UNDER_PUSH ); } else { // // Since we have one or more Partners to replicate with, // read in the value of the InitTimeReplication attribute // of all such Partners // QUERY_VALUE_M( CnfKey, WINSCNF_INIT_TIME_RPL_NM, ValTyp, InitTime, 0, //WINS_EVT_CANT_GET_INITRPL_VAL, DO_INIT_TIME_RPL ); // // Since we have one or more Partners to replicate with, // read in the value of the RplType attribute // QUERY_VALUE_M( CnfKey, WINSCNF_RPL_TYPE_NM, ValTyp, RplType, 0, pWinsCnf->RplType ); #if PRSCONN QUERY_VALUE_M( CnfKey, WINSCNF_PRS_CONN_NM, ValTyp, pWinsCnf->fPrsConn, 0, TRUE ); #endif // // Allocate buffer big enough to hold data for // the number of subkeys found under the PULL key // BuffSize = RPL_CONFIG_REC_SIZE * (NoOfPnrs + 1); WinsMscAlloc( BuffSize, &paCnfRecs); if (RRType_e == RPL_E_PULL) { pWinsCnf->PullInfo.pPullCnfRecs = paCnfRecs; QUERY_VALUE_M( CnfKey, WINSCNF_RETRY_COUNT_NM, ValTyp, pWinsCnf->PullInfo.MaxNoOfRetries, 0, //WINS_EVT_CANT_GET_RETRY_COUNT, WINSCNF_MAX_COMM_RETRIES ); } else { // // Get the value of the field that indicates // whether we should send a trigger when the // address of an owned entry changes. // Sz = sizeof(pWinsCnf->PushInfo.fAddChgTrigger); RetVal = RegQueryValueEx( CnfKey, WINSCNF_ADDCHG_TRIGGER_NM, NULL, //reserved; must be NULL &ValTyp, (LPBYTE)&pWinsCnf->PushInfo.fAddChgTrigger, &Sz ); if (RetVal != ERROR_SUCCESS) { pWinsCnf->PushInfo.fAddChgTrigger = FALSE; } else { pWinsCnf->PushInfo.fAddChgTrigger = (pWinsCnf->PushInfo.fAddChgTrigger >= 1); } QUERY_VALUE_M( CnfKey, WINSCNF_PROP_NET_UPD_NTF, ValTyp, pWinsCnf->PushInfo.PropNetUpdNtf, 0, //no event DO_PROP_NET_UPD_NTF ); pWinsCnf->PushInfo.pPushCnfRecs = paCnfRecs; pWinsCnf->PushInfo.NoPushRecsWValUpdCnt = 0; } /* * For each key, get the values (Time Interval/UpdateCount, * etc) */ NoOfPnrsSv = NoOfPnrs; //save the number that we got from the //GetkeyInfo function for( IndexOfPnr = 0, NoOfPnrs = 0; NoOfPnrs < NoOfPnrsSv; //no of valid pnrs < the total # IndexOfPnr++ ) { KeyNameSz = sizeof(KeyName)/sizeof(TCHAR); //init before every call RetVal = RegEnumKeyEx( CnfKey, IndexOfPnr, //Index Of Pnr KeyName, &KeyNameSz, NULL, //reserved NULL, //don't need class name NULL, //ptr to var. to hold class name &LastWrite //not looked at by us ); if (RetVal != ERROR_SUCCESS) { // // No more ip address keys to get // break; } // // Store pointer to the Wins Config structure in // the configuration record // paCnfRecs->pWinsCnf = pWinsCnf; // // pWinsCnf->MagicNo contains the value of // WinsCnfCnfMagicNo // paCnfRecs->MagicNo = pWinsCnf->MagicNo; paCnfRecs->RRTyp_e = RRType_e; #ifdef UNICODE if (wcstombs(AscKeyName, KeyName, KeyNameSz) == -1) { DBGPRINT0(ERR, "Conversion not possible in the current locale\n"); } AscKeyName[KeyNameSz] = EOS; NONPORT("Call a comm function to do this") paCnfRecs->WinsAdd.Add.IPAdd = inet_addr(AscKeyName); #else paCnfRecs->WinsAdd.Add.IPAdd = inet_addr(KeyName); #endif // // inet_addr returns bytes in network byte order // (Left to Right). Let us convert this into host // order. This will avoid confusion later on. All // formatting functions expect address to be in host // order. // paCnfRecs->WinsAdd.AddLen = COMM_IP_ADD_SIZE; paCnfRecs->WinsAdd.AddTyp_e = COMM_ADD_E_TCPUDPIP; paCnfRecs->WinsAdd.Add.IPAdd = ntohl( paCnfRecs->WinsAdd.Add.IPAdd ); if (COMM_ADDRESS_SAME_M(&NmsLocalAdd, &paCnfRecs->WinsAdd)) { // // Invalid partner. Ignore. NoOfPnrs will // not be incremented. Also, the buffer // pointer stays the same // continue; } RetVal = RegOpenKeyEx( CnfKey, KeyName, 0, //reserved; must be 0 KEY_READ, &SubKey ); if (RetVal != ERROR_SUCCESS) { WINSEVT_LOG_M( WINS_FATAL_ERR, RRType_e == RPL_E_PULL ? WINS_EVT_CANT_OPEN_PULL_SUBKEY : WINS_EVT_CANT_OPEN_PUSH_SUBKEY ); FUTURES("It is possible that the user deleted the key. Recover from this") if (RRType_e == RPL_E_PULL) { pWinsCnf->PullInfo.NoOfPushPnrs = 0; WinsMscDealloc(pWinsCnf->PullInfo.pPullCnfRecs); pWinsCnf->PullInfo.pPullCnfRecs = NULL; } else { pWinsCnf->PushInfo.NoOfPullPnrs = 0; WinsMscDealloc(pWinsCnf->PushInfo.pPushCnfRecs); pWinsCnf->PushInfo.pPushCnfRecs = NULL; } WINS_RAISE_EXC_M(WINS_EXC_CANT_OPEN_KEY); } FUTURES("Maybe, we will support a time interval attribute for Push records") FUTURES("when that is done, LnkRecsWSameMetric would need to be updated") if (RRType_e == RPL_E_PULL) { // // Read in specific time for replication if one // has been specified // GetSpTimeData(SubKey, &CurrTime, &paCnfRecs->fSpTime, &paCnfRecs->SpTimeIntvl); Sz = sizeof(paCnfRecs->TimeInterval); RetVal = RegQueryValueEx( SubKey, WINSCNF_RPL_INTERVAL_NM, NULL, //reserved; must be NULL &ValTyp, (LPBYTE)&paCnfRecs->TimeInterval, &Sz ); if (RetVal != ERROR_SUCCESS) { WINSEVT_LOG_INFO_D_M( WINS_SUCCESS, WINS_EVT_CANT_GET_PULL_TIMEINT ); paCnfRecs->TimeInterval = RPL_INVALID_METRIC; } else // a value was read in { // // If the time interval is less than or // equal to the minimum allowed, use the // default minimum // if (paCnfRecs->TimeInterval < WINSCNF_MIN_VALID_RPL_INTVL) { paCnfRecs->TimeInterval = WINSCNF_MIN_VALID_RPL_INTVL; } if ( (DWORD)paCnfRecs->TimeInterval > pWinsCnf->MaxRplTimeInterval ) { pWinsCnf->MaxRplTimeInterval = paCnfRecs->TimeInterval; } } // // Read in the precedence level. This can currently // be either HIGH (> 0) or LOW (0). // Sz = sizeof(paCnfRecs->MemberPrec); RetVal = RegQueryValueEx( SubKey, WINSCNF_MEMBER_PREC_NM, NULL, //reserved; must be NULL &ValTyp, (LPBYTE)&paCnfRecs->MemberPrec, &Sz ); if (RetVal != ERROR_SUCCESS) { paCnfRecs->MemberPrec = WINSCNF_LOW_PREC; } else { paCnfRecs->MemberPrec = (paCnfRecs->MemberPrec > 0) ? WINSCNF_HIGH_PREC : WINSCNF_LOW_PREC; } #if PRSCONN QUERY_VALUE_M( SubKey, WINSCNF_PRS_CONN_NM, ValTyp, paCnfRecs->fPrsConn, 0, pWinsCnf->fPrsConn ); #endif } else // it is a PUSH record { // // Currently, we don't support periodic // or specific time replication for Push // records // paCnfRecs->fSpTime = FALSE; #if PRSCONN QUERY_VALUE_M( SubKey, WINSCNF_PRS_CONN_NM, ValTyp, paCnfRecs->fPrsConn, 0, pWinsCnf->fPrsConn ); #endif Sz = sizeof(paCnfRecs->UpdateCount); RetVal = RegQueryValueEx( SubKey, WINSCNF_UPDATE_COUNT_NM, NULL, &ValTyp, (LPBYTE)&paCnfRecs->UpdateCount, &Sz ); if (RetVal != ERROR_SUCCESS) { paCnfRecs->UpdateCount = RPL_INVALID_METRIC; } else { paCnfRecs->LastVersNo.QuadPart = 0; #if PRSCONN if (!paCnfRecs->fPrsConn && !sfNoLimitChk) #else if (!sfNoLimitChk) #endif { if (paCnfRecs->UpdateCount < WINSCNF_MIN_VALID_UPDATE_CNT) { paCnfRecs->UpdateCount = WINSCNF_MIN_VALID_UPDATE_CNT; } } else { if (paCnfRecs->UpdateCount == 0) { paCnfRecs->UpdateCount = 1; } } pWinsCnf->PushInfo.NoPushRecsWValUpdCnt++; } } #if MCAST > 0 Sz = sizeof(paCnfRecs->fSelfFnd); RetVal = RegQueryValueEx( SubKey, WINSCNF_SELF_FND_NM, NULL, &ValTyp, (LPBYTE)&paCnfRecs->fSelfFnd, &Sz ); if (RetVal != ERROR_SUCCESS) { paCnfRecs->fSelfFnd = FALSE; } #endif Sz = sizeof(paCnfRecs->fOnlyDynRecs); RetVal = RegQueryValueEx( SubKey, WINSCNF_ONLY_DYN_RECS_NM, NULL, &ValTyp, (LPBYTE)&paCnfRecs->fOnlyDynRecs, &Sz ); if (RetVal != ERROR_SUCCESS) { paCnfRecs->fOnlyDynRecs = FALSE; } QUERY_VALUE_M( SubKey, WINSCNF_RPL_TYPE_NM, ValTyp, paCnfRecs->RplType, 0, pWinsCnf->RplType ); if (paCnfRecs->RplType != 0) { WINSEVT_LOG_INFO_M(paCnfRecs->WinsAdd.Add.IPAdd, WINS_EVT_PARTIAL_RPL_TYPE); } #if PRSCONN if (paCnfRecs->fPrsConn != 0) { paCnfRecs->fPrsConn = TRUE; } #endif REG_M( RegCloseKey(SubKey), WINS_EVT_CANT_CLOSE_KEY, WINS_EXC_CANT_CLOSE_KEY ); // // Initialize the retry count to 0 and the fLinked flag // to FALSE // //used when pulling // paCnfRecs->RetryCount = 0; paCnfRecs->fLinked = FALSE; // // Initialize the following to 0 so that once we stop // communicating with a WINS we can start again when // the following count reaches // WINSCNF_RETRY_AFTER_THIS_MANY_RPL // paCnfRecs->RetryAfterThisManyRpl = 0; #if PRSCONN ECOMM_INIT_DLG_HDL_M(&paCnfRecs->PrsDlgHdl); paCnfRecs->LastCommTime = 0; #endif // // Initialize LastCommFailTime to 0. Used by // SndPushNtf in rplpull.c // paCnfRecs->LastCommFailTime = 0; paCnfRecs->PushNtfTries = 0; // // Link the record with other PULL records with the same // Time Interval // LnkWSameMetricValRecs(pWinsCnf, paCnfRecs); // // Mark the record as permanent (i.e. it will stay // around until a reconfiguration or until the process // terminates // paCnfRecs->fTemp = FALSE; NoOfPnrs++; paCnfRecs = (PRPL_CONFIG_REC_T)( (LPBYTE)paCnfRecs + RPL_CONFIG_REC_SIZE); } // end of for {..} for looping over subkeys of PULL // // GetReplicasNew expects the list to be terminated with a // record with INADDR_NONE as the address // paCnfRecs->WinsAdd.Add.IPAdd = INADDR_NONE; if (RRType_e == RPL_E_PULL) { pWinsCnf->PullInfo.NoOfPushPnrs = NoOfPnrs; pWinsCnf->PullInfo.InitTimeRpl = InitTime; pWinsCnf->PullInfo.RplType = RplType; } else { pWinsCnf->PushInfo.NoOfPullPnrs = NoOfPnrs; pWinsCnf->PushInfo.InitTimePush = InitTime; pWinsCnf->PushInfo.RplType = RplType; // // Now that we are done with the Push record list, //let us sort it on the update count field // // // Sort the array in increasing order of Update Counts // FUTURES("May use qsort to optimize the update notification process") CHECK("Not sure yet whether sorting would optimize it") #if 0 CHECK("this is resulting in compilation warnings. haven't figured out") CHECK("yet why.") qsort( pWinsCnf->pPushCnfRecs, //start of array (size_t)pWinsCnf->NoOfPullPnrs,//no of elements RPL_CONFIG_REC_SIZE, //size of each //element CompUpdCnt //compare func ); #endif } //end of else (It is PULL key) } // end of else (NoOfPnrs == 0) /* * Close the key */ REG_M( RegCloseKey(CnfKey), WINS_EVT_CANT_CLOSE_KEY, WINS_EXC_CANT_CLOSE_KEY ); } //end of else (key could not be opened) #if 0 #ifdef WINSDBG PrintRecs(RRType_e, pWinsCnf); #endif #endif return; } // GetPnrInfo VOID GetOwnerList( PWINSCNF_CNF_T pWinsCnf ) /*++ Routine Description: This function reads the list of owners whose records should be or should not be pulled from a partner WINS. Arguments: Externals Used: None Return Value: Success status codes -- Error status codes -- Error Handling: Called by: Side Effects: Comments: None --*/ { LONG RetVal; DWORD dwValType; // type of the reg value LPSTR pValName; // pointer to the reg LPBYTE pValData; // pointer to the reg value's data DWORD dwValDataLen; // length of the reg value's data DBGENTER("GetOwnerList\n"); // query for the type of persona (grata (1) / non-grata (0)) pWinsCnf->fPersonaGrata = 0; dwValDataLen = sizeof(DWORD); RetVal = RegQueryValueExA( sPartnersKey, // reg key [HKLM\System\CCS\Services\Wins\Partners] WINSCNF_PERSONA_MODE_NM, // name of the value: "PersonaType" NULL, // reserved; must be NULL &dwValType, // type of the value: should get REG_DWORD (LPVOID)&(pWinsCnf->fPersonaGrata), // value data &dwValDataLen); // size of the value's data // if this call didn't succeed, we go on with the default which is 0, 'non-grata' // get the actual entry we're going to pick the list of addresses from pValName = pWinsCnf->fPersonaGrata ? WINSCNF_PERSONA_GRATA_NM : WINSCNF_PERSONA_NON_GRATA_NM; // get the size of the data from the registry // since Sz is 0, if there are any personas // grata/non-grata then we should get ERROR_MORE_DATA // if we get a different error than just remove the current list dwValDataLen = 0; RetVal = RegQueryValueExA( sPartnersKey, // reg key [HKLM\System\CCS\Services\Wins\Partners] pValName, // name of the value: "PersonaList" NULL, // reserved; must be NULL &dwValType, // type of the value: should get REG_MULTI_SZ (LPVOID)&pValData, // dummy address &dwValDataLen); // initially 0 since we try to determine the actual size // this call should return ERROR_MORE_DATA for a REG_MULTI_SZ value // clear-up the old buffer if (pWinsCnf->pPersonaList != NULL) { WinsMscDealloc(pWinsCnf->pPersonaList); } pWinsCnf->NoOfPersona = 0; pWinsCnf->pPersonaList = NULL; // check if there is a valid value, with the expected type; return if not if (RetVal != ERROR_MORE_DATA || dwValType != REG_MULTI_SZ) { DBGLEAVE("GetOwnerList\n"); return; } // allocate the needed buffer WinsMscAlloc(dwValDataLen, &pValData); // now query for the data value with a buffer large enough RetVal = RegQueryValueExA( sPartnersKey, pValName, NULL, // reserved; must be NULL &dwValType, (LPVOID)pValData, // now this is the real address &dwValDataLen); // ERROR_SUCCESS is expected here if (RetVal == ERROR_SUCCESS) { LPBYTE pString = pValData; // count in nAddr the number of addresses in the string for( pWinsCnf->NoOfPersona=0; *pString; pWinsCnf->NoOfPersona++) pString+= strlen(pString)+1; // see if there are any addresses there if (pWinsCnf->NoOfPersona > 0) { COMM_IP_ADD_T IpAdd; // allocate an array of nAddr COMM_ADD_T structures WinsMscAlloc( (pWinsCnf->NoOfPersona) * sizeof(COMM_ADD_T), &(pWinsCnf->pPersonaList)); // loop through the string of addresses and convert // them to COMM_IP_ADD_T structures for (pString = pValData, pWinsCnf->NoOfPersona = 0; *pString; pString += strlen(pString) + 1) { if ((IpAdd = inet_addr(pString)) != -1) { // initialize a COMM_ADD_T structure only if the string token is // indeed an IP address (pWinsCnf->pPersonaList)[pWinsCnf->NoOfPersona].AddTyp_e = COMM_ADD_E_TCPUDPIP; (pWinsCnf->pPersonaList)[pWinsCnf->NoOfPersona].AddLen = COMM_IP_ADD_SIZE; (pWinsCnf->pPersonaList)[pWinsCnf->NoOfPersona].Add.IPAdd = ntohl(IpAdd); DBGPRINT2( DET, "GetOwnerList: Address[%d] = %x\n", pWinsCnf->NoOfPersona, (pWinsCnf->pPersonaList)[pWinsCnf->NoOfPersona].Add.IPAdd); pWinsCnf->NoOfPersona++; } //end 'if valid ip address' } //end 'for each token in the string' // if there are at least two addresses in the list, // sort them in ascending order if (pWinsCnf->NoOfPersona > 1) { qsort(pWinsCnf->pPersonaList, (size_t)pWinsCnf->NoOfPersona, sizeof(COMM_ADD_T), ECommCompareAdd); } else { DBGPRINT0(DET, "GetOwnerList: No valid address found\n"); } //end 'if there are more than two addresses picked up' } //end 'if there are any tokens at all' } //end 'if string could be read successfully from the registry' // the string buffer is no longer needed here WinsMscDealloc(pValData); #ifdef WINSDBG { DWORD tstNAddrs; PCOMM_ADD_T tstPAddrs; DWORD i; DBGPRINT1( DET, "GetOwnerList: Persona %sGrata List:\n", pWinsCnf->fPersonaGrata ? "" : "Non-"); tstNAddrs = pWinsCnf->NoOfPersona; tstPAddrs = pWinsCnf->pPersonaList; for (i = 0; i < tstNAddrs; i++) { DBGPRINT2( DET, "GetOwnerList:PersonaList[%d] = %08x\n", i, tstPAddrs[i].Add.IPAdd); } } #endif DBGLEAVE("GetOwnerList\n"); return; } LONG ReadClusterIp( HKEY KeyHandle, DWORD *IpAddress ) { DWORD Sz; LONG RetVal; DWORD ValTyp; TCHAR DirPath[WINS_MAX_FILENAME_SZ]; *IpAddress = 0; // Read the wins cluster name Sz = WINS_MAX_FILENAME_SZ * sizeof(TCHAR); RetVal = RegQueryValueEx( KeyHandle, WINSCNF_CLUSTER_RESOURCE_NM, NULL, //reserved; must be NULL &ValTyp, (LPBYTE)DirPath, &Sz ); if ((RetVal == ERROR_SUCCESS) && (DirPath[0] != (TCHAR)EOS)) { HCLUSTER hCluster; HRESOURCE hResource; CHAR IpAddressStr[sizeof ("xxx.xxx.xxx.xxx")]; WCHAR IpAddressWStr[sizeof ("xxx.xxx.xxx.xxx")]; DWORD i; HMODULE Dll1, Dll2; #define FUNC_TBL_ENTRY( _Dll, _Name ) { _Dll, &(#_Name)[1], NULL } #define CALL_FUNC( _Func) (PVOID)( *FuncTbl[_Func].FuncHdl ) enum { _OpenCluster, _OpenClusterResource, _CloseCluster, _CloseClusterResource, _ResUtilGetResourceDependentIPAddressProps }; struct { HMODULE *Dll; LPCSTR FuncName; FARPROC FuncHdl; } FuncTbl[] = { FUNC_TBL_ENTRY( &Dll1,_OpenCluster), FUNC_TBL_ENTRY( &Dll1,_OpenClusterResource), FUNC_TBL_ENTRY( &Dll1,_CloseCluster), FUNC_TBL_ENTRY( &Dll1,_CloseClusterResource), FUNC_TBL_ENTRY( &Dll2,_ResUtilGetResourceDependentIPAddressProps) }; DBGPRINT1(DET, "WinsCnfReadWinsInfo: ClusterResourceName is (%ws)\n", DirPath); hCluster = NULL; hResource = NULL; Dll1 = Dll2 = NULL; do { Dll1 = LoadLibrary(TEXT("clusapi.dll")); if (!Dll1) { RetVal = GetLastError(); break; } Dll2 = LoadLibrary(TEXT("resutils.dll")); if (!Dll2) { RetVal = GetLastError(); break; } for (i=0; i<(sizeof(FuncTbl)/sizeof(FuncTbl[0])); i++) { FuncTbl[i].FuncHdl = GetProcAddress(*FuncTbl[i].Dll, FuncTbl[i].FuncName); if (!FuncTbl[i].FuncHdl) { RetVal = GetLastError(); break; } } if (i<(sizeof(FuncTbl)/sizeof(FuncTbl[0]))) { break; } hCluster = CALL_FUNC(_OpenCluster)( NULL ); if (!hCluster) { RetVal = GetLastError(); break; } hResource = CALL_FUNC(_OpenClusterResource)(hCluster, DirPath); if (!hResource) { RetVal = GetLastError(); break; } Sz = sizeof (IpAddressWStr); RetVal = PtrToLong(CALL_FUNC(_ResUtilGetResourceDependentIPAddressProps)( hResource, IpAddressWStr, &Sz, NULL, NULL, NULL, NULL )); if (ERROR_SUCCESS != RetVal) { break; } WinsMscConvertUnicodeStringToAscii((LPBYTE)IpAddressWStr, IpAddressStr, sizeof(IpAddressStr)); *IpAddress = ntohl(inet_addr(IpAddressStr)); DBGPRINT1(DET, "ReadClusterIp: Cluster IpAddress is (%lx)\n", *IpAddress); } while ( FALSE ); if( hResource ) CALL_FUNC(_CloseClusterResource)(hResource); if( hCluster ) CALL_FUNC(_CloseCluster) (hCluster); if ( Dll1 ) FreeLibrary(Dll1); if ( Dll2 ) FreeLibrary(Dll2); } return RetVal; } extern DOM_CACHE_T sDomCache; VOID WinsCnfReadWinsInfo( PWINSCNF_CNF_T pWinsCnf ) /*++ Routine Description: This function reads information (excluding subkeys) about the local WINS Arguments: None Externals Used: sConfigRoot, Return Value: None Error Handling: Called by: WinsCnfInitConfig Side Effects: Comments: None --*/ { DWORD Sz; LONG RetVal; DWORD ValTyp; VERS_NO_T MaxVersNo; WINSEVT_STRS_T EvtStr; TCHAR DirPath[WINS_MAX_FILENAME_SZ]; TCHAR Path2[WINS_MAX_FILENAME_SZ]; LPTSTR pHoldFileName; DWORD fUse351Db; DWORD fUse4Db; EvtStr.NoOfStrs = 1; try { #if defined(DBGSVC) && !defined(WINS_INTERACTIVE) // // Read the value of WinsDbg. Though this value is // being used concurrently by multiple threads (at reinit time), we // don't enter any critical section here. This value // is used only for debugging // WinsCnfReadWinsDbgFlagValue(); #endif Sz = sizeof(pWinsCnf->LogDetailedEvts); (VOID)RegQueryValueEx( sParametersKey, WINSCNF_LOG_DETAILED_EVTS_NM, NULL, //reserved; must be NULL &ValTyp, (LPBYTE)&pWinsCnf->LogDetailedEvts, &Sz ); // Read in the 1B filter. If the "Filter1BRequests" is there and it is a REG_MULTI_SZ // then the filter is created for each of the names specified there. When R_WinsGetBrowserNames // is called, the database is filtered only for the name present in the filter. RetVal = RegQueryValueExW( sParametersKey, WINSCNF_FILTER1BREQUESTS_NM, NULL, &ValTyp, NULL, &Sz); if (RetVal == ERROR_SUCCESS && ValTyp == REG_MULTI_SZ) { LPWSTR str1BFilters = NULL; LPWSTR p1BFilter; WinsMscAlloc(Sz, &str1BFilters); if (RegQueryValueExW( sParametersKey, WINSCNF_FILTER1BREQUESTS_NM, NULL, &ValTyp, (LPBYTE)str1BFilters, &Sz) == ERROR_SUCCESS) { EnterCriticalSection(&g_cs1BFilter); try { g_p1BFilter = InitNmFilter(g_p1BFilter); p1BFilter = str1BFilters; do { DWORD nLenFilter = wcslen(p1BFilter); CHAR strOemName[17]; OEM_STRING oemString; UNICODE_STRING unicodeString; if (nLenFilter == 0) break; memset(strOemName, ' ', 16); strOemName[16]=0; if (nLenFilter > 15) p1BFilter[16]=L'\0'; RtlInitUnicodeString(&unicodeString, p1BFilter); RtlInitString(&oemString, strOemName); RtlUpcaseUnicodeStringToOemString(&oemString, &unicodeString, FALSE); strOemName[strlen(strOemName)] = ' '; strOemName[15] = strOemName[0]; strOemName[0] = 0x1B; InsertNmInFilter(g_p1BFilter, strOemName, 16); p1BFilter += nLenFilter+1; } while(TRUE); } finally { LeaveCriticalSection(&g_cs1BFilter); } } WinsMscDealloc(str1BFilters); } else { // if the reg key is not there, reset the filter - all names will be returned. EnterCriticalSection(&g_cs1BFilter); try { g_p1BFilter = DestroyNmFilter(g_p1BFilter); } finally { g_p1BFilter = NULL; LeaveCriticalSection(&g_cs1BFilter); } } sDomCache.bRefresh = TRUE; // // Read in the fAdd1Bto1CQueries parameter. Default is TRUE // meaning: when processing name queries for 1C names, prepend the // response with the 1B name (browser name). // pWinsCnf->fAdd1Bto1CQueries = TRUE; Sz = sizeof(pWinsCnf->fAdd1Bto1CQueries); (VOID)RegQueryValueEx( sParametersKey, WINSCNF_ADD1BTO1CQUERIES_NM, NULL, &ValTyp, (LPBYTE)&pWinsCnf->fAdd1Bto1CQueries, &Sz ); // // Read in the cap value on the number of worker threads. // QUERY_VALUE_M( sParametersKey, WINSCNF_MAX_NO_WRK_THDS_NM, ValTyp, pWinsCnf->MaxNoOfWrkThds, 0, 0 //WINSTHD_DEF_NO_NBT_THDS ); // // Check if the user needs to override our checks. // sfNoLimitChk = pWinsCnf->MaxNoOfWrkThds & NO_LIMIT_CHK_FLAG; if (sfNoLimitChk) { WINSEVT_LOG_M(pWinsCnf->LogDetailedEvts, WINS_EVT_INTERNAL_FEATURE); pWinsCnf->MaxNoOfWrkThds &= ~NO_LIMIT_CHK_FLAG; } if (pWinsCnf->MaxNoOfWrkThds > WINSTHD_MAX_NO_NBT_THDS) { pWinsCnf->MaxNoOfWrkThds = WINSTHD_MAX_NO_NBT_THDS; } if (pWinsCnf->MaxNoOfWrkThds < WINSTHD_MIN_NO_NBT_THDS) { pWinsCnf->MaxNoOfWrkThds = WINSTHD_MIN_NO_NBT_THDS; } #if 0 if (WinsCnf.State_e == WINSCNF_E_INITING) { ReadSpecGrpMasks(pWinsCnf); } #endif #if DYNLOADJET // // Read in the cap value on the number of worker threads. // QUERY_VALUE_M( sParametersKey, WINSCNF_USE_351DB_NM, ValTyp, fUse351Db, 0, 0 //Use 500 db ); // // If set to a non-zero value, we need to load jet.dll // if (fUse351Db) { DynLoadJetVersion = DYN_LOAD_JET_200; } else { QUERY_VALUE_M( sParametersKey, WINSCNF_USE_4DB_NM, ValTyp, fUse4Db, 0, 0 //Use 500 db ); // // If set to a non-zero value, we need to load jet.dll // if (fUse4Db) { DynLoadJetVersion = DYN_LOAD_JET_500; } } #endif // // Read in the refresh Interval // Sz = sizeof(pWinsCnf->RefreshInterval); RetVal = RegQueryValueEx( sParametersKey, WINSCNF_REFRESH_INTVL_NM, NULL, //reserved; must be NULL &ValTyp, (LPBYTE)&pWinsCnf->RefreshInterval, &Sz ); if (RetVal != ERROR_SUCCESS) { WINSEVT_LOG_INFO_D_M( WINS_SUCCESS, WINS_EVT_CANT_GET_REFRESH_INTERVAL_VAL ); pWinsCnf->RefreshInterval = WINSCNF_DEF_REFRESH_INTERVAL; } else { if (!sfNoLimitChk) { if (pWinsCnf->RefreshInterval < WINSCNF_MIN_REFRESH_INTERVAL) { pWinsCnf->RefreshInterval = WINSCNF_MIN_REFRESH_INTERVAL; WinsEvtLogDetEvt(TRUE, WINS_EVT_ADJ_TIME_INTVL, NULL, __LINE__, "ud", WINSCNF_REFRESH_INTVL_NM, pWinsCnf->RefreshInterval); } } else { if (pWinsCnf->RefreshInterval < 60) { pWinsCnf->RefreshInterval = 60; } } } // // Read in the Initial Challenge Retry Interval // Sz = sizeof(pWinsCnf->RetryInterval); RetVal = RegQueryValueEx( sParametersKey, WINSCNF_INIT_CHL_RETRY_INTVL_NM, NULL, //reserved; must be NULL &ValTyp, (LPBYTE)&pWinsCnf->RetryInterval, &Sz ); if (RetVal != ERROR_SUCCESS) { WINSEVT_LOG_INFO_D_M( WINS_SUCCESS, WINS_EVT_CANT_GET_INIT_CHL_RETRY_INTVL_VAL ); pWinsCnf->RetryInterval = WINSCNF_DEF_INIT_CHL_RETRY_INTVL; } else { if (!sfNoLimitChk) { if (pWinsCnf->RetryInterval < WINSCNF_MIN_INIT_CHL_RETRY_INTVL) { pWinsCnf->RetryInterval = WINSCNF_MIN_INIT_CHL_RETRY_INTVL; WinsEvtLogDetEvt(TRUE, WINS_EVT_ADJ_TIME_INTVL, NULL, __LINE__, "ud", WINSCNF_INIT_CHL_RETRY_INTVL_NM, pWinsCnf->RetryInterval); } } else { if (pWinsCnf->RetryInterval < WINSCNF_MIN_INIT_CHL_RETRY_INTVL) { pWinsCnf->RetryInterval = WINSCNF_MIN_INIT_CHL_RETRY_INTVL; } } } // // Read in the Initial Challenge Max. No. of Retries // Sz = sizeof(pWinsCnf->MaxNoOfRetries); RetVal = RegQueryValueEx( sParametersKey, WINSCNF_CHL_MAX_RETRIES_NM, NULL, //reserved; must be NULL &ValTyp, (LPBYTE)&pWinsCnf->MaxNoOfRetries, &Sz ); if (RetVal != ERROR_SUCCESS) { WINSEVT_LOG_INFO_D_M( WINS_SUCCESS, WINS_EVT_CANT_GET_CHL_MAX_RETRIES_VAL ); pWinsCnf->MaxNoOfRetries = WINSCNF_DEF_CHL_MAX_RETRIES; } else { if (!sfNoLimitChk) { if (pWinsCnf->MaxNoOfRetries < WINSCNF_MIN_CHL_MAX_RETRIES) { pWinsCnf->MaxNoOfRetries = WINSCNF_MIN_CHL_MAX_RETRIES; WinsEvtLogDetEvt(TRUE, WINS_EVT_ADJ_TIME_INTVL, NULL, __LINE__, "ud", WINSCNF_CHL_MAX_RETRIES_NM, pWinsCnf->MaxNoOfRetries); } } else { if (pWinsCnf->MaxNoOfRetries < WINSCNF_MIN_CHL_MAX_RETRIES) { pWinsCnf->MaxNoOfRetries = WINSCNF_MIN_CHL_MAX_RETRIES; } } } // // Read in the tombstone Interval // Sz = sizeof(pWinsCnf->TombstoneInterval); RetVal = RegQueryValueEx( sParametersKey, WINSCNF_TOMBSTONE_INTVL_NM, NULL, //reserved; must be NULL &ValTyp, (LPBYTE)&pWinsCnf->TombstoneInterval, &Sz ); if (RetVal != ERROR_SUCCESS) { WINSEVT_LOG_INFO_D_M( WINS_SUCCESS, WINS_EVT_CANT_GET_TOMBSTONE_INTERVAL_VAL ); pWinsCnf->TombstoneInterval = WINSCNF_MAKE_TOMB_INTVL_0_M(pWinsCnf->RefreshInterval); } else { if ( !sfNoLimitChk) { if (pWinsCnf->TombstoneInterval < WINSCNF_MAKE_TOMB_INTVL_0_M(pWinsCnf->RefreshInterval) ) { pWinsCnf->TombstoneInterval = WINSCNF_MAKE_TOMB_INTVL_0_M(pWinsCnf->RefreshInterval); WinsEvtLogDetEvt(TRUE, WINS_EVT_ADJ_TIME_INTVL, NULL, __LINE__, "ud", WINSCNF_TOMBSTONE_INTVL_NM, pWinsCnf->TombstoneInterval); } } else { if (pWinsCnf->TombstoneInterval < 60) { pWinsCnf->TombstoneInterval = 60; } } } // // Read in the tombstone timeout // Sz = sizeof(pWinsCnf->TombstoneTimeout); RetVal = RegQueryValueEx( sParametersKey, WINSCNF_TOMBSTONE_TMOUT_NM, NULL, //reserved; must be NULL &ValTyp, (LPBYTE)&pWinsCnf->TombstoneTimeout, &Sz ); if (RetVal != ERROR_SUCCESS) { WINSEVT_LOG_INFO_D_M( WINS_SUCCESS, WINS_EVT_CANT_GET_TOMBSTONE_TIMEOUT_VAL ); pWinsCnf->TombstoneTimeout = pWinsCnf->RefreshInterval; } else { if (!sfNoLimitChk) { if (pWinsCnf->TombstoneTimeout < pWinsCnf->RefreshInterval) { pWinsCnf->TombstoneTimeout = pWinsCnf->RefreshInterval; WinsEvtLogDetEvt(TRUE, WINS_EVT_ADJ_TIME_INTVL, NULL, __LINE__, "ud", WINSCNF_TOMBSTONE_TMOUT_NM, pWinsCnf->TombstoneTimeout); } } else { if (pWinsCnf->TombstoneTimeout < 60) { pWinsCnf->TombstoneTimeout = 60; } } } // // Read in the Verify Interval // Sz = sizeof(pWinsCnf->VerifyInterval); RetVal = RegQueryValueEx( sParametersKey, WINSCNF_VERIFY_INTVL_NM, NULL, //reserved; must be NULL &ValTyp, (LPBYTE)&pWinsCnf->VerifyInterval, &Sz ); if (RetVal != ERROR_SUCCESS) { WINSEVT_LOG_INFO_D_M( WINS_SUCCESS, WINS_EVT_CANT_GET_VERIFY_INTERVAL_VAL ); pWinsCnf->VerifyInterval = WINSCNF_MAKE_VERIFY_INTVL_M(pWinsCnf->TombstoneInterval); } else { if ( !sfNoLimitChk) { if (pWinsCnf->VerifyInterval < WINSCNF_MAKE_VERIFY_INTVL_M(pWinsCnf->TombstoneInterval)) { pWinsCnf->VerifyInterval = WINSCNF_MAKE_VERIFY_INTVL_M(pWinsCnf->TombstoneInterval); WinsEvtLogDetEvt(TRUE, WINS_EVT_ADJ_TIME_INTVL, NULL, __LINE__, "ud", WINSCNF_VERIFY_INTVL_NM, pWinsCnf->VerifyInterval); } } else { if (pWinsCnf->VerifyInterval < 60) { pWinsCnf->VerifyInterval = 60; } } } ReadCCInfo(pWinsCnf); // // Check if the admin. wants us to do pull/push replications with // pnrs found by self. // QUERY_VALUE_M( sParametersKey, WINSCNF_BURST_HANDLING_NM, ValTyp, pWinsCnf->fDoSpoofing, 0, TRUE ); if (pWinsCnf->fDoSpoofing) { pWinsCnf->fDoSpoofing = TRUE; //for robustness } #if MCAST > 0 // // Check if the admin. wants us to do pull/push replications with // pnrs found by self. // QUERY_VALUE_M( sParametersKey, WINSCNF_USE_SELF_FND_PNRS_NM, ValTyp, pWinsCnf->fUseSelfFndPnrs, 0, FALSE ); if (pWinsCnf->fUseSelfFndPnrs) { if (WinsCnf.State_e == WINSCNF_E_INITING) { Sz = sizeof(pWinsCnf->McastTtl); RetVal = RegQueryValueEx( sParametersKey, WINSCNF_MCAST_TTL_NM, NULL, &ValTyp, (LPBYTE)&pWinsCnf->McastTtl, &Sz ); if (RetVal != ERROR_SUCCESS) { pWinsCnf->McastTtl = WINSCNF_DEF_MCAST_TTL; } else { if ( (pWinsCnf->McastTtl < WINSCNF_MIN_MCAST_TTL) || (pWinsCnf->McastTtl > WINSCNF_MAX_MCAST_TTL) ) { pWinsCnf->McastTtl = WINSCNF_DEF_MCAST_TTL; } } } Sz = sizeof(pWinsCnf->McastIntvl); RetVal = RegQueryValueEx( sParametersKey, WINSCNF_MCAST_INTVL_NM, NULL, &ValTyp, (LPBYTE)&pWinsCnf->McastIntvl, &Sz ); if (RetVal != ERROR_SUCCESS) { pWinsCnf->McastIntvl = WINSCNF_DEF_MCAST_INTVL; } else { if ( pWinsCnf->McastIntvl < WINSCNF_MIN_MCAST_INTVL ) { pWinsCnf->McastIntvl = WINSCNF_MIN_MCAST_INTVL; } } } #endif // // Check if replication is to be done only with configured partners. // If set to TRUE, it means that an administrator will not be allowed // to trigger replication to/from a WINS that this WINS does not know // about. Default value is FALSE // QUERY_VALUE_M( sParametersKey, WINSCNF_RPL_ONLY_W_CNF_PNRS_NM, ValTyp, pWinsCnf->fRplOnlyWCnfPnrs, 0, TRUE ); // // Robust programming (in case the registry has a value other than 1 // and later on we compare the value with TRUE) // if (pWinsCnf->fRplOnlyWCnfPnrs != FALSE) { pWinsCnf->fRplOnlyWCnfPnrs = TRUE; } if (WinsCnf.State_e == WINSCNF_E_INITING) { (VOID)WinsMscAlloc(WINS_MAX_FILENAME_SZ, &(pWinsCnf->pWinsDb)); // // Read in the name of the database file // FUTURES("when jet supports UNICODE in its api, change this") Sz = WINS_MAX_FILENAME_SZ * sizeof(TCHAR); RetVal = RegQueryValueEx( sParametersKey, WINSCNF_DB_FILE_NM, NULL, //reserved; must be NULL &ValTyp, (LPBYTE)DirPath, &Sz ); if ((RetVal != ERROR_SUCCESS) || (DirPath[0] == (TCHAR)EOS)) { WinsMscDealloc(pWinsCnf->pWinsDb); pWinsCnf->pWinsDb = WINSCNF_DB_NAME_ASCII; } else { if(!WinsMscGetName(ValTyp, DirPath, Path2, WINS_MAX_FILENAME_SZ, &pHoldFileName)) { WinsMscDealloc(pWinsCnf->pWinsDb); pWinsCnf->pWinsDb = WINSCNF_DB_NAME_ASCII; } else { WinsMscConvertUnicodeStringToAscii((LPBYTE)pHoldFileName, pWinsCnf->pWinsDb, WINS_MAX_FILENAME_SZ); DBGPRINT1(DET, "WinsCnfReadWinsInfo: Db file path is (%s)\n", pWinsCnf->pWinsDb); } } RetVal = ReadClusterIp( sParametersKey, &WinsClusterIpAddress ); if (ERROR_SUCCESS == RetVal) { NmsLocalAdd.Add.IPAdd = WinsClusterIpAddress; } else { DBGPRINT1(DET, "ReadClusterIp: Returned (%ld)\n", RetVal); } } // // Read in the PriorityClassHigh value. Default is normal // QUERY_VALUE_M( sParametersKey, WINSCNF_PRIORITY_CLASS_HIGH_NM, ValTyp, pWinsCnf->WinsPriorityClass, 0, WINSINTF_E_NORMAL ); if (pWinsCnf->WinsPriorityClass != WINSINTF_E_NORMAL) { if (WinsCnf.WinsPriorityClass != WINSINTF_E_HIGH) { WinsSetPriorityClass(WINSINTF_E_HIGH); } } else { if (WinsCnf.WinsPriorityClass != WINSINTF_E_NORMAL) { WinsSetPriorityClass(WINSINTF_E_NORMAL); } } if (WinsCnf.State_e == WINSCNF_E_INITING) { // // Read in the InitTimeState value. Default is FALSE // QUERY_VALUE_M( sParametersKey, WINSCNF_INIT_TIME_PAUSE_NM, ValTyp, fWinsCnfInitStatePaused, 0, FALSE ); // // Read in the name of the recovery file // (VOID)WinsMscAlloc(WINS_MAX_FILENAME_SZ, &(pWinsCnf->pLogFilePath)); Sz = WINS_MAX_FILENAME_SZ * sizeof(TCHAR); RetVal = RegQueryValueEx( sParametersKey, WINSCNF_LOG_FILE_PATH_NM, NULL, //reserved; must be NULL &ValTyp, (LPBYTE)DirPath, &Sz ); if ((RetVal != ERROR_SUCCESS) || (DirPath[0] == (TCHAR)EOS)) { DBGPRINT1(ERR, "WinsCnfReadInfo: RetVal=(%x)\n", RetVal); WinsMscDealloc(pWinsCnf->pLogFilePath); pWinsCnf->pLogFilePath = DEFAULT_LOG_PATH; } else { if(!WinsMscGetName(ValTyp, DirPath, Path2, WINS_MAX_FILENAME_SZ, &pHoldFileName)) { DBGPRINT0(ERR, "WinsCnfReadInfo:WinsMscGetName returned FALSE\n"); WinsMscDealloc(pWinsCnf->pLogFilePath); pWinsCnf->pLogFilePath = DEFAULT_LOG_PATH; } else { DBGPRINT1(DET, "WinsCnfReadInfo:pHoldFileName=%s\n", pHoldFileName); WinsMscConvertUnicodeStringToAscii((LPBYTE)pHoldFileName, pWinsCnf->pLogFilePath, WINS_MAX_FILENAME_SZ); } } // // Check if user wants logging to be turned on. // In case of Q servers, the user would not wish the logging to be // turned on // Sz = sizeof(pWinsCnf->fLoggingOn); RetVal = RegQueryValueEx( sParametersKey, WINSCNF_LOG_FLAG_NM, NULL, //reserved; must be NULL &ValTyp, (LPBYTE)&pWinsCnf->fLoggingOn, &Sz ); if (RetVal != ERROR_SUCCESS) { // // default is to turn on logging // pWinsCnf->fLoggingOn = TRUE; } else { // // If user has specified logging, get the path to the log // file if specified by user // if (pWinsCnf->fLoggingOn) { pWinsCnf->fLoggingOn = TRUE; } } } // // Check to see if STATIC initialization of the WINS database needs // to be done // Sz = sizeof(pWinsCnf->fStaticInit); RetVal = RegQueryValueEx( sParametersKey, WINSCNF_STATIC_INIT_FLAG_NM, NULL, //reserved; must be NULL &ValTyp, (LPBYTE)&pWinsCnf->fStaticInit, &Sz ); if (RetVal != ERROR_SUCCESS) { pWinsCnf->fStaticInit = FALSE; } else { // // Safe programming (just in case a maintainer of this code // assumes a BOOL field to have just TRUE and FALSE values // pWinsCnf->fStaticInit = pWinsCnf->fStaticInit > 0 ? TRUE : FALSE; } // // If Static Initialization needs to be done, read in the name of // the file that contains the data. // if(pWinsCnf->fStaticInit) { WinsCnfGetNamesOfDataFiles(pWinsCnf); } // // Assign MaxVersNo with the default value // WINS_ASSIGN_INT_TO_VERS_NO_M(MaxVersNo, 0); // // If the WINS server is just coming up (i.e. it is not a reinit), // then read in the starting value of the version number counter // if present in the registry // Sz = sizeof(DWORD); (VOID)RegQueryValueEx( sParametersKey, WINSCNF_INIT_VERSNO_VAL_LW_NM, NULL, //reserved; must be NULL &ValTyp, (LPBYTE)&MaxVersNo.LowPart, &Sz ); (VOID)RegQueryValueEx( sParametersKey, WINSCNF_INIT_VERSNO_VAL_HW_NM, NULL, //reserved; must be NULL &ValTyp, (LPBYTE)&MaxVersNo.HighPart, &Sz ); // // if we read in a value for the version counter // if (LiGtrZero(MaxVersNo) && (MaxVersNo.HighPart == 0) && (MaxVersNo.LowPart < MAX_START_VERS_NO)) { // // Use WinsCnf, not pWinsCnf since at initialization time, we always // read into WinsCnf. At reinit, the State_e field in the WinsCnf // structure allocated may have garbage (actually will be 0 since we // initialize allocated memory to zero -- I might change in the // future to improve performance) // if (WinsCnf.State_e == WINSCNF_E_INITING) { // // Min. Vers. to start scavenging from. // // NOTE: if we find local records or the special record then // NmsScvMinScvVersNo will get changed (check out GetMaxVersNos // in nmsdb.c // NmsNmhMyMaxVersNo = MaxVersNo; NmsScvMinScvVersNo = NmsNmhMyMaxVersNo; NmsVersNoToStartFromNextTime.QuadPart = LiAdd(NmsNmhMyMaxVersNo, NmsRangeSize); NmsHighWaterMarkVersNo.QuadPart = LiAdd(NmsNmhMyMaxVersNo, NmsHalfRangeSize); } else // this must be a reconfiguration { EnterCriticalSection(&NmsNmhNamRegCrtSec); // // change the value of the version counter if // the new value is more than it. // if (LiGtr(MaxVersNo, NmsNmhMyMaxVersNo)) { NmsNmhMyMaxVersNo = MaxVersNo; WINSEVT_LOG_INFO_M(MaxVersNo.LowPart, WINS_EVT_VERS_COUNTER_CHANGED); } NmsVersNoToStartFromNextTime.QuadPart = LiAdd(NmsNmhMyMaxVersNo, NmsRangeSize); NmsHighWaterMarkVersNo.QuadPart = LiAdd(NmsNmhMyMaxVersNo, NmsHalfRangeSize); LeaveCriticalSection(&NmsNmhNamRegCrtSec); } } if (WinsCnf.State_e == WINSCNF_E_INITING) { // // Check if a port has been assigned by the user. // QUERY_VALUE_M( sParametersKey, WINSCNF_WINS_PORT_NO_NM, ValTyp, CommWinsTcpPortNo, 0, COMM_DEFAULT_IP_PORT ); DBGPRINT1(DET, "WinsCnfReadWinsInfo: Port No is (%d)\n", CommWinsTcpPortNo); // // Check if WINS should continue replication in case of an // error in replication. // QUERY_VALUE_M( sParametersKey, WINSCNF_NO_RPL_ON_ERR_NM, ValTyp, WinsCnf.fNoRplOnErr, 0, TRUE ); // // Assign MaxVersNo with the default value // WINS_ASSIGN_INT_TO_VERS_NO_M(MaxVersNo, 0); // // Read in the value specified in the registry for the version // number that we should use when starting. // Sz = sizeof(DWORD); (VOID)RegQueryValueEx( sConfigRoot, WINSCNF_INT_VERSNO_NEXTTIME_LW_NM, NULL, //reserved; must be NULL &ValTyp, (LPBYTE)&MaxVersNo.LowPart, &Sz ); (VOID)RegQueryValueEx( sConfigRoot, WINSCNF_INT_VERSNO_NEXTTIME_HW_NM, NULL, //reserved; must be NULL &ValTyp, (LPBYTE)&MaxVersNo.HighPart, &Sz ); // // if we read in a value for the version counter and it is greater // than the high-water mark currently there // if (LiGtr(MaxVersNo, NmsHighWaterMarkVersNo)) { fWinsCnfReadNextTimeVersNo = TRUE; // // Use WinsCnf, not pWinsCnf since at initialization time, // we always read into WinsCnf. At reinit, the State_e field // in the WinsCnf structure allocated may have garbage // (actually will be 0 since we initialize allocated memory // to zero -- I might change in the future to improve // performance) // // // Min. Vers. to start scavenging from. // // NOTE: if we find local records or the special record then // NmsScvMinScvVersNo will get changed (check out GetMaxVersNos // in nmsdb.c // if (LiLtr(NmsNmhMyMaxVersNo, MaxVersNo)) { NmsNmhMyMaxVersNo = MaxVersNo; NmsScvMinScvVersNo = NmsNmhMyMaxVersNo; } NmsVersNoToStartFromNextTime.QuadPart = LiAdd(NmsNmhMyMaxVersNo, NmsRangeSize); NmsHighWaterMarkVersNo.QuadPart = LiAdd(NmsNmhMyMaxVersNo, NmsHalfRangeSize); } } //end of if state is INITING // // Check to see if a backup directory has been specified for the WINS // database // // // Read in the name of the recovery file // Sz = WINS_MAX_FILENAME_SZ * sizeof(TCHAR); RetVal = RegQueryValueEx( sParametersKey, WINSCNF_BACKUP_DIR_PATH_NM, NULL, //reserved; must be NULL &ValTyp, (LPBYTE)DirPath, &Sz ); if ((RetVal != ERROR_SUCCESS) || (DirPath[0] == (TCHAR)EOS)) { pWinsCnf->pBackupDirPath = NULL; } else { if(!WinsMscGetName(ValTyp, DirPath, Path2, WINS_MAX_FILENAME_SZ, &pHoldFileName)) { pWinsCnf->pBackupDirPath = NULL; } else { WinsMscAlloc(Sz + sizeof(WINS_BACKUP_DIR_ASCII), &pWinsCnf->pBackupDirPath); FUTURES("When Jet starts taking UNICODE input, get rid of this") WinsMscConvertUnicodeStringToAscii((LPBYTE)pHoldFileName, pWinsCnf->pBackupDirPath, WINS_MAX_FILENAME_SZ); strcat(pWinsCnf->pBackupDirPath, WINS_BACKUP_DIR_ASCII); // // No need to look at the return code. // CreateDirectoryA(pWinsCnf->pBackupDirPath, NULL); } } // // Check to see if the admin. has told WINS to do a backup on // termination // Sz = sizeof(pWinsCnf->fDoBackupOnTerm); RetVal = RegQueryValueEx( sParametersKey, WINSCNF_DO_BACKUP_ON_TERM_NM, NULL, //reserved; must be NULL &ValTyp, (LPBYTE)&pWinsCnf->fDoBackupOnTerm, &Sz ); if (RetVal != ERROR_SUCCESS) { pWinsCnf->fDoBackupOnTerm = FALSE; } // // Check to see if static records have to be treated as p-static // Sz = sizeof(pWinsCnf->fPStatic); RetVal = RegQueryValueEx( sParametersKey, WINSCNF_MIGRATION_ON_NM, NULL, //reserved; must be NULL &ValTyp, (LPBYTE)&pWinsCnf->fPStatic, &Sz ); if (RetVal != ERROR_SUCCESS) { pWinsCnf->fPStatic = FALSE; } // // Read max wins registration que len. // QUERY_VALUE_M( sParametersKey, WINSCNF_BURST_QUE_SIZE_NM, ValTyp, QueOtherNbtWrkQueMaxLen, 0, WINS_QUEUE_HWM ); if (QueOtherNbtWrkQueMaxLen < WINS_QUEUE_HWM_MIN) { QueOtherNbtWrkQueMaxLen = WINS_QUEUE_HWM_MIN; } else if (QueOtherNbtWrkQueMaxLen > WINS_QUEUE_HWM_MAX) { QueOtherNbtWrkQueMaxLen = WINS_QUEUE_HWM_MAX; } // Read whether or not we randomize 1c list retrieval. QUERY_VALUE_M( sParametersKey, WINSCNF_RANDOMIZE_1C_LIST_NM, ValTyp, WinsCnf.fRandomize1CList, 0, FALSE ); } // end of try .. except(EXCEPTION_EXECUTE_HANDLER) { DBGPRINTEXC("WinsCnfReadWinsInfo"); WINSEVT_LOG_M(GetExceptionCode(), WINS_EVT_SFT_ERR); } return; } VOID ReadCCInfo( PWINSCNF_CNF_T pWinsCnf ) /*++ Routine Description: Function to read in CC info Arguments: Externals Used: None Return Value: Success status codes -- Error status codes -- Error Handling: Called by: Side Effects: Comments: None --*/ { SYSTEMTIME CurrTime; DWORD Sz; LONG RetVal; DWORD ValTyp; VERS_NO_T MaxVersNo; WINSEVT_STRS_T EvtStr; DBGENTER("ReadCCInfo\n"); // // Open the Consistency Chk Key // RetVal = RegOpenKeyEx( sConfigRoot, //predefined key value _WINS_CFG_CC_KEY, 0, //must be zero (reserved) KEY_READ | KEY_WRITE, //we desire read/write access // to the key &sCCKey //handle to key ); if (RetVal != ERROR_SUCCESS) { WINSEVT_LOG_INFO_D_M( WINS_SUCCESS, WINS_EVT_CANT_OPEN_CC_KEY ); pWinsCnf->CC.TimeInt = MAXULONG; return; } Sz = sizeof(pWinsCnf->CC.TimeInt); RetVal = RegQueryValueEx( sCCKey, WINSCNF_CC_INTVL_NM, NULL, //reserved; must be NULL &ValTyp, (LPBYTE)&pWinsCnf->CC.TimeInt, &Sz ); if (RetVal != ERROR_SUCCESS) { WINSEVT_LOG_INFO_D_M( WINS_SUCCESS, WINS_EVT_CANT_GET_CC_INTERVAL_VAL ); pWinsCnf->CC.TimeInt = WINSCNF_CC_DEF_INTERVAL; } else { if ( !sfNoLimitChk) { if (pWinsCnf->CC.TimeInt < WINSCNF_CC_MIN_INTERVAL) { pWinsCnf->CC.TimeInt = WINSCNF_CC_MIN_INTERVAL; WinsEvtLogDetEvt(TRUE, WINS_EVT_ADJ_TIME_INTVL, NULL, __LINE__, "ud", WINSCNF_CC_INTVL_NM, pWinsCnf->CC.TimeInt); } } else { if (pWinsCnf->CC.TimeInt < 60) { pWinsCnf->CC.TimeInt = 60; } } } Sz = sizeof(pWinsCnf->CC.MaxRecsAAT); RetVal = RegQueryValueEx( sCCKey, WINSCNF_CC_MAX_RECS_AAT_NM, NULL, //reserved; must be NULL &ValTyp, (LPBYTE)&pWinsCnf->CC.MaxRecsAAT, &Sz ); if (RetVal != ERROR_SUCCESS) { WINSEVT_LOG_INFO_D_M( WINS_SUCCESS, WINS_EVT_CANT_GET_CC_MAX_RECS_AAT_VAL ); pWinsCnf->CC.MaxRecsAAT = WINSCNF_CC_DEF_RECS_AAT; } else { if (pWinsCnf->CC.MaxRecsAAT < WINSCNF_CC_MIN_RECS_AAT) { if ( !sfNoLimitChk) { WinsEvtLogDetEvt(TRUE, WINS_EVT_ADJ_MAX_RECS_AAT, NULL, __LINE__, "udd", WINSCNF_CC_MAX_RECS_AAT_NM, WINSCNF_CC_MIN_RECS_AAT, pWinsCnf->CC.MaxRecsAAT); pWinsCnf->CC.MaxRecsAAT = WINSCNF_CC_MIN_RECS_AAT; } else { if (pWinsCnf->CC.MaxRecsAAT < 2) { pWinsCnf->CC.MaxRecsAAT = 2; } } } } Sz = sizeof(pWinsCnf->CC.fUseRplPnrs); RetVal = RegQueryValueEx( sCCKey, WINSCNF_CC_USE_RPL_PNRS_NM, NULL, //reserved; must be NULL &ValTyp, (LPBYTE)&pWinsCnf->CC.fUseRplPnrs, &Sz ); if (RetVal != ERROR_SUCCESS) { WINSEVT_LOG_INFO_D_M( WINS_SUCCESS, WINS_EVT_CANT_GET_CC_USE_RPL_PNRS_VAL ); pWinsCnf->CC.fUseRplPnrs = WINSCNF_CC_DEF_USE_RPL_PNRS; } GetLocalTime(&CurrTime); GetSpTimeData(sCCKey, &CurrTime, &pWinsCnf->CC.fSpTime, &pWinsCnf->CC.SpTimeInt); REG_M( RegCloseKey(sCCKey), WINS_EVT_CANT_CLOSE_KEY, WINS_EXC_CANT_CLOSE_KEY ); DBGLEAVE("ReadCCInfo\n"); return; } #if USENETBT > 0 //------------------------------------------------------------------------ STATUS WinsCnfReadNbtDeviceName( VOID ) /*++ Routine Description: This procedure reads the registry to get the name of NBT to bind to. That name is stored in the Linkage section under the Netbt key. Arguments: Return Value: 0 if successful, -1 otherwise. --*/ { PTCHAR SubKeyLinkage=NETBT_LINKAGE_KEY; HKEY Key; PTCHAR pLinkage=TEXT("Export"); LONG Type; LONG Status; LONG Status2; ULONG Size; // // Open the NETBT key // Status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, SubKeyLinkage, 0, KEY_READ, &Key); if (Status == ERROR_SUCCESS) { // // now read the linkage values // Status = RegQueryValueEx(Key, pLinkage, NULL, &Type, NULL, &Size); if (Status != ERROR_SUCCESS) { DBGPRINT0(ERR, "Error closing the Registry key\n"); WINSEVT_LOG_M(Status, WINS_EVT_QUERY_NETBT_KEY_ERR); (VOID)RegCloseKey(Key); return(WINS_FAILURE); } else { // // Let us allocate a buffer that is big enough to hold all the // data // WinsMscAlloc(Size, (LPVOID *)&pWinsCnfNbtPath); // // now read the linkage values // Status = RegQueryValueEx(Key, pLinkage, NULL, &Type, (LPBYTE)pWinsCnfNbtPath, &Size); Status2 = RegCloseKey(Key); if ((Status != ERROR_SUCCESS) || (Status2 != ERROR_SUCCESS)) { DBGPRINT0(ERR, "Error closing the Registry key\n"); WINSEVT_LOG_M(Status, WINS_EVT_QUERY_NETBT_KEY_ERR); return(WINS_FAILURE); } } } else { WINSEVT_LOG_D_M(Status, WINS_EVT_OPEN_NETBT_KEY_ERR); return(WINS_FAILURE); } return(WINS_SUCCESS); } #endif VOID WinsCnfReadRegInfo( PWINSCNF_CNF_T pWinsCnf ) /*++ Routine Description: This function is called to read the registry in order to populate the WinsCnf structure Arguments: None Externals Used: None Return Value: None Error Handling: Called by: WinsCnfInitConfig Side Effects: Comments: None --*/ { try { if (sfParametersKeyExists) { /* Read in the registry information pertaining to WINS */ WinsCnfReadWinsInfo(pWinsCnf); } if (sfPartnersKeyExists) { // // Read the PUSH/PULL records and other global information used for // replication // WinsCnfReadPartnerInfo(pWinsCnf); } // // Do a sanity check on the params. We are not interested in the // return code // (VOID)SanityChkParam(pWinsCnf); } except(EXCEPTION_EXECUTE_HANDLER) { DBGPRINTEXC("WinsCnfReadRegInfo"); // // If we encountered an exception at boot time, we do not want to // reraise the exception, since we want to come up and continue on // For the non-initing case, the exception that we raise will be caught // in Reinit(). For the boot time case, it is ok to come up with the // defaults (an event message is being logged) - in WinsCnf. // In the non-init case, the defaults are not in the memory used to // read in the parameters (WinsCnf is initialized with stuff in // this memory block later). // if (WinsCnf.State_e != WINSCNF_E_INITING) { WINS_RERAISE_EXC_M(); } WINSEVT_LOG_M(GetExceptionCode(), WINS_EVT_RECONFIG_ERR); } return; } VOID WinsCnfCopyWinsCnf( WINS_CLIENT_E Client_e, PWINSCNF_CNF_T pSrc ) /*++ Routine Description: This function is called to copy relevant information from a WINS Cnf structure to the master (external) Wins Cnf structure Arguments: pSrc - WinsCnf stucture to copy from Externals Used: WinsCnf Return Value: None Error Handling: Called by: RplPullInit Side Effects: Comments: This function may be enhanced in the future Note: this function is called only by the main thread --*/ { BOOL fScvParamChg = FALSE; if (Client_e == WINS_E_WINSCNF) { FUTURES("Queue a message to the Scavenger thread passing it pSrc") FUTURES("That will avoid this synchronization overhead") // // We need to synchronize with the scavenger thread and // RPC threads that might be looking at fRplOnlyWCnfPnrs // EnterCriticalSection(&WinsCnfCnfCrtSec); // // Also need to synchronize with the nbt threads doing // name registrations/refreshes // EnterCriticalSection(&NmsNmhNamRegCrtSec); // // Sanity check the parameters // fScvParamChg = SanityChkParam(pSrc); if (fScvParamChg) { // // Initialize the scavenging stuff. // WinsCnf.RefreshInterval = pSrc->RefreshInterval; WinsCnf.TombstoneInterval = pSrc->TombstoneInterval; WinsCnf.TombstoneTimeout = pSrc->TombstoneTimeout; WinsCnf.CC = pSrc->CC; WinsCnf.ScvThdPriorityLvl = pSrc->ScvThdPriorityLvl; } // // Store the verify interval since SanityChkParam does // not set fScvParamChg if VerifyINterval has changed. // WinsCnf.VerifyInterval = pSrc->VerifyInterval; WinsCnf.fRplOnlyWCnfPnrs = pSrc->fRplOnlyWCnfPnrs; WinsCnf.LogDetailedEvts = pSrc->LogDetailedEvts; WinsCnf.fAdd1Bto1CQueries = pSrc->fAdd1Bto1CQueries; WinsCnf.fPStatic = pSrc->fPStatic; LeaveCriticalSection(&NmsNmhNamRegCrtSec); WinsCnf.fDoSpoofing = pSrc->fDoSpoofing; WinsCnf.MaxNoOfWrkThds = pSrc->MaxNoOfWrkThds; WinsCnf.fDoBackupOnTerm = pSrc->fDoBackupOnTerm; #if MCAST > 0 WinsCnf.fUseSelfFndPnrs = pSrc->fUseSelfFndPnrs; WinsCnf.McastIntvl = pSrc->McastIntvl; #endif #if PRSCONN WinsCnf.fPrsConn = pSrc->fPrsConn; #endif if (WinsCnf.fDoBackupOnTerm && pSrc->pBackupDirPath != NULL) { if (WinsCnf.pBackupDirPath != NULL) { WinsMscDealloc(WinsCnf.pBackupDirPath); } WinsCnf.pBackupDirPath = pSrc->pBackupDirPath; } LeaveCriticalSection(&WinsCnfCnfCrtSec); // return; } else { if (Client_e == WINS_E_RPLPULL) { EnterCriticalSection(&WinsCnfCnfCrtSec); // // Copy the Scavenging parameters into the cnf structure // just allocated so that we can compare them for // compatibility with the new max. replication time interval // (since the Partners key was signaled, the replication // stuff might have changed) // pSrc->RefreshInterval = WinsCnf.RefreshInterval; pSrc->TombstoneInterval = WinsCnf.TombstoneInterval; pSrc->TombstoneTimeout = WinsCnf.TombstoneTimeout; pSrc->VerifyInterval = WinsCnf.VerifyInterval; // // Wasteful here and in SanityChkParam // PERF("Pass an argument to SanityChk so that we don't have to do this") PERF("See similar remark in SanityChk") pSrc->CC = WinsCnf.CC; // // Sanity check the parameters. // // Sanity checking of the parameters is done here in // the main thread instead of in the PULL thread because // we don't want a situation where two different threads // (the main thread for changes to the PARAMETERS key) // and the PULL thread (for changes in the PARTNERS key) // updating the WinsCnf structure // // Also, as an aside, we don't copy the PullInfo information // into WinsCnf here to avoid unnecessary complication and // synchronization that would ensue by the fact that we // would then have two threads (main thread) and the PULL // thread accessing that field (check Reconfig() in // rplpull.c). // FUTURES("When we start supporting time interval as an attribute of PUSHing") FUTURES("move this check inside the NmsNmhNamRegCrtSec below") fScvParamChg = SanityChkParam(pSrc); // // If one or more scavenging parameters have changed, // update WinsCnf and signal the Scavenger thread. // if (fScvParamChg) { WinsCnf.RefreshInterval = pSrc->RefreshInterval; WinsCnf.TombstoneInterval = pSrc->TombstoneInterval; WinsCnf.TombstoneTimeout = pSrc->TombstoneTimeout; // // If SanityChkParam changed Tombstone interval, then // verify interval has also changed. // WinsCnf.VerifyInterval = pSrc->VerifyInterval; } WinsCnf.MaxRplTimeInterval = pSrc->MaxRplTimeInterval; WinsCnf.RplType = pSrc->RplType; LeaveCriticalSection(&WinsCnfCnfCrtSec); } } // // If the scavenging params have changed we need to signal // the scavenger thread // if (fScvParamChg) { WinsMscSignalHdl(WinsCnf.CnfChgEvtHdl); } return; } LPVOID WinsCnfGetNextRplCnfRec( PRPL_CONFIG_REC_T pCnfRec, RPL_REC_TRAVERSAL_E RecTrv_e ) /*++ Routine Description: This function is called to get to the next configuration record Arguments: pCnfRec - The current configuration record in a buffer of configuration records RecTrv_e - indicates how the next one should be retrieved. If set to TRUE, it means that the next record to be retrieved is one that follows the current record in the buffer. If set to FALSE, the next record is retrieved using the pNext field of the current configuration record Externals Used: None Return Value: address of the next configuration record Error Handling: Called by: EstablishComm in rplpull.c, WinsPushTrigger() in wins.c Side Effects: Comments: None --*/ { // // If no traversal is desired, return NULL as the next record // if (RecTrv_e == RPL_E_NO_TRAVERSAL) { return(NULL); } // // Go to the next configuration record in a way specified // by the value of the RecTrv_e flag. // if(RecTrv_e == RPL_E_IN_SEQ) { pCnfRec = (PRPL_CONFIG_REC_T)( (LPBYTE)pCnfRec + RPL_CONFIG_REC_SIZE); } else // RPL_E_VIA_LINK { return(pCnfRec->pNext); } return(pCnfRec); } VOID WinsCnfAskToBeNotified( WINSCNF_KEY_E KeyToMonitor_e ) /*++ Routine Description: This function is called to request that WINS be notified when the information pertaining to WINS and its subkeys in the registry changes Arguments: KeyToMonitor_e Externals Used: None Return Value: None Error Handling: Called by: Reinit() in nms.c WinsCnfOpenSubKeys() WinsCnfInitConfig() Side Effects: Comments: None --*/ { DWORD NotifyFilter = 0; LONG RetVal; DWORD Error; #define CHK_RET_VAL_M { \ if (RetVal != ERROR_SUCCESS) \ { \ DBGPRINT1(ERR, "WinsAskToBeNotified: Error = (%d)\n", RetVal); \ WINSEVT_LOG_M( \ WINS_FATAL_ERR, \ WINS_EVT_REG_NTFY_FN_ERR \ ); \ } \ } /* * Set the notify filter. Ask to be notified for all changes. */ NotifyFilter = REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_ATTRIBUTES | REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_SECURITY ; switch(KeyToMonitor_e) { case(WINSCNF_E_WINS_KEY): // DBGPRINT0(SPEC, "WinsCnfAskToBeNotified: WINS Key\n"); RetVal = RegNotifyChangeKeyValue( sConfigRoot, TRUE, //report changes in key and all subkeys REG_NOTIFY_CHANGE_NAME, WinsCnf.WinsKChgEvtHdl, TRUE //Async signaling is what we want ); CHK_RET_VAL_M; break; case(WINSCNF_E_PARAMETERS_KEY): // DBGPRINT0(SPEC, "WinsCnfAskToBeNotified: PARAMETERS Key\n"); RetVal = RegNotifyChangeKeyValue( sParametersKey, TRUE, //report changes in key and all subkeys NotifyFilter, WinsCnf.ParametersKChgEvtHdl, TRUE //Async signaling is what we want ); CHK_RET_VAL_M; break; case(WINSCNF_E_PARTNERS_KEY): // DBGPRINT0(SPEC, "WinsCnfAskToBeNotified: PARTNERS Key\n"); RetVal = RegNotifyChangeKeyValue( sPartnersKey, TRUE, //report changes in key and all subkeys NotifyFilter, WinsCnf.PartnersKChgEvtHdl, TRUE //Async signaling is what we want ); CHK_RET_VAL_M; break; FUTURES("Remove the following case") // // The following case would never get exercised. // case(WINSCNF_E_ALL_KEYS): RetVal = RegNotifyChangeKeyValue( sConfigRoot, TRUE, //report changes in key and all subkeys REG_NOTIFY_CHANGE_NAME, WinsCnf.WinsKChgEvtHdl, TRUE //Async signaling is what we want ); CHK_RET_VAL_M; if (sfParametersKeyExists) { RetVal = RegNotifyChangeKeyValue( sParametersKey, TRUE, //report changes in key and //all subkeys NotifyFilter, WinsCnf.ParametersKChgEvtHdl, TRUE //Async signaling is what we // want ); if (RetVal != ERROR_SUCCESS) { Error = GetLastError(); if (Error == ERROR_BADKEY) { // // Key must not be there // sfParametersKeyExists = FALSE; } else { DBGPRINT1(ERR, "WinsCnfAskToBeNotified: RegNotifyChangeKeyValue error = (%d)\n", Error); } } } if (sfPartnersKeyExists) { RetVal = RegNotifyChangeKeyValue( sPartnersKey, TRUE, //report changes in key and //all subkeys NotifyFilter, WinsCnf.PartnersKChgEvtHdl, TRUE //Async signaling is what we //want ); if (RetVal != ERROR_SUCCESS) { Error = GetLastError(); if (Error == ERROR_BADKEY) { // // Key must not be there // sfPartnersKeyExists = FALSE; } else { DBGPRINT1(ERR, "WinsCnfAskToBeNotified: RegNotifyChangeKeyValue error = (%d)\n", Error); } } } break; default: DBGPRINT1(ERR, "WinsCnfAskToBeNotified: Wrong Hdl (%d)\n", KeyToMonitor_e); WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_SFT_ERR); WINS_RAISE_EXC_M(WINS_EXC_FAILURE); break; } return; } VOID WinsCnfDeallocCnfMem( PWINSCNF_CNF_T pWinsCnf ) /*++ Routine Description: This function is called to deallocate the Wins Cnf structure and memory associated with it Arguments: Externals Used: None Return Value: None Error Handling: Called by: Reconfig in rplpull.c Side Effects: Comments: None --*/ { try { // // Deallocate the buffer holding one or more names of files used // for STATIC initialization of WINS // if (pWinsCnf->pStaticDataFile != NULL) { WinsMscDealloc(pWinsCnf->pStaticDataFile); } WinsMscDealloc(pWinsCnf); } except(EXCEPTION_EXECUTE_HANDLER) { DBGPRINTEXC("WinsCnfDeallocCnfMem"); DBGPRINT0(EXC, "WinsCnfDeallocCnfMem: Got an exception\n"); WINSEVT_LOG_M(GetExceptionCode(), WINS_EVT_RECONFIG_ERR); } return; } VOID GetKeyInfo( IN HKEY Key, IN WINSCNF_KEY_E KeyType_e, OUT LPDWORD pNoOfSubKeys, OUT LPDWORD pNoOfVals ) /*++ Routine Description: This function is called to get the number of subkeys under a key Arguments: Key - Key whose subkey count has to be determined KeyType_e pNoOfSubKeys Externals Used: None Return Value: None Error Handling: Called by: GetPnrInfo() Side Effects: Comments: None --*/ { TCHAR ClsStr[40]; DWORD ClsStrSz = sizeof(ClsStr); DWORD LongestKeyLen; DWORD LongestKeyClassLen; DWORD LongestValueNameLen; DWORD LongestValueDataLen; DWORD SecDesc; LONG RetVal; FILETIME LastWrite; /* Query the key. The subkeys are IP addresses of PULL partners. */ RetVal = RegQueryInfoKey( Key, ClsStr, &ClsStrSz, NULL, //must be NULL, reserved pNoOfSubKeys, &LongestKeyLen, &LongestKeyClassLen, pNoOfVals, &LongestValueNameLen, &LongestValueDataLen, &SecDesc, &LastWrite ); if (RetVal != ERROR_SUCCESS) { WINSEVT_LOG_M( WINS_FATAL_ERR, KeyType_e == WINSCNF_E_DATAFILES_KEY ? WINS_EVT_CANT_QUERY_DATAFILES_KEY : ((KeyType_e == WINSCNF_E_PULL_KEY) ? WINS_EVT_CANT_QUERY_PULL_KEY : ((KeyType_e == WINSCNF_E_PUSH_KEY) ? WINS_EVT_CANT_QUERY_PUSH_KEY : WINS_EVT_CANT_QUERY_SPEC_GRP_MASKS_KEY)) ); WINS_RAISE_EXC_M(WINS_EXC_CANT_QUERY_KEY); } return; } VOID WinsCnfOpenSubKeys( VOID ) /*++ Routine Description: This function opens the subkeys of the WINS key. The subkeys are the PARTNERS key and the PARAMETERS key. Arguments: None Externals Used: sfParamatersKeyExists sfPartnersKeyExists Return Value: None Error Handling: Called by: WinsCnfInitConfig() Side Effects: Comments: None --*/ { LONG RetVal; // // Check if the Parameters and Partners Keys are present // ChkWinsSubKeys(); // // Try to open the Parameters key if it exists // if ((sfParametersKeyExists) && (!sfParametersKeyOpen)) { /* * Open the Parameters key */ RetVal = RegOpenKeyEx( sConfigRoot, //predefined key value _WINS_CFG_PARAMETERS_KEY, 0, //must be zero (reserved) KEY_READ | KEY_WRITE, //we desire read/write access // to the key &sParametersKey //handle to key ); if (RetVal != ERROR_SUCCESS) { CHECK("Is there any need to log this") WINSEVT_LOG_INFO_M( WINS_SUCCESS, WINS_EVT_CANT_OPEN_PARAMETERS_KEY ); sfParametersKeyExists = FALSE; } else { sfParametersKeyOpen = TRUE; WinsCnfAskToBeNotified(WINSCNF_E_PARAMETERS_KEY); } } // // Try to open the Partners key if it exists // if ((sfPartnersKeyExists) && (!sfPartnersKeyOpen)) { /* * Open the Partners key */ RetVal = RegOpenKeyEx( sConfigRoot, //predefined key value _WINS_CFG_PARTNERS_KEY, 0, //must be zero(reserved) KEY_READ, //we desire read //access to the key &sPartnersKey //handle to key ); if (RetVal != ERROR_SUCCESS) { CHECK("Is there any need to log this") WINSEVT_LOG_INFO_M( WINS_SUCCESS, WINS_EVT_CANT_OPEN_KEY ); sfPartnersKeyExists = FALSE; } else { sfPartnersKeyOpen = TRUE; WinsCnfAskToBeNotified(WINSCNF_E_PARTNERS_KEY); } } return; } //WinsCnfOpenSubKeys() BOOL SanityChkParam( PWINSCNF_CNF_T pWinsCnf ) /*++ Routine Description: This function is called to ensure that the time intervals for scavenging specified in WinsCnf are compatible with the ones used for replication Arguments: pWinsCnf - ptr to the WINS configuration Externals Used: None Return Value: None Error Handling: Called by: WinsCnfCopyWinsCnf (during reinitialization of the WINS), by WinsCnfReadRegInfo() during initialization of the WINS Side Effects: The scavenging intervals could be affected Comments: This function must be called from inside the critical section guarded by WinsCnfCnfCrtSec except at process initialization. --*/ { DWORD MinTombInterval; BOOL fScvParamChg = FALSE; WINSEVT_STRS_T EvtStr; EvtStr.NoOfStrs = 1; DBGENTER("SanityChkParam\n"); // // Get the minimum tombstone time interval // MinTombInterval = WINSCNF_MAKE_TOMB_INTVL_M(pWinsCnf->RefreshInterval, pWinsCnf->MaxRplTimeInterval); // // Make the actual equal to the min. if it is less // if (!sfNoLimitChk && (pWinsCnf->TombstoneInterval < MinTombInterval)) { DBGPRINT2(FLOW, "SanityChkParam: Adjusting Tombstone Interval from (%d) to (%d)\n", pWinsCnf->TombstoneInterval, MinTombInterval); FUTURES("This is actually a warning. Use a different macro or enhance it") FUTURES("Currently, it will log this message as an informational") WinsEvtLogDetEvt(TRUE, WINS_EVT_ADJ_TIME_INTVL_R, NULL, __LINE__, "ud", WINSCNF_TOMBSTONE_INTVL_NM, MinTombInterval ); pWinsCnf->TombstoneInterval = MinTombInterval; // // Verify Interval is dependent on the tombstone interval // pWinsCnf->VerifyInterval = WINSCNF_MAKE_VERIFY_INTVL_M(MinTombInterval); fScvParamChg = TRUE; } // // reusing the var. The time interval is for tombstone timeout // MinTombInterval = WINSCNF_MAKE_TOMBTMOUT_INTVL_M(pWinsCnf->MaxRplTimeInterval); if (!sfNoLimitChk && (pWinsCnf->TombstoneTimeout < MinTombInterval)) { DBGPRINT2(FLOW, "SanityChkParam: Adjusting Tombstone Timeout from (%d) to (%d)\n", pWinsCnf->TombstoneInterval, MinTombInterval); pWinsCnf->TombstoneTimeout = MinTombInterval; WinsEvtLogDetEvt(TRUE, WINS_EVT_ADJ_TIME_INTVL_R, NULL, __LINE__, "ud", WINSCNF_TOMBSTONE_TMOUT_NM, MinTombInterval ); if (!fScvParamChg) { fScvParamChg = TRUE; } } if (!fScvParamChg) { PERF("Pass an argument to SanityChk so that we don't have to do this") PERF("for CC for the case where we just read the partner info. See") PERF("WinsCnfCopyWinsCnf for the case where client_e is WINS_E_RPLPULL") if ( (WinsCnf.RefreshInterval != pWinsCnf->RefreshInterval) || (WinsCnf.TombstoneInterval != pWinsCnf->TombstoneInterval) || (WinsCnf.TombstoneTimeout != pWinsCnf->TombstoneTimeout) || (WinsCnf.CC.TimeInt != pWinsCnf->CC.TimeInt) || (WinsCnf.CC.SpTimeInt != pWinsCnf->CC.SpTimeInt) || (WinsCnf.CC.fUseRplPnrs != pWinsCnf->CC.fUseRplPnrs) || (WinsCnf.CC.MaxRecsAAT != pWinsCnf->CC.MaxRecsAAT) ) { fScvParamChg = TRUE; } } DBGLEAVE("SanityChkParam\n"); return(fScvParamChg); } STATUS WinsCnfGetNamesOfDataFiles( PWINSCNF_CNF_T pWinsCnf ) /*++ Routine Description: This function gets the names of all the datafiles that need to be used for initializing WINS. Arguments: Externals Used: None Return Value: Success status codes -- WINS_SUCCESS Error status codes -- WINS_FAILURE Error Handling: Called by: Side Effects: Comments: None --*/ { LONG RetVal; HKEY DFKey; DWORD BuffSize; STATUS RetStat = WINS_SUCCESS; PWINSCNF_DATAFILE_INFO_T pSaveDef; DWORD NoOfSubKeys; DBGENTER("WinsCnfGetNamesOfDataFiles\n"); // // Store timestamp of initialization in the statistics structure // WinsIntfSetTime(NULL, WINSINTF_E_INIT_DB); // // Set up the default name // // // First allocate the buffer that will hold the default file name // WinsMscAlloc(WINSCNF_FILE_INFO_SZ, &pWinsCnf->pStaticDataFile); lstrcpy(pWinsCnf->pStaticDataFile->FileNm, WINSCNF_STATIC_DATA_NAME); // // The default name contains a %% in it. Therefore, specify // the type as EXPAND_SZ // pWinsCnf->pStaticDataFile->StrType = REG_EXPAND_SZ; pWinsCnf->NoOfDataFiles = 1; pSaveDef = pWinsCnf->pStaticDataFile; //save the address /* * Open the DATAFILES key */ RetVal = RegOpenKeyEx( sConfigRoot, //predefined key value _WINS_CFG_DATAFILES_KEY, 0, //must be zero (reserved) KEY_READ, //we desire read access to the keyo &DFKey //handle to key ); if (RetVal != ERROR_SUCCESS) { CHECK("Is there any need to log this") WINSEVT_LOG_INFO_M( WINS_SUCCESS, WINS_EVT_CANT_OPEN_DATAFILES_KEY ); DBGLEAVE("WinsCnfGetNamesOfDataFiles\n"); return(FALSE); } else try { { // // Get the count of data files listed under the DATAFILES // key // GetKeyInfo( DFKey, WINSCNF_E_DATAFILES_KEY, &NoOfSubKeys, //ignored &pWinsCnf->NoOfDataFiles ); } if (pWinsCnf->NoOfDataFiles > 0) { DWORD Index; PWINSCNF_DATAFILE_INFO_T pTmp; TCHAR ValNmBuff[MAX_PATH]; DWORD ValNmBuffSz = MAX_PATH; // // Allocate buffer big enough to hold data for // the number of subkeys found under the PULL key // BuffSize = WINSCNF_FILE_INFO_SZ * pWinsCnf->NoOfDataFiles; WinsMscAlloc( BuffSize, &pWinsCnf->pStaticDataFile); /* * Enumerate the values */ for( Index = 0, pTmp = pWinsCnf->pStaticDataFile; Index < pWinsCnf->NoOfDataFiles; // no third expression ) { ValNmBuffSz = sizeof(ValNmBuff)/sizeof(TCHAR); //init before //every call BuffSize = sizeof(pWinsCnf->pStaticDataFile->FileNm); RetVal = RegEnumValue( DFKey, Index, //key ValNmBuff, &ValNmBuffSz, (LPDWORD)NULL, //reserved &pTmp->StrType, (LPBYTE)(pTmp->FileNm),//ptr to var. to //hold name of //datafile &BuffSize //not looked at by us ); if (RetVal != ERROR_SUCCESS) { continue; } // // if StrType is not REG_SZ or REG_EXPAND_SZ, go to // the next Value // if ( (pTmp->StrType != REG_EXPAND_SZ) && (pTmp->StrType != REG_SZ) ) { continue; } Index++; pTmp = (PWINSCNF_DATAFILE_INFO_T)((LPBYTE)pTmp + WINSCNF_FILE_INFO_SZ); } // // If not even one valid name was retrieved, get rid of the // buffer // if (Index == 0) { // // Get rid of the buffer // WinsMscDealloc((LPBYTE)pWinsCnf->pStaticDataFile); // // We will use the default // pWinsCnf->pStaticDataFile = pSaveDef; } else { // // Get rid of the default name buffer // WinsMscDealloc((LPBYTE)pSaveDef); } pWinsCnf->NoOfDataFiles = Index; } } // end of try .. except (EXCEPTION_EXECUTE_HANDLER) { DBGPRINTEXC("WinsCnfGetNamesOfDataFiles"); WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_SFT_ERR); RetStat = WINS_FAILURE; } REG_M( RegCloseKey(DFKey), WINS_EVT_CANT_CLOSE_KEY, WINS_EXC_CANT_CLOSE_KEY ); DBGLEAVE("WinsCnfGetNamesOfDataFiles\n"); return(RetStat); } VOID WinsCnfCloseKeys( VOID ) /*++ Routine Description: This function closes the the open keys. The keys closed are the WINS key, the PARTNERS key, and the PARAMETERS key. Arguments: None Externals Used: sfParametersKeyExists sfPartnersKeyExists Return Value: None Error Handling: Called by: Reinit() Side Effects: Comments: We don't look at the return code of RegCloseKey. This is because we might call this function even with the key not being open (not the case currently). --*/ { // // Close the PARAMETERS key if it is open // if (sfParametersKeyOpen) { (VOID)RegCloseKey(sParametersKey); } // // Close the PARTNERS key if it is open // if (sfPartnersKeyOpen) { (VOID)RegCloseKey(sPartnersKey); } #if 0 // // NOTE NOTE NOTE: Build 436. If we attempt to close a key that has been // deleted from the registry NT comes down // // // Close the WINS key // (VOID)RegCloseKey(sConfigRoot); #endif return; } //WinsCnfCloseKeys() VOID ChkWinsSubKeys( VOID ) /*++ Routine Description: This function is called to check whether we have the PARTNERS and PARAMETERS sub-keys under the root subkey of WINS. Arguments: None Externals Used: None Return Value: None Error Handling: Called by: Reinit() in nms.c Side Effects: Comments: None --*/ { DWORD NoOfSubKeys = 0; DWORD KeyNameSz; TCHAR KeyName[20]; FILETIME LastWrite; LONG RetVal; BOOL fParametersKey = FALSE; BOOL fPartnersKey = FALSE; /* * Get each subkey's name */ RetVal = ERROR_SUCCESS; for( ; RetVal == ERROR_SUCCESS; NoOfSubKeys++ ) { KeyNameSz = sizeof(KeyName)/sizeof(TCHAR); //init before every call RetVal = RegEnumKeyEx( sConfigRoot, NoOfSubKeys, //key KeyName, &KeyNameSz, NULL, //reserved NULL, //don't need class name NULL, //ptr to var. to hold class name &LastWrite //not looked at by us ); if (RetVal != ERROR_SUCCESS) { continue; } if (lstrcmp(KeyName, _WINS_CFG_PARAMETERS_KEY) == 0) { fParametersKey = TRUE; } if (lstrcmp(KeyName, _WINS_CFG_PARTNERS_KEY) == 0) { fPartnersKey = TRUE; } } // // if the Parameters key does not exist but it existed before, // close the key to get rid of the handle we have // if (!fParametersKey) { if (sfParametersKeyExists) { sfParametersKeyExists = FALSE; sfParametersKeyOpen = FALSE; } } else { sfParametersKeyExists = TRUE; } // // if the Partners key does not exist but it existed before, // close the key to get rid of the handle we have // if (!fPartnersKey) { if (sfPartnersKeyExists) { sfPartnersKeyExists = FALSE; sfPartnersKeyOpen = FALSE; } } else { sfPartnersKeyExists = TRUE; } return; } //ChkWinsSubKeys() VOID GetSpTimeData( HKEY SubKey, LPSYSTEMTIME pCurrTime, LPBOOL pfSpTime, LPDWORD pSpTimeIntvl /*++ Routine Description: This function is called to get the specific time and period information for a PULL/PUSH record. Arguments: SubKey - Key of a WINS under the Pull/Push key pCnfRFec - ptr to the Conf. record of the WINS Externals Used: None Return Value: Success status codes -- WINS_SUCCESS Error status codes -- WINS_NO_SP_TIME Error Handling: Called by: GetPnrInfo Side Effects: Comments: None --*/ ) { DWORD ValTyp; BYTE tSpTime[MAX_SZ_SIZE]; BYTE SpTime[MAX_SZ_SIZE]; LPBYTE pSpTime = SpTime; DWORD Sz = sizeof(tSpTime); LONG RetVal; DWORD Hr = 0; DWORD Mt = 0; DWORD Sec = 0; LONG TimeInt; // DBGENTER("GetSpTimeData\n"); *pfSpTime = FALSE; try { Sz = sizeof(tSpTime); RetVal = RegQueryValueEx( SubKey, WINSCNF_SP_TIME_NM, NULL, //reserved; must be NULL &ValTyp, tSpTime, &Sz ); // // If the user has not specifed a specific time, then we use // the current time as the specific time. For current time, // the interval is 0 // if (RetVal == ERROR_SUCCESS) { #ifdef UNICODE (VOID)WinsMscConvertUnicodeStringToAscii(tSpTime, SpTime, MAX_SZ_SIZE); #else pSpTime = tSpTime; #endif RetVal = (LONG)sscanf(pSpTime, "%d:%d:%d", &Hr, &Mt, &Sec); if ((RetVal == EOF) || (RetVal == 0)) { DBGPRINT1(ERR, "GetSpTime: Wrong time format (%s)\n", pSpTime); WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_WRONG_TIME_FORMAT); } else { *pSpTimeIntvl = 0; if ((Hr <= 23) && (Mt <= 59) && (Sec <= 59)) { TimeInt = ((Hr * 3600) + (Mt * 60) + Sec) - ((pCurrTime->wHour * 3600) + (pCurrTime->wMinute * 60) + pCurrTime->wSecond); if (TimeInt < 0) { *pSpTimeIntvl = (24 * 3600) + TimeInt; } else { *pSpTimeIntvl = TimeInt; } *pfSpTime = TRUE; DBGPRINT1(DET, "GetSpTimeData: Sp. Time Interval is %d\n", *pSpTimeIntvl); } else { DBGPRINT0(DET, "GetSpTimeData: WRONG TIME FORMAT\n"); } } } } except (EXCEPTION_EXECUTE_HANDLER) { DBGPRINTEXC("GetSpTime"); WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_CONFIG_ERR); } // DBGLEAVE("GetSpTimeData\n"); return; } #if MCAST > 0 STATUS WinsCnfAddPnr( RPL_RR_TYPE_E RRType_e, LPBYTE pPnrAdd ) /*++ Routine Description: Arguments: Externals Used: None Return Value: Success status codes -- Error status codes -- Error Handling: Called by: Side Effects: Comments: None --*/ { LONG RetVal; HKEY CnfKey; HKEY PnrKey; DWORD NewKeyInd; DBGENTER("WinsCnfAddPnr\n"); /* * Open the key (PULL/PUSH) */ RetVal = RegOpenKeyEx( sConfigRoot, //predefined key value RRType_e == RPL_E_PULL ? _WINS_CFG_PULL_KEY : _WINS_CFG_PUSH_KEY, //subkey for WINS 0, //must be zero (reserved) KEY_CREATE_SUB_KEY, //we want "subkey create" priv &CnfKey //handle to key ); if (RetVal != ERROR_SUCCESS) { CHECK("Is there any need to log this") WINSEVT_LOG_INFO_M( RetVal, RRType_e == RPL_E_PULL ? WINS_EVT_CANT_OPEN_PULL_KEY : WINS_EVT_CANT_OPEN_PUSH_KEY ); return (WINS_FAILURE); } // // Add the pnr // RetVal = RegCreateKeyExA( CnfKey, //predefined key value pPnrAdd, //subkey for WINS 0, //must be zero (reserved) "Class", //class -- may change in future REG_OPTION_NON_VOLATILE, //non-volatile information KEY_ALL_ACCESS, //we desire all access to the keyo NULL, //let key have default sec. attributes &PnrKey, //handle to key &NewKeyInd //is it a new key (out arg) ); if (RetVal != ERROR_SUCCESS) { WINSEVT_LOG_M( RetVal, RRType_e == RPL_E_PULL ? WINS_EVT_CANT_OPEN_PULL_SUBKEY : WINS_EVT_CANT_OPEN_PUSH_SUBKEY ); DBGPRINT3(ERR, "WinsCnfAddPnr: Could not create key with address = (%s) under the %s Key. RetVal = (%d)\n", pPnrAdd, RRType_e == RPL_E_PULL ? "PULL" : "PUSH", RetVal); return(WINS_FAILURE); } else { if (NewKeyInd != REG_CREATED_NEW_KEY) { DBGPRINT2(ERR, "WinsCnfAddPnr: key with address = (%s) under the %s Key already present\n", pPnrAdd, RRType_e == RPL_E_PULL ? "PULL" : "PUSH"); } else { // // If Pull pnr, add the time interval // if (RRType_e == RPL_E_PULL) { // // Add the time interval // SetVal(PnrKey, WINSCNF_RPL_INTERVAL_NM, REG_DWORD, (LPWSTR)WINSCNF_TIME_INT_W_SELF_FND_PNRS, sizeof(DWORD)); } SetVal(PnrKey, WINSCNF_SELF_FND_NM, REG_DWORD, (LPWSTR)TRUE, sizeof(DWORD)); } RegCloseKey(PnrKey); RegCloseKey(CnfKey); } DBGLEAVE("WinsCnfAddPnr\n"); return(WINS_SUCCESS); } STATUS WinsCnfDelPnr( RPL_RR_TYPE_E RRType_e, LPBYTE pPnrAdd ) /*++ Routine Description: Arguments: Externals Used: None Return Value: Success status codes -- Error status codes -- Error Handling: Called by: Side Effects: Comments: None --*/ { LONG RetVal; HKEY TypeOfPnrKey; HKEY PnrKey; //WCHAR Key[160]; WCHAR String[160]; BOOL fSelfFnd; DWORD Sz; DWORD ValType; DBGENTER("WinsCnfDelPnr\n"); WinsMscConvertAsciiStringToUnicode(pPnrAdd, (LPBYTE)String, sizeof(String)/sizeof(WCHAR)); /* * Open the key (PULL/PUSH) */ RetVal = RegOpenKeyEx( sConfigRoot, //predefined key value RRType_e == RPL_E_PULL ? _WINS_CFG_PULL_KEY : _WINS_CFG_PUSH_KEY, 0, //must be zero (reserved) KEY_ALL_ACCESS, &TypeOfPnrKey //handle to key ); if (RetVal != ERROR_SUCCESS) { CHECK("Is there any need to log this") WINSEVT_LOG_INFO_M( WINS_SUCCESS, RRType_e == RPL_E_PULL ? WINS_EVT_CANT_OPEN_PULL_KEY : WINS_EVT_CANT_OPEN_PUSH_KEY ); //--ft: Prefix bug 444974 - this key has to exist. If absurdly is missing, we won't find // the partner anyhow. return (WINS_SUCCESS); } RetVal = RegOpenKeyEx( TypeOfPnrKey, //predefined key value String, 0, //must be zero (reserved) KEY_ALL_ACCESS, //we want "subkey create" priv &PnrKey //handle to key ); if (RetVal != ERROR_SUCCESS) { DBGPRINT3(ERR, "WinsCnfDelPnr: %s Pnr with address = (%s) is Non-existent. RetVal = (%d)", RRType_e == RPL_E_PULL ? "PULL" : "PUSH", pPnrAdd, RetVal); return(WINS_SUCCESS); } else { Sz = sizeof(fSelfFnd); RetVal = RegQueryValueEx( PnrKey, WINSCNF_SELF_FND_NM, NULL, &ValType, (LPBYTE)&fSelfFnd, &Sz ); // // If SelfFnd is there and it's value is 1, delete it // if ((RetVal == ERROR_SUCCESS) && (fSelfFnd == 1)) { RetVal = RegDeleteKey(TypeOfPnrKey, String); if (RetVal != ERROR_SUCCESS) { DBGPRINT3(ERR, "WinsCnfDelPnr: Could not delete %s Pnr with address = (%s). RetVal = (%d)", RRType_e == RPL_E_PULL ? "PULL" : "PUSH", pPnrAdd, RetVal); RegCloseKey(PnrKey); return(WINS_FAILURE); } } RegCloseKey(TypeOfPnrKey); } DBGLEAVE("WinsCnfDelPnr\n"); return(WINS_SUCCESS); } DWORD SetVal( HKEY RootKey, LPWSTR pName, DWORD ValType, LPWSTR pVal, DWORD ValSize ) { UINT Status = WINS_SUCCESS; LONG RetVal; DWORD Val; if (ValType == REG_DWORD) { Val = PtrToUlong (pVal); } RetVal = RegSetValueEx( RootKey, pName, 0, //reserved -- must be 0 ValType, ValType == REG_DWORD ? (LPBYTE)&Val : (LPBYTE)pVal, ValType == REG_DWORD ? ValSize : lstrlen(pVal) ); if (RetVal != ERROR_SUCCESS) { printf("SetVal: Could not set value of %s\n", pName); Status = WINS_FAILURE; } return(Status); } #endif DWORD WinsCnfWriteReg( LPVOID pTmp ) /*++ Routine Description: This function write the value of the version counter to be used at the next invocation. Arguments: pTmp - Will be NULL if WinsCnfNextTimeVersNo was found in the registry when WINS came up. Externals Used: NmsHighWaterMarkVersNo NmsVersNoToStartFromNextTime NmsNmhNamRegCrtSec NmsRangeSize NmsHalfRangeSize sfVersNoChanged sfVersNoUpdThdExists Return Value: VOID Error Handling: Called by: NMSNMH_INC_VERS_COUNTER_M Side Effects: Comments: None --*/ { LONG RetVal; LONG RetVal2; VERS_NO_T VersNo; DBGENTER("WinsCnfWriteReg\n"); EnterCriticalSection(&NmsNmhNamRegCrtSec); // // if pTmp is not NULL, it means that either WINS did not find // Next time's version number in the registry or that the max. version // number in the db is greater than the high water mark we set at // initialization. In the former case, we already have the correct // value in NmsNmhToStartFromNextTime, so the if body is not executed. // if (!pTmp || LiLtr(NmsHighWaterMarkVersNo, NmsNmhMyMaxVersNo)) { NmsHighWaterMarkVersNo.QuadPart = LiAdd(NmsVersNoToStartFromNextTime, NmsHalfRangeSize); NmsVersNoToStartFromNextTime.QuadPart = LiAdd(NmsVersNoToStartFromNextTime, NmsRangeSize); } VersNo = NmsVersNoToStartFromNextTime; LeaveCriticalSection(&NmsNmhNamRegCrtSec); RetVal = RegSetValueEx( sConfigRoot, WINSCNF_INT_VERSNO_NEXTTIME_LW_NM, 0, //reserved -- must be 0 REG_DWORD, (LPBYTE)&VersNo.LowPart, sizeof(DWORD) ); RetVal2 = RegSetValueEx( sConfigRoot, WINSCNF_INT_VERSNO_NEXTTIME_HW_NM, 0, //reserved -- must be 0 REG_DWORD, (LPBYTE)&VersNo.HighPart, sizeof(DWORD) ); if ((RetVal != ERROR_SUCCESS) || (RetVal2 != ERROR_SUCCESS)) { DBGPRINT2(ERR, "WinsCnfWriteReg - Could not set Next time's start version counter value in the registry. The new value is (%d %d)\n", VersNo.HighPart, VersNo.LowPart); } EnterCriticalSection(&NmsNmhNamRegCrtSec); WinsCnfRegUpdThdExists = FALSE; LeaveCriticalSection(&NmsNmhNamRegCrtSec); DBGLEAVE("WinsCnfWriteReg\n"); return(WINS_SUCCESS); } #if defined (DBGSVC) && !defined (WINS_INTERACTIVE) VOID WinsCnfReadWinsDbgFlagValue( VOID ) { DWORD Sz; DWORD ValTyp; WinsDbg = 0; //set it to zero now. It was set to a value by Init() in //nms.c Sz = sizeof(WinsDbg); (VOID)RegQueryValueEx( sParametersKey, WINSCNF_DBGFLAGS_NM, NULL, //reserved; must be NULL &ValTyp, (LPBYTE)&WinsDbg, &Sz ); return; } #endif VOID ReadSpecGrpMasks( PWINSCNF_CNF_T pWinsCnf ) /*++ Routine Description: This function is called to read in the special group masks specified under the SpecialGrpMasks key Arguments: Externals Used: None Return Value: Success status codes -- Error status codes -- Error Handling: Called by: Side Effects: Comments: None --*/ { DWORD NoOfSubKeys; HKEY SGMKey; BOOL fKeyOpen = FALSE; LONG RetVal; DBGENTER("ReadSpecGrpMasks\n"); try { /* * Open the SPEC_GRP_MASKS key */ RetVal = RegOpenKeyEx( sParametersKey, //predefined key value _WINS_CFG_SPEC_GRP_MASKS_KEY, 0, //must be zero (reserved) KEY_READ, //we desire read access to the keyo &SGMKey //handle to key ); if (RetVal == ERROR_SUCCESS) { fKeyOpen = TRUE; // // Get the count of data files listed under the DATAFILES // key // GetKeyInfo( SGMKey, WINSCNF_E_SPEC_GRP_MASKS_KEY, &NoOfSubKeys, //ignored &pWinsCnf->SpecGrpMasks.NoOfSpecGrpMasks ); if (pWinsCnf->SpecGrpMasks.NoOfSpecGrpMasks > 0) { DWORD Index; LPBYTE pTmp; TCHAR ValNmBuff[5]; DWORD ValNmBuffSz; DWORD StrType; LPBYTE pByte; DWORD BuffSize; CHAR Tmp[WINS_MAX_FILENAME_SZ]; #ifdef UNICODE WCHAR Str[WINSCNF_SPEC_GRP_MASK_SZ]; #endif // // Allocate buffer big enough to hold data for // the number of subkeys found under the PULL key // BuffSize = (WINSCNF_SPEC_GRP_MASK_SZ + 1) * pWinsCnf->SpecGrpMasks.NoOfSpecGrpMasks; WinsMscAlloc( BuffSize, &pWinsCnf->SpecGrpMasks.pSpecGrpMasks); /* * Enumerate the values */ for( Index = 0, pTmp = pWinsCnf->SpecGrpMasks.pSpecGrpMasks; Index < pWinsCnf->SpecGrpMasks.NoOfSpecGrpMasks; // no third expression ) { ValNmBuffSz = sizeof(ValNmBuff)/sizeof(TCHAR); //init before //every call BuffSize = WINSCNF_SPEC_GRP_MASK_SZ; RetVal = RegEnumValue( SGMKey, Index, //key ValNmBuff, &ValNmBuffSz, (LPDWORD)NULL, //reserved &StrType, #ifdef UNICODE (LPBYTE)Str, #else pTmp, #endif &BuffSize ); if (RetVal != ERROR_SUCCESS) { continue; } // // if StrType is not REG_SZ go to the next Value // if (StrType != REG_SZ) { continue; } if (BuffSize != WINSCNF_SPEC_GRP_MASK_SZ) { DBGPRINT1(ERR, "ReadSpecGrpMasks: Wrong spec. grp mask (%s)\n", pTmp); WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_WRONG_SPEC_GRP_MASK_M); continue; } else { #ifdef UNICODE WinsMscConvertUnicodeStringToAscii( (LPBYTE)Str, (LPBYTE)Tmp, WINSCNF_SPEC_GRP_MASK_SZ ); #endif pByte = (LPBYTE)Tmp; for (Index = 0; Index < WINSCNF_SPEC_GRP_MASK_SZ; Index++, pByte++) { *pByte = (BYTE)CharUpperA((LPSTR)*pByte); if ( ((*pByte >= '0') && (*pByte <= '9')) || ((*pByte >= 'A') && (*pByte <= 'F')) ) { continue; } else { break; } } if (Index > WINSCNF_SPEC_GRP_MASK_SZ) { DBGPRINT1(ERR, "ReadSpecGrpMasks: Wrong spec. grp mask (%s)\n", pTmp); WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_WRONG_SPEC_GRP_MASK_M); continue; } *(pTmp + WINSCNF_SPEC_GRP_MASK_SZ) = EOS; } Index++; pTmp += WINSCNF_SPEC_GRP_MASK_SZ + 1; } // // If not even one valid name was retrieved, get rid of the // buffer // if (Index == 0) { // // Get rid of the buffer // WinsMscDealloc((LPBYTE)pWinsCnf->SpecGrpMasks.pSpecGrpMasks); } pWinsCnf->SpecGrpMasks.NoOfSpecGrpMasks = Index; } } // end of if } // end of try .. except (EXCEPTION_EXECUTE_HANDLER) { DBGPRINTEXC("ReadSpecGrpMasks"); WINSEVT_LOG_D_M(GetExceptionCode(), WINS_EVT_CANT_INIT); } if (fKeyOpen && RegCloseKey(SGMKey) != ERROR_SUCCESS) { WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_CANT_CLOSE_KEY); DBGPRINT0(ERR, "ReadSpecGrpMasks: Can not read the spec. grp. mask. key\n"); } DBGLEAVE("ReadSpecGrpMasks\n"); return; } #if 0 int __cdecl CompUpdCnt( CONST LPVOID pElem1, CONST LPVOID pElem2 ) /*++ Routine Description: This function is called by qsort crtl function to compare two elements of the array that has to be sorted Arguments: pElem1 - ptr to first element pElem1 - ptr to second element Externals Used: None Return Value: -1 if first element is < second element = 0 if first element is == second element 1 if first element is > second element Error Handling: Called by: qsort (which is called by WinsCnfReadPartnerInfo Side Effects: Comments: Not used currently --*/ { CONST PRPL_CONFIG_REC_T pCnfRec1 = pElem1; CONST PRPL_CONFIG_REC_T pCnfRec2 = pElem2; if (pCnfRec1->UpdateCount < pCnfRec2->UpdateCount) { return(-1); } else { if (pCnfRec1->UpdateCount == pCnfRec2->UpdateCount) { return(0); } } // // The first record has a higher UpdateCount than the second one // return(1); } #endif #ifdef WINSDBG VOID PrintRecs( RPL_RR_TYPE_E RRType_e, PWINSCNF_CNF_T pWinsCnf ) { return; } #endif