1933 lines
44 KiB
C
1933 lines
44 KiB
C
// NOTE:
|
||
//
|
||
// Unless the data read from the STATIC file is converted to UNICODE, we should
|
||
// not have UNICODE defined for this module
|
||
//
|
||
/*++
|
||
|
||
Copyright (c) 1990 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
winsprs.c
|
||
|
||
Abstract:
|
||
This source contains the functions that parse the lmhosts file.
|
||
|
||
|
||
Functions:
|
||
GetTokens,
|
||
IsKeyWord,
|
||
Fgets,
|
||
PrimeDb
|
||
ExpandName,
|
||
RegOrdinaryName,
|
||
RegGrpName
|
||
WinsPrsDoStaticInit
|
||
|
||
|
||
Portability:
|
||
|
||
This module is portable
|
||
|
||
|
||
Author:
|
||
|
||
Pradeep Bahl (PradeepB) Apr-1993
|
||
|
||
Stole the parsing code from lm_parse.c, lm_io.c, and lm_parse.c in
|
||
streams\tcpip\nbt; Modified it appropriately
|
||
|
||
Revision History:
|
||
|
||
Modification date Person Description of modification
|
||
----------------- ------- ----------------------------
|
||
--*/
|
||
|
||
/*
|
||
* Includes
|
||
*/
|
||
#include <ctype.h>
|
||
#include <string.h>
|
||
#include "wins.h"
|
||
#include "nms.h" //required for DBGPRINT statements
|
||
#include <winuser.h>
|
||
#include "winsevt.h"
|
||
#include "winsprs.h"
|
||
#include "winsmsc.h"
|
||
#include "nmsmsgf.h"
|
||
#include "nmsnmh.h"
|
||
#include "comm.h"
|
||
#include "winsintf.h"
|
||
|
||
|
||
/*
|
||
* Local Macro Declarations
|
||
*/
|
||
|
||
|
||
#define DOMAIN_TOKEN "#DOM:"
|
||
#define PRELOAD_TOKEN "#PRE"
|
||
#define INCLUDE_TOKEN "#INCLUDE"
|
||
#define BEG_ALT_TOKEN "#BEGIN_ALTERNATE"
|
||
#define END_ALT_TOKEN "#END_ALTERNATE"
|
||
|
||
#define DOMAIN_TOKEN_SIZE (sizeof(DOMAIN_TOKEN) - 1)
|
||
|
||
//
|
||
// To mark special groups in the lmhosts file
|
||
//
|
||
#define SPEC_GRP_TOKEN "#SG:"
|
||
#define SPEC_GRP_TOKEN_SIZE (sizeof(SPEC_GRP_TOKEN) - 1)
|
||
|
||
//
|
||
// To indicate an mh node
|
||
//
|
||
#define MH_TOKEN "#MH"
|
||
#define MH_TOKEN_SIZE (sizeof(MH_TOKEN) - 1)
|
||
|
||
|
||
|
||
#define QUOTE_CHAR '"'
|
||
#define TAB_CHAR '\t'
|
||
#define SPACE_CHAR ' '
|
||
#define CARRIAGE_RETURN_CHAR '\r'
|
||
#define NEWLINE_CHAR '\n'
|
||
#define COMMENT_CHAR '#'
|
||
#define BACKSLASH_CHAR '\\'
|
||
#define ZERO_CHAR '0'
|
||
#define x_CHAR 'x'
|
||
#define X_CHAR 'X'
|
||
|
||
//
|
||
// Size of array to hold a non-coded netbios name read from a file (lmhosts)
|
||
//
|
||
#define NON_CODED_NAME_SIZE 17
|
||
/*
|
||
* Local Typedef Declarations
|
||
*/
|
||
|
||
|
||
//
|
||
// Private Definitions
|
||
//
|
||
typedef struct _FILE_PARAM_T {
|
||
PWINSCNF_DATAFILE_INFO_T pDataFile;
|
||
DWORD NoOfFiles;
|
||
} FILE_PARAM_T, *PFILE_PARAM_T;
|
||
|
||
//
|
||
// GetTokens() parses a line and returns the tokens in the following
|
||
// order:
|
||
//
|
||
typedef enum _TOKEN_ORDER_E {
|
||
E_IPADDRESS = 0, // first token
|
||
E_NBNAME, // 2nd token
|
||
E_GROUPNAME, // 3rd or 4th token
|
||
E_NOTUSED, // #PRE, if any
|
||
E_MAX_TOKENS // this must be last
|
||
|
||
} TOKEN_ORDER_E, *PTOKEN_ORDER_E;
|
||
|
||
//
|
||
// If the line category is E_SPEC_GRP, then we have just one token
|
||
//
|
||
#define SPEC_GRP_TOKEN_POS 0
|
||
|
||
//
|
||
// As each line in an lmhosts file is parsed, it is classified into one of
|
||
// the categories enumerated below.
|
||
//
|
||
// However, Preload is a special member of the enum (ignored by us).
|
||
//
|
||
//
|
||
typedef enum _TYPE_OF_LINE_E {
|
||
|
||
E_COMMENT = 0x0000, // comment line
|
||
E_ORDINARY = 0x0001, // ip_addr NetBIOS name
|
||
E_DOMAIN = 0x0002, // ... #DOM:name
|
||
E_INCLUDE = 0x0003, // #INCLUDE file
|
||
E_BEGIN_ALTERNATE = 0x0004, // #BEGIN_ALTERNATE
|
||
E_END_ALTERNATE = 0x0005, // #END_ALTERNATE
|
||
E_SPEC_GRP = 0x0006, // #Spec Grp
|
||
E_SGWADD = 0x0007, // #Spec Grp with add
|
||
|
||
E_PRELOAD = 0x8000, // ... #PRE
|
||
E_MH = 0x8001 // ip_addr NetBIOS name
|
||
// for a mh machine
|
||
} TYPE_OF_LINE_E, *PTYPE_OF_LINE_E;
|
||
|
||
|
||
//
|
||
// In an lmhosts file, the following are recognized as keywords:
|
||
//
|
||
// #BEGIN_ALTERNATE #END_ALTERNATE #PRE
|
||
// #DOM: #INCLUDE
|
||
//
|
||
// Information about each keyword is kept in a KEYWORD structure.
|
||
//
|
||
//
|
||
typedef struct _KEYWORD_T { // reserved keyword
|
||
LPBYTE pKString; // NULL terminated
|
||
size_t KStrlen; // length of token
|
||
TYPE_OF_LINE_E KType_e; // type of line
|
||
DWORD KNoOfOperands; // max operands on line
|
||
} KEYWORD_T, *PKEYWORD_T;
|
||
|
||
|
||
//
|
||
// Information about the type of line read is kept in the LINE_CHARACTERISTICS
|
||
// structure
|
||
//
|
||
typedef struct _LINE_CHARACTERISTICS_T
|
||
{
|
||
int LineCategory:4; // enum _TYPE_OF_LINE
|
||
int LinePreload:1; // marked with #PRE ?
|
||
int Mh:1; // marked with #MH ?
|
||
} LINE_CHARACTERISTICS_T, *PLINE_CHARACTERISTICS_T;
|
||
|
||
/*
|
||
* Global Variable Definitions
|
||
*/
|
||
|
||
|
||
|
||
/*
|
||
* Local Variable Definitions
|
||
*/
|
||
|
||
|
||
//
|
||
// In an lmhosts file, the token '#' in any column usually denotes that
|
||
// the rest of the line is to be ignored. However, a '#' may also be the
|
||
// first character of a keyword.
|
||
//
|
||
// Keywords are divided into two groups:
|
||
//
|
||
// 1. decorations that must either be the 3rd or 4th token of a line,
|
||
// 2. directives that must begin in column 0,
|
||
//
|
||
//
|
||
KEYWORD_T Decoration[] = {
|
||
DOMAIN_TOKEN, sizeof(DOMAIN_TOKEN) - 1, E_DOMAIN, 4,
|
||
PRELOAD_TOKEN, sizeof(PRELOAD_TOKEN) - 1, E_PRELOAD, 4,
|
||
SPEC_GRP_TOKEN, sizeof(SPEC_GRP_TOKEN) - 1, E_SGWADD, 4,
|
||
MH_TOKEN, sizeof(MH_TOKEN) - 1, E_MH, 4,
|
||
NULL, 0 // must be last
|
||
};
|
||
|
||
|
||
KEYWORD_T Directive[] = {
|
||
INCLUDE_TOKEN, sizeof(INCLUDE_TOKEN) - 1, E_INCLUDE, 2,
|
||
BEG_ALT_TOKEN, sizeof(BEG_ALT_TOKEN) - 1, E_BEGIN_ALTERNATE, 1,
|
||
END_ALT_TOKEN, sizeof(END_ALT_TOKEN) - 1, E_END_ALTERNATE, 1,
|
||
SPEC_GRP_TOKEN, sizeof(SPEC_GRP_TOKEN) - 1, E_SPEC_GRP, 1,
|
||
NULL, 0 // must be last
|
||
};
|
||
|
||
|
||
|
||
/*
|
||
* Local Function Prototype Declarations
|
||
*/
|
||
|
||
/* prototypes for functions local to this module go here */
|
||
|
||
|
||
//
|
||
// Local (Private) Functions
|
||
//
|
||
STATIC
|
||
BOOL
|
||
ChkAdd(
|
||
LPBYTE pstrAdd,
|
||
LPDWORD pAdd
|
||
);
|
||
STATIC
|
||
LINE_CHARACTERISTICS_T
|
||
GetTokens (
|
||
IN OUT LPBYTE pLine,
|
||
OUT LPBYTE *ppToken,
|
||
IN OUT LPDWORD pNumTokens
|
||
);
|
||
|
||
STATIC
|
||
PKEYWORD_T
|
||
IsKeyWord (
|
||
IN LPBYTE pString,
|
||
IN PKEYWORD_T pTable
|
||
);
|
||
|
||
STATIC
|
||
LPBYTE
|
||
Fgets (
|
||
PWINSPRS_FILE_INFO_T pFileInfo,
|
||
LPDWORD pCount
|
||
);
|
||
|
||
|
||
STATIC
|
||
VOID
|
||
PrimeDb (
|
||
PWINSPRS_FILE_INFO_T pFileInfo
|
||
);
|
||
|
||
STATIC
|
||
BOOL
|
||
ExpandName (
|
||
OUT LPBYTE pDest,
|
||
IN LPBYTE pSrc,
|
||
IN BYTE LastCh,
|
||
OUT LPBOOL pfQuoted
|
||
);
|
||
|
||
STATIC
|
||
VOID
|
||
CheckForInt(
|
||
IN OUT LPBYTE pDest,
|
||
IN BOOL fQuoted
|
||
);
|
||
|
||
STATIC
|
||
VOID
|
||
RegOrdinaryName(
|
||
LPBYTE pName,
|
||
DWORD IpAdd
|
||
);
|
||
|
||
VOID
|
||
RegGrpName(
|
||
LPBYTE pName,
|
||
DWORD IpAdd,
|
||
DWORD TypeOfRec
|
||
);
|
||
STATIC
|
||
DWORD
|
||
DoStaticInitThdFn(
|
||
IN LPVOID pThdParam
|
||
);
|
||
|
||
STATIC
|
||
LINE_CHARACTERISTICS_T
|
||
GetTokens (
|
||
IN OUT LPBYTE pLine,
|
||
OUT LPBYTE *ppToken,
|
||
IN OUT LPDWORD pNumTokens
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function parses a line for tokens. A maximum of *pnumtokens
|
||
are collected.
|
||
|
||
Arguments:
|
||
|
||
pLine - pointer to the NULL terminated line to parse
|
||
pToken - an array of pointers to tokens collected
|
||
pNumTokens - on input, number of elements in the array, token[];
|
||
on output, number of tokens collected in token[]
|
||
|
||
Return Value:
|
||
|
||
The characteristics of this lmhosts line.
|
||
|
||
Notes:
|
||
|
||
1. Each token must be separated by white space. Hence, the keyword
|
||
"#PRE" in the following line won't be recognized:
|
||
|
||
11.1.12.132 lothair#PRE
|
||
|
||
2. Any ordinary line can be decorated with a "#PRE", a "#DOM:name" or
|
||
both. Hence, the following lines must all be recognized:
|
||
|
||
111.21.112.3 kernel #DOM:ntwins #PRE
|
||
111.21.112.4 orville #PRE #DOM:ntdev
|
||
111.21.112.7 cliffv4 #DOM:ntlan
|
||
111.21.112.132 lothair #PRE
|
||
|
||
--*/
|
||
|
||
{
|
||
enum _PARSE_E
|
||
{ // current fsm state
|
||
E_START_OF_LINE,
|
||
E_WHITESPACE,
|
||
E_TOKEN
|
||
} State_e;
|
||
|
||
LPBYTE pCh; // current fsm input
|
||
//LPBYTE pByte; // current fsm input
|
||
PKEYWORD_T pKeyword;
|
||
DWORD Index;
|
||
DWORD MaxTokens;
|
||
LINE_CHARACTERISTICS_T Retval;
|
||
BOOL fQuoteSeen = FALSE;
|
||
BOOL fBreakOut = FALSE;
|
||
|
||
//
|
||
// Zero out the token array
|
||
//
|
||
RtlZeroMemory(ppToken, *pNumTokens * sizeof(LPBYTE *));
|
||
|
||
State_e = E_START_OF_LINE;
|
||
Retval.LineCategory = E_ORDINARY;
|
||
Retval.LinePreload = 0;
|
||
Retval.Mh = 0;
|
||
MaxTokens = *pNumTokens;
|
||
Index = 0;
|
||
|
||
for (pCh = pLine; *pCh != (BYTE)NULL && !fBreakOut; pCh++)
|
||
{
|
||
switch ((int)*pCh)
|
||
{
|
||
//
|
||
// does the '#' signify the start of a reserved keyword, or the
|
||
// start of a comment ?
|
||
//
|
||
case COMMENT_CHAR:
|
||
//
|
||
// if a quote character has been seen earlier, skip this
|
||
// char
|
||
//
|
||
if(fQuoteSeen)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// See if we have a keyword. Use the appropriate table for the
|
||
// lookup
|
||
//
|
||
pKeyword = IsKeyWord(
|
||
pCh,
|
||
(State_e == E_START_OF_LINE) ?
|
||
Directive : Decoration
|
||
);
|
||
|
||
//
|
||
// If it is a keyword
|
||
//
|
||
if (pKeyword)
|
||
{
|
||
State_e = E_TOKEN;
|
||
MaxTokens = pKeyword->KNoOfOperands;
|
||
|
||
switch (pKeyword->KType_e)
|
||
{
|
||
case E_PRELOAD:
|
||
Retval.LinePreload = 1;
|
||
continue;
|
||
|
||
case E_MH:
|
||
Retval.Mh = 1;
|
||
continue;
|
||
|
||
//
|
||
// It is one of the other keywords
|
||
//
|
||
default:
|
||
ASSERT(Index < MaxTokens);
|
||
|
||
ppToken[Index++] = pCh;
|
||
Retval.LineCategory = pKeyword->KType_e;
|
||
continue;
|
||
}
|
||
|
||
ASSERT(0);
|
||
}
|
||
|
||
//
|
||
// Since it is not a keyword, it is a comment
|
||
//
|
||
if (State_e == E_START_OF_LINE)
|
||
{
|
||
Retval.LineCategory = E_COMMENT;
|
||
}
|
||
/* fall through */
|
||
|
||
case CARRIAGE_RETURN_CHAR:
|
||
case NEWLINE_CHAR:
|
||
*pCh = (BYTE) NULL;
|
||
fBreakOut = TRUE;
|
||
break; //break out of the loop. We are done
|
||
|
||
case SPACE_CHAR:
|
||
case TAB_CHAR:
|
||
//
|
||
// if State is Token, and there is no ending quote to worry about
|
||
// we change the state to WhiteSpace
|
||
//
|
||
if (State_e == E_TOKEN)
|
||
{
|
||
if (!fQuoteSeen)
|
||
{
|
||
State_e = E_WHITESPACE;
|
||
*pCh = (BYTE)NULL;
|
||
|
||
//
|
||
// If we have accumulated the desired number of tokens
|
||
// break out of the loop
|
||
//
|
||
if (Index == MaxTokens)
|
||
{
|
||
fBreakOut = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
continue;
|
||
|
||
case QUOTE_CHAR:
|
||
|
||
//
|
||
// Check whether we have seen the beginning quote char earlier
|
||
//
|
||
if(fQuoteSeen)
|
||
{
|
||
//
|
||
// Ending quote consumed. Set flag to FALSE
|
||
//
|
||
fQuoteSeen = FALSE;
|
||
}
|
||
else // companion quote not seen earlier
|
||
{
|
||
//
|
||
// This could be the starting quote of the #DOM:
|
||
// keyword's string or could be the starting
|
||
// quote of the nbtname string
|
||
//
|
||
if (State_e == E_TOKEN)
|
||
{
|
||
//
|
||
// It is the starting quote of the #DOM: keyword
|
||
// string
|
||
//
|
||
// --ft: the statement above doesn't stand for legal LMHOSTS lines like:
|
||
// #SG:"SGNoMember"
|
||
// so I commented out the assert below:
|
||
//ASSERT(Index > E_NBNAME);
|
||
}
|
||
else
|
||
{
|
||
|
||
//
|
||
// Must be the starting quote of the Nbt name
|
||
//
|
||
ASSERT(Index == E_NBNAME);
|
||
|
||
State_e = E_TOKEN;
|
||
//
|
||
// Store the pointer to the token
|
||
//
|
||
ppToken[Index++] = pCh;
|
||
}
|
||
fQuoteSeen = TRUE;
|
||
}
|
||
continue;
|
||
|
||
default:
|
||
|
||
//
|
||
// If this is the token state, continue
|
||
//
|
||
if (State_e == E_TOKEN)
|
||
{
|
||
continue;
|
||
}
|
||
ASSERT(Index < MaxTokens);
|
||
|
||
State_e = E_TOKEN;
|
||
//
|
||
// Store the pointer to the token
|
||
//
|
||
ppToken[Index++] = pCh;
|
||
continue;
|
||
} // end of switch
|
||
} // end of for loop
|
||
|
||
|
||
*pNumTokens = Index;
|
||
|
||
return(Retval);
|
||
|
||
} // GetTokens
|
||
|
||
|
||
|
||
|
||
STATIC
|
||
PKEYWORD_T
|
||
IsKeyWord (
|
||
IN LPBYTE pString,
|
||
IN PKEYWORD_T pKTable
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function determines whether the string is a reserved keyword.
|
||
|
||
Arguments:
|
||
|
||
pString - the string to search
|
||
pKTable - an array of keywords to look for
|
||
|
||
Return Value:
|
||
|
||
A pointer to the relevant keyword object, or NULL if unsuccessful
|
||
|
||
--*/
|
||
|
||
{
|
||
size_t StringSize;
|
||
PKEYWORD_T pSpecial;
|
||
|
||
|
||
StringSize = strlen(pString);
|
||
|
||
for (pSpecial = pKTable; pSpecial->pKString; pSpecial++) {
|
||
|
||
//
|
||
// If the length of the string is less than that of the keyword,
|
||
// go on to the next keyword in the table
|
||
//
|
||
if (StringSize < pSpecial->KStrlen)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// if length of string is greater than or equal to the keyword
|
||
// length and the string matches the keyword in the # of characters
|
||
// that comprise the keywordm, return the address of the keyword
|
||
// structure
|
||
//
|
||
FUTURES("use lstrncmp when it becomes available")
|
||
if (
|
||
(StringSize >= pSpecial->KStrlen)
|
||
&&
|
||
!strncmp(pString, pSpecial->pKString, pSpecial->KStrlen)
|
||
)
|
||
{
|
||
return(pSpecial);
|
||
}
|
||
}
|
||
return((PKEYWORD_T) NULL);
|
||
|
||
} // IsKeyWord
|
||
|
||
|
||
|
||
|
||
VOID
|
||
PrimeDb (
|
||
PWINSPRS_FILE_INFO_T pFileInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
This function primes the WINS db
|
||
|
||
Arguments:
|
||
|
||
|
||
Externals Used:
|
||
None
|
||
|
||
|
||
Return Value:
|
||
None
|
||
|
||
Error Handling:
|
||
|
||
Called by:
|
||
|
||
Side Effects:
|
||
|
||
Comments:
|
||
None
|
||
--*/
|
||
|
||
{
|
||
LPBYTE CurrLine;
|
||
DWORD Count;
|
||
DWORD NWords;
|
||
LPBYTE ppToken[E_MAX_TOKENS];
|
||
LINE_CHARACTERISTICS_T CurrLineChar;
|
||
DWORD Add;
|
||
BOOL fBadAdd;
|
||
DWORD TkSize;
|
||
DWORD TypeOfRec;
|
||
|
||
try {
|
||
|
||
//
|
||
// Loop over all records
|
||
//
|
||
pFileInfo->pCurrPos = pFileInfo->pFileBuff;
|
||
while (CurrLine = Fgets(pFileInfo, &Count) )
|
||
{
|
||
|
||
NWords = E_MAX_TOKENS;
|
||
|
||
fBadAdd = FALSE;
|
||
CurrLineChar = GetTokens(CurrLine, ppToken, &NWords);
|
||
switch (CurrLineChar.LineCategory)
|
||
{
|
||
|
||
case E_SGWADD:
|
||
TypeOfRec = NMSDB_USER_SPEC_GRP_ENTRY;
|
||
TkSize = SPEC_GRP_TOKEN_SIZE;
|
||
|
||
//fall through
|
||
case E_DOMAIN:
|
||
|
||
if (CurrLineChar.LineCategory == E_DOMAIN)
|
||
{
|
||
TypeOfRec = NMSDB_SPEC_GRP_ENTRY;
|
||
TkSize = DOMAIN_TOKEN_SIZE;
|
||
}
|
||
|
||
//
|
||
// If there are too few words in the line, go
|
||
// get the next line
|
||
//
|
||
if ((NWords - 1) < E_GROUPNAME)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
if (ChkAdd(ppToken[E_IPADDRESS], &Add))
|
||
{
|
||
|
||
//
|
||
// Register the domain name (group name with 1C at
|
||
// the end)
|
||
//
|
||
RegGrpName(
|
||
ppToken[E_GROUPNAME] + TkSize,
|
||
Add,
|
||
TypeOfRec
|
||
);
|
||
}
|
||
else
|
||
{
|
||
fBadAdd = TRUE;
|
||
}
|
||
|
||
//
|
||
// Fall through
|
||
//
|
||
|
||
case E_ORDINARY:
|
||
|
||
//
|
||
// If there are too few words in the line, go
|
||
// get the next line
|
||
//
|
||
// Don't use (NWords - 1) < E_NBNAME since
|
||
// NWords can be 0 in which case the test will
|
||
// fail
|
||
//
|
||
|
||
if (NWords < (E_NBNAME + 1))
|
||
{
|
||
continue;
|
||
}
|
||
else
|
||
{
|
||
if (!fBadAdd && ChkAdd(ppToken[E_IPADDRESS], &Add))
|
||
{
|
||
if (CurrLineChar.Mh)
|
||
{
|
||
RegGrpName(
|
||
ppToken[E_NBNAME],
|
||
Add,
|
||
NMSDB_MULTIHOMED_ENTRY
|
||
);
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// register the name
|
||
//
|
||
RegOrdinaryName( ppToken[E_NBNAME], Add);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
WinsMscLogEvtStrs(
|
||
ppToken[E_NBNAME],
|
||
WINS_EVT_BAD_ADDRESS,
|
||
FALSE
|
||
);
|
||
DBGPRINT2(ERR, "PrimeDb: Name (%s) has bad address = (%s). It is being ignored\n", ppToken[E_NBNAME], ppToken[E_IPADDRESS]);
|
||
}
|
||
}
|
||
continue;
|
||
|
||
case E_SPEC_GRP:
|
||
//
|
||
// Register the domain name (group name with 1C at
|
||
// the end)
|
||
//
|
||
RegGrpName(
|
||
ppToken[SPEC_GRP_TOKEN_POS] + SPEC_GRP_TOKEN_SIZE,
|
||
0,
|
||
NMSDB_USER_SPEC_GRP_ENTRY);
|
||
continue;
|
||
|
||
|
||
case E_INCLUDE: // fall through
|
||
case E_BEGIN_ALTERNATE: // fall through
|
||
case E_END_ALTERNATE: // fall through
|
||
continue;
|
||
default:
|
||
continue;
|
||
}
|
||
}
|
||
} // end of try block
|
||
finally {
|
||
|
||
//
|
||
// deallocate the memory to which the file was mapped
|
||
//
|
||
WinsMscDealloc(pFileInfo->pFileBuff);
|
||
}
|
||
return;
|
||
|
||
} // PrimeDb
|
||
|
||
|
||
|
||
LPBYTE
|
||
Fgets (
|
||
IN PWINSPRS_FILE_INFO_T pFileInfo,
|
||
OUT LPDWORD pNoOfCh
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is vaguely similar to fgets(3).
|
||
|
||
Starting at the current seek position, it reads through a newline
|
||
character, or the end of the file. If a newline is encountered, it
|
||
is replaced with a NULL character.
|
||
|
||
Arguments:
|
||
|
||
pfile - file to read from
|
||
nbytes - the number of characters read, excluding the NULL character
|
||
|
||
Return Value:
|
||
|
||
A pointer to the beginning of the line, or NULL if we are at or past
|
||
the end of the file.
|
||
|
||
--*/
|
||
|
||
{
|
||
LPBYTE pEndOfLine;
|
||
LPBYTE pStartOfLine;
|
||
SIZE_T MaxCh;
|
||
|
||
//
|
||
// Store the current position in the memory buffer
|
||
//
|
||
pStartOfLine = (LPBYTE)pFileInfo->pCurrPos;
|
||
|
||
//
|
||
// If it is greater or equal than the limit, return NULL
|
||
//
|
||
if (pStartOfLine >= (LPBYTE)pFileInfo->pLimit) {
|
||
|
||
return(NULL);
|
||
}
|
||
|
||
//
|
||
// Store the max. number of bytes between the current position and
|
||
// the end of the buffer.
|
||
//
|
||
MaxCh = (pFileInfo->pLimit - pFileInfo->pCurrPos);
|
||
|
||
//
|
||
// get to the end of the line
|
||
//
|
||
pEndOfLine = (LPBYTE)memchr(pStartOfLine, NEWLINE_CHAR, (size_t)MaxCh);
|
||
|
||
if (!pEndOfLine)
|
||
{
|
||
|
||
DBGPRINT0(FLOW, "Data file does not end in newline\n");
|
||
return(NULL);
|
||
}
|
||
|
||
*pEndOfLine = (BYTE)NULL;
|
||
|
||
pFileInfo->pCurrPos = pEndOfLine + 1; //adjust the pointer
|
||
|
||
ASSERT(pFileInfo->pCurrPos <= pFileInfo->pLimit);
|
||
|
||
*pNoOfCh = (DWORD) (pEndOfLine - pStartOfLine);
|
||
return(pStartOfLine);
|
||
|
||
} // Fgets
|
||
|
||
|
||
VOID
|
||
RegOrdinaryName(
|
||
IN LPBYTE pName,
|
||
IN DWORD IPAdd
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
This function registers a unique name
|
||
|
||
Arguments:
|
||
|
||
pName - Name to register
|
||
IPAdd - Address to register
|
||
|
||
Externals Used:
|
||
None
|
||
|
||
|
||
Return Value:
|
||
None
|
||
|
||
Error Handling:
|
||
|
||
Called by:
|
||
|
||
Side Effects:
|
||
|
||
Comments:
|
||
None
|
||
--*/
|
||
|
||
{
|
||
BYTE Dest[WINS_MAX_LINE_SZ];
|
||
BOOL fQuoted;
|
||
COMM_ADD_T NodeAdd;
|
||
LPBYTE pDest = Dest;
|
||
|
||
NodeAdd.AddLen = sizeof(COMM_IP_ADD_T);
|
||
NodeAdd.AddTyp_e = COMM_ADD_E_TCPUDPIP;
|
||
NodeAdd.Add.IPAdd = IPAdd;
|
||
|
||
//
|
||
// Form the name. If the name is < 16 characters, 0x20 will
|
||
// be put in the Sixteenth bytes
|
||
//
|
||
if (!ExpandName(Dest, pName, 0x20, &fQuoted))
|
||
{
|
||
DBGPRINT1(ERR, "Name (%s) has more than 16 characters\n", pName);
|
||
return;
|
||
}
|
||
|
||
NMSMSGF_MODIFY_NAME_IF_REQD_M(Dest);
|
||
|
||
NmsNmhNamRegInd(
|
||
NULL,
|
||
Dest,
|
||
strlen(Dest) + 1, //we always store the terminating
|
||
//NULL
|
||
&NodeAdd,
|
||
NMSMSGF_E_BNODE,
|
||
NULL,
|
||
0,
|
||
0,
|
||
FALSE, //it is a name registration (not a refresh)
|
||
NMSDB_ENTRY_IS_STATIC,
|
||
0 //not an administrative action
|
||
);
|
||
//
|
||
// If the name was not quoted, register the other two records
|
||
// (same name -- different suffixes)
|
||
//
|
||
if(!fQuoted)
|
||
{
|
||
#if 0
|
||
if (*pDest == 0x1B)
|
||
{
|
||
WINS_SWAP_BYTES_M(pDest, pDest + 15);
|
||
}
|
||
#endif
|
||
Dest[NON_CODED_NAME_SIZE - 2] = 0x3;
|
||
NmsNmhNamRegInd(
|
||
NULL,
|
||
Dest,
|
||
strlen(Dest) + 1, //we always store the terminating
|
||
//NULL
|
||
&NodeAdd,
|
||
NMSMSGF_E_BNODE,
|
||
NULL,
|
||
0,
|
||
0,
|
||
FALSE, //it is a name registration (not a refresh)
|
||
NMSDB_ENTRY_IS_STATIC,
|
||
0 //not an administrative action
|
||
);
|
||
|
||
Dest[NON_CODED_NAME_SIZE - 2] = 0x0;
|
||
NmsNmhNamRegInd(
|
||
NULL,
|
||
Dest,
|
||
strlen(Dest) + 2, //add 1 since terminating 0x0 is
|
||
//to be stored (will be taken
|
||
//as NULL by strlen
|
||
&NodeAdd,
|
||
NMSMSGF_E_BNODE,
|
||
NULL,
|
||
0,
|
||
0,
|
||
FALSE, //it is a name registration (not a refresh)
|
||
NMSDB_ENTRY_IS_STATIC,
|
||
0 //not an administrative action
|
||
);
|
||
}
|
||
return;
|
||
}
|
||
|
||
VOID
|
||
RegGrpName(
|
||
IN LPBYTE pName,
|
||
IN DWORD IPAdd,
|
||
IN DWORD TypeOfRec
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function registers a domain name
|
||
|
||
Arguments:
|
||
pName - Name to register
|
||
IpAdd - Address to register
|
||
|
||
Externals Used:
|
||
None
|
||
|
||
|
||
Return Value:
|
||
|
||
None
|
||
Error Handling:
|
||
|
||
Called by:
|
||
|
||
Side Effects:
|
||
|
||
Comments:
|
||
None
|
||
--*/
|
||
|
||
{
|
||
|
||
BYTE Dest[WINS_MAX_LINE_SZ];
|
||
BOOL fQuoted;
|
||
NMSMSGF_CNT_ADD_T CntAdd;
|
||
DWORD RecType;
|
||
BYTE SixteenthByte;
|
||
|
||
if (*pName == EOS)
|
||
{
|
||
WinsMscLogEvtStrs(pName, WINS_EVT_NAME_FMT_ERR, FALSE);
|
||
return;
|
||
}
|
||
|
||
//
|
||
// don't want 0 ip address to be put in
|
||
//
|
||
if (IPAdd)
|
||
{
|
||
CntAdd.NoOfAdds = 1;
|
||
CntAdd.Add[0].AddLen = sizeof(COMM_IP_ADD_T);
|
||
CntAdd.Add[0].AddTyp_e = COMM_ADD_E_TCPUDPIP;
|
||
CntAdd.Add[0].Add.IPAdd = IPAdd;
|
||
}
|
||
else
|
||
{
|
||
CntAdd.NoOfAdds = 0;
|
||
}
|
||
|
||
if (TypeOfRec != NMSDB_SPEC_GRP_ENTRY)
|
||
{
|
||
SixteenthByte = 0x20;
|
||
}
|
||
else
|
||
{
|
||
SixteenthByte = 0x1C;
|
||
}
|
||
|
||
//
|
||
// We can get called for domains, user. spec. grps and mh names.
|
||
//
|
||
RecType = (TypeOfRec == NMSDB_USER_SPEC_GRP_ENTRY) ?
|
||
NMSDB_SPEC_GRP_ENTRY : TypeOfRec;
|
||
//
|
||
// If the name length is < 16 characters, 0x20 or 0x1C will be put in
|
||
// the Sixteenth byte
|
||
//
|
||
if (!ExpandName(Dest, pName, SixteenthByte, &fQuoted))
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (RecType == NMSDB_MULTIHOMED_ENTRY)
|
||
{
|
||
//
|
||
// switch the 1st and Sixteenth bytes if the Sixteenth byte is a 0x1B. This
|
||
// is done only for non-group names
|
||
//
|
||
NMSMSGF_MODIFY_NAME_IF_REQD_M(Dest);
|
||
}
|
||
|
||
//
|
||
// register the group
|
||
//
|
||
NmsNmhNamRegGrp(
|
||
NULL,
|
||
Dest,
|
||
strlen(Dest) + 1, // to store the null
|
||
&CntAdd,
|
||
0, //Node type (not used)
|
||
NULL,
|
||
0,
|
||
0,
|
||
RecType,
|
||
FALSE, //it is a name registration (not a refresh)
|
||
NMSDB_ENTRY_IS_STATIC,
|
||
0 //not an administrative action
|
||
);
|
||
|
||
if (RecType == NMSDB_MULTIHOMED_ENTRY)
|
||
{
|
||
//
|
||
// If the name was not quoted, register the other two records
|
||
// (same name -- different suffixes)
|
||
//
|
||
if(!fQuoted)
|
||
{
|
||
Dest[NON_CODED_NAME_SIZE - 2] = 0x3;
|
||
NmsNmhNamRegGrp(
|
||
NULL,
|
||
Dest,
|
||
strlen(Dest) + 1, // to store the null
|
||
&CntAdd,
|
||
0, //Node type (not used)
|
||
NULL,
|
||
0,
|
||
0,
|
||
RecType,
|
||
FALSE, //it is a name registration (not a refresh)
|
||
NMSDB_ENTRY_IS_STATIC,
|
||
0 //not an administrative action
|
||
);
|
||
|
||
Dest[NON_CODED_NAME_SIZE - 2] = 0x0;
|
||
NmsNmhNamRegGrp(
|
||
NULL,
|
||
Dest,
|
||
strlen(Dest) + 2, // to store the null
|
||
&CntAdd,
|
||
0, //Node type (not used)
|
||
NULL,
|
||
0,
|
||
0,
|
||
RecType,
|
||
FALSE, //it is a name registration (not a refresh)
|
||
NMSDB_ENTRY_IS_STATIC,
|
||
0 //not an administrative action
|
||
);
|
||
}
|
||
}
|
||
return;
|
||
}
|
||
|
||
|
||
|
||
BOOL
|
||
ExpandName (
|
||
OUT LPBYTE pDest,
|
||
IN LPBYTE pSrc,
|
||
IN BYTE LastCh,
|
||
OUT LPBOOL pfQuoted
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function expands an lmhosts entry into a full 16 byte NetBIOS
|
||
name. It is padded with blanks up to 15 bytes; the Sixteenth byte is the
|
||
input parameter, last.
|
||
|
||
|
||
Both dest and source are NULL terminated strings.
|
||
|
||
Arguments:
|
||
|
||
pDest - sizeof(dest) must be WINSPRS_NONCODED_NMSZ
|
||
pSrc - the lmhosts entry
|
||
LastCh - the Sixteenth byte of the NetBIOS name
|
||
pfQuoted - flag to indicate whether the string was quoted or not
|
||
|
||
Return Value:
|
||
None
|
||
--*/
|
||
|
||
|
||
{
|
||
BYTE Ch;
|
||
DWORD i = 0;
|
||
LPBYTE pFrom = pSrc;
|
||
LPBYTE pTo = pDest;
|
||
|
||
// Detect if it is quoted name..
|
||
*pfQuoted = (*pFrom == QUOTE_CHAR);
|
||
// ..and skip the initial quote char
|
||
pFrom += *pfQuoted;
|
||
|
||
// count for as many chars as are in a legal NetBios name (15) plus
|
||
// the terminating char. (NON_CODED_NAME_SIZE is #defined to be 17)
|
||
for (i = 0; i < NON_CODED_NAME_SIZE - 1; i++)
|
||
{
|
||
// get the next char from the name
|
||
Ch = *(pFrom++);
|
||
|
||
// check if it is a terminating char
|
||
if (!Ch || (*pfQuoted ? Ch == QUOTE_CHAR : Ch == NEWLINE_CHAR))
|
||
break;
|
||
|
||
// check if the name doesn't exceed the legal 15 chars
|
||
if (i == NON_CODED_NAME_SIZE - 2)
|
||
{
|
||
// We have picked up 15 characters already and there are more in the name
|
||
// This is illegal so log error and bail out
|
||
DBGPRINT1(ERR, "Name (%s) has more than 16 characters\n", pSrc);
|
||
WinsMscLogEvtStrs(pSrc, WINS_EVT_BAD_NAME, FALSE);
|
||
return FALSE;
|
||
}
|
||
|
||
// If the char is a leading DBCS byte then accept the extended char as it
|
||
// is (take the trailing byte and go on.
|
||
if (IsDBCSLeadByteEx(CP_ACP, Ch))
|
||
{
|
||
*pTo++ = Ch;
|
||
*pTo++ = *pFrom++;
|
||
continue;
|
||
}
|
||
|
||
// If the name is not quoted, map lower case alpha chars to upper case.
|
||
// Note: don't use _toupper since _toupper does not check whether its
|
||
// argument is indeed a lowercase char.
|
||
if (!*pfQuoted && IsCharAlpha(Ch))
|
||
{
|
||
if(IsCharLower(Ch))
|
||
{
|
||
LPBYTE pCh;
|
||
BYTE sCh[2];
|
||
sCh[0] = Ch;
|
||
sCh[1] = (BYTE)NULL;
|
||
|
||
pCh = (LPBYTE)CharUpperA(sCh);
|
||
Ch = *pCh;
|
||
}
|
||
}
|
||
|
||
// Check if we have hex value in the name
|
||
if (Ch == BACKSLASH_CHAR)
|
||
{
|
||
DWORD NoOfChar;
|
||
INT NumValue = 0;
|
||
CHAR Ch2;
|
||
BOOL fFailed = FALSE;
|
||
|
||
// the hex value can be either \A3 or \xFC (obviously with any kind of hex digits)
|
||
Ch = *pFrom;
|
||
Ch2 = *(pFrom+1);
|
||
|
||
if (Ch == BACKSLASH_CHAR)
|
||
{
|
||
// '\\' should be seen as one '\', hence keep Ch as it is and break from switch
|
||
pFrom++;
|
||
}
|
||
else
|
||
{
|
||
if ((Ch == X_CHAR || Ch == x_CHAR) ||
|
||
(Ch == ZERO_CHAR && (Ch2 == X_CHAR || Ch2 == x_CHAR))
|
||
)
|
||
{
|
||
DBGPRINT1(TMP, "Parsing hex num %s\n", pFrom);
|
||
// skip over x or 0x.
|
||
pFrom += (Ch == X_CHAR || Ch == x_CHAR) ? 1 : 2;
|
||
// we do have a hex number here. Pick up at most the first two digits.
|
||
fFailed = (sscanf(pFrom, "%2x%n", &NumValue, &NoOfChar) == 0 || NoOfChar == 0);
|
||
|
||
DBGPRINT2(TMP, "fFailed=%d; HexNumValue=0x%x\n", fFailed, NumValue);
|
||
}
|
||
else
|
||
{
|
||
DBGPRINT1(TMP, "Parsing dec num %s\n", pFrom);
|
||
// it might be a decimal number. Pick up at most the first 3 digits.
|
||
fFailed = (sscanf(pFrom, "%3u%n", &NumValue, &NoOfChar) == 0 || NoOfChar == 0 || NumValue > 255);
|
||
|
||
DBGPRINT2(TMP, "fFailed=%d; DecNumValue=%u\n", fFailed, NumValue);
|
||
}
|
||
|
||
if (fFailed)
|
||
{
|
||
// log an event and bail out with error.
|
||
DBGPRINT1(ERR, "Name (%s) contains incorrectly formed character code.\n", pSrc);
|
||
WinsMscLogEvtStrs(pSrc, WINS_EVT_BAD_CHARCODING, FALSE);
|
||
return FALSE;
|
||
}
|
||
|
||
// everything went fine, copy the hex value back to Ch
|
||
Ch = (BYTE)NumValue;
|
||
// and make sure to advance on the pFrom string
|
||
pFrom += NoOfChar;
|
||
}
|
||
}
|
||
|
||
// finally copy the char to the destination string
|
||
*pTo = Ch;
|
||
// advance with the pointer on the destination string
|
||
pTo++;
|
||
} //end of for loop
|
||
|
||
// if there were less than expected char, form the valid netbios name
|
||
// by padding it with spaces
|
||
for (;i < NON_CODED_NAME_SIZE - 2; i++, pTo++)
|
||
*pTo = SPACE_CHAR;
|
||
|
||
*pTo = (BYTE)NULL;
|
||
*(pTo+1) = (BYTE)NULL;
|
||
CheckForInt(pDest, *pfQuoted);
|
||
|
||
// at the end, append the LastCh (16th byte) to the name.
|
||
*pTo = LastCh;
|
||
|
||
return(TRUE);
|
||
} // ExpandName
|
||
|
||
VOID
|
||
CheckForInt(
|
||
LPBYTE pDest,
|
||
BOOL fQuoted
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
This function munges the name so that if there are any characters
|
||
from a different code set, they are converted properly
|
||
|
||
Arguments:
|
||
|
||
|
||
Externals Used:
|
||
None
|
||
|
||
|
||
Return Value:
|
||
|
||
Success status codes --
|
||
Error status codes --
|
||
|
||
Error Handling:
|
||
|
||
Called by:
|
||
|
||
Side Effects:
|
||
|
||
Comments:
|
||
None
|
||
--*/
|
||
|
||
{
|
||
WCHAR UnicodeBuf[255];
|
||
UNICODE_STRING UnicodeStr;
|
||
STRING TmpStr;
|
||
NTSTATUS NTStatus;
|
||
|
||
DBGENTER("CheckForInt\n");
|
||
//
|
||
// Now, convert to UNICODE then to OEM to force the ANSI -> OEM munge.
|
||
// Then convert back to UNICODE and uppercase the name. Finally convert
|
||
// back to OEM.
|
||
//
|
||
UnicodeStr.Length = 0;
|
||
UnicodeStr.MaximumLength = sizeof(UnicodeBuf);
|
||
UnicodeStr.Buffer = UnicodeBuf;
|
||
|
||
RtlInitString(&TmpStr, pDest);
|
||
|
||
NTStatus = RtlAnsiStringToUnicodeString(&UnicodeStr, &TmpStr, FALSE);
|
||
|
||
if (!NT_SUCCESS(NTStatus))
|
||
{
|
||
DBGPRINT1(ERR, "CheckForInt: Ansi -> Unicode failed, NTStatus %X\n",
|
||
NTStatus);
|
||
goto ERROR_PROC;
|
||
}
|
||
|
||
NTStatus = RtlUnicodeStringToOemString(&TmpStr, &UnicodeStr, FALSE);
|
||
|
||
if (!NT_SUCCESS(NTStatus))
|
||
{
|
||
DBGPRINT1(ERR, "CheckForInt: Unicode -> Oem failed, NTStatus %X\n",
|
||
NTStatus);
|
||
goto ERROR_PROC;
|
||
}
|
||
|
||
NTStatus = RtlOemStringToUnicodeString(&UnicodeStr, &TmpStr, FALSE);
|
||
|
||
if (!NT_SUCCESS(NTStatus))
|
||
{
|
||
DBGPRINT1(ERR, "CheckForInt: Oem -> Unicode failed, NTStatus %X\n",
|
||
NTStatus);
|
||
goto ERROR_PROC;
|
||
}
|
||
|
||
|
||
if (!fQuoted)
|
||
NTStatus = RtlUpcaseUnicodeStringToOemString(&TmpStr, &UnicodeStr, FALSE);
|
||
else
|
||
NTStatus = RtlUnicodeStringToOemString(&TmpStr, &UnicodeStr, FALSE);
|
||
|
||
if (!NT_SUCCESS(NTStatus))
|
||
{
|
||
DBGPRINT1(ERR, "CheckForInt: Unicode -> Oem failed, NTStatus %X\n",
|
||
NTStatus);
|
||
goto ERROR_PROC;
|
||
}
|
||
ERROR_PROC:
|
||
DBGLEAVE("CheckForInt\n");
|
||
return;
|
||
}
|
||
|
||
STATUS
|
||
WinsPrsDoStaticInit(
|
||
IN PWINSCNF_DATAFILE_INFO_T pDataFile,
|
||
IN DWORD NoOfFiles,
|
||
IN BOOL fAsync
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
This function is called to do the STATIC initialization of the WINS
|
||
db
|
||
|
||
Arguments:
|
||
pDataFiles - Pointer to buffer containing one or more data file
|
||
structures (PWINSCNF_DATAFILE_INFO_T)
|
||
|
||
Externals Used:
|
||
None
|
||
|
||
|
||
Return Value:
|
||
|
||
None
|
||
Error Handling:
|
||
|
||
Called by:
|
||
Init()
|
||
Side Effects:
|
||
|
||
Comments:
|
||
None
|
||
--*/
|
||
|
||
{
|
||
DWORD ThdId;
|
||
PFILE_PARAM_T pFileParam;
|
||
STATUS RetStat = WINS_SUCCESS;
|
||
HANDLE sThdHdl = NULL;
|
||
|
||
try {
|
||
WinsMscAlloc(sizeof(FILE_PARAM_T), &pFileParam);
|
||
pFileParam->pDataFile = pDataFile;
|
||
pFileParam->NoOfFiles = NoOfFiles;
|
||
if (fAsync)
|
||
{
|
||
sThdHdl =
|
||
WinsMscCreateThd(DoStaticInitThdFn, pFileParam, &ThdId);
|
||
//
|
||
// We don't need the handle, so let us close it
|
||
//
|
||
CloseHandle(sThdHdl);
|
||
}
|
||
else
|
||
{
|
||
RetStat = DoStaticInitThdFn(pFileParam);
|
||
}
|
||
}
|
||
except(EXCEPTION_EXECUTE_HANDLER) {
|
||
DBGPRINTEXC("WinsPrsDoStaticInit");
|
||
WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_STATIC_INIT_ERR);
|
||
}
|
||
return(RetStat);
|
||
}
|
||
|
||
DWORD
|
||
DoStaticInitThdFn(
|
||
IN LPVOID pThdParam
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
This thread reads one or more files to do STATIC initialization
|
||
|
||
Arguments:
|
||
|
||
|
||
Externals Used:
|
||
None
|
||
|
||
|
||
Return Value:
|
||
|
||
Success status codes --
|
||
Error status codes --
|
||
|
||
Error Handling:
|
||
|
||
Called by:
|
||
|
||
Side Effects:
|
||
|
||
Comments:
|
||
None
|
||
--*/
|
||
|
||
{
|
||
WINSPRS_FILE_INFO_T FileInfo;
|
||
DWORD i;
|
||
PWINSCNF_DATAFILE_INFO_T pDataFile =
|
||
(((PFILE_PARAM_T)pThdParam)->pDataFile);
|
||
DWORD NoOfFiles =
|
||
(((PFILE_PARAM_T)pThdParam)->NoOfFiles);
|
||
LPVOID pSvDataFilePtr = pDataFile;
|
||
DWORD RetStat = WINS_SUCCESS;
|
||
|
||
//
|
||
// initialize this thread with the db engine
|
||
//
|
||
// This is not an RPC thread. It could have been created either by
|
||
// the main thread (doing an init/reinit) or by an rpc thread. For
|
||
// either case, we do not want the counter NmsTermThdCnt to be
|
||
// incremented in NmsDbThdInit(). Instead of passing a client
|
||
// var to indicate which thread invoked it, we call it an RPC
|
||
// thread to have NmsDbThdInit do the right thing. NmsDbOpenTables
|
||
// will also do the right thing.
|
||
//
|
||
NmsDbThdInit(WINS_E_WINSRPC);
|
||
NmsDbOpenTables(WINS_E_WINSRPC);
|
||
|
||
EnterCriticalSection(&WinsIntfCrtSec);
|
||
WinsIntfNoCncrntStaticInits++;
|
||
LeaveCriticalSection(&WinsIntfCrtSec);
|
||
try {
|
||
|
||
for (
|
||
i = 0;
|
||
i < NoOfFiles;
|
||
i++, pDataFile = (PWINSCNF_DATAFILE_INFO_T)((LPBYTE)pDataFile +
|
||
WINSCNF_FILE_INFO_SZ)
|
||
)
|
||
{
|
||
//
|
||
// Open the file
|
||
//
|
||
if (
|
||
!WinsMscOpenFile(
|
||
pDataFile->FileNm,
|
||
pDataFile->StrType,
|
||
&FileInfo.FileHdl
|
||
)
|
||
)
|
||
{
|
||
WINSEVT_STRS_T EvtStrs;
|
||
#ifndef UNICODE
|
||
DBGPRINT1(ERR, "WinsPrsDoStaticInit: Could not open file= (%s)\n", pDataFile->FileNm);
|
||
#else
|
||
|
||
|
||
#ifdef WINSDBG
|
||
IF_DBG(ERR)
|
||
{
|
||
wprintf(L"WinsPrsDoStatisInit: Could not open file = (%s)\n", pDataFile->FileNm);
|
||
}
|
||
#endif
|
||
#endif
|
||
EvtStrs.NoOfStrs = 1;
|
||
EvtStrs.pStr[0] = pDataFile->FileNm;
|
||
WINSEVT_LOG_STR_M(WINS_EVT_CANT_OPEN_DATAFILE, &EvtStrs);
|
||
RetStat = WINS_FAILURE;
|
||
continue;
|
||
}
|
||
|
||
#ifndef UNICODE
|
||
DBGPRINT1(DET, "WinsPrsDoStaticInit: Opened file (%s) for doing STATIC initialization\n", pDataFile->FileNm);
|
||
#else
|
||
#ifdef WINSDBG
|
||
IF_DBG(ERR)
|
||
{
|
||
wprintf(L"WinsPrsDoStatisInit: Opened file (%s) for doing STATIC initialization\n", pDataFile->FileNm);
|
||
}
|
||
#endif
|
||
#endif
|
||
//
|
||
// Map the file into allocated memory
|
||
//
|
||
if(!WinsMscMapFile(&FileInfo))
|
||
{
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// prime the db
|
||
//
|
||
PrimeDb(&FileInfo);
|
||
|
||
} // end of for loop
|
||
} // end of try ..
|
||
except(EXCEPTION_EXECUTE_HANDLER) {
|
||
DBGPRINTEXC("DoStaticInitThdFn");
|
||
WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_STATIC_INIT_ERR);
|
||
}
|
||
|
||
EnterCriticalSection(&WinsIntfCrtSec);
|
||
WinsIntfNoCncrntStaticInits--;
|
||
LeaveCriticalSection(&WinsIntfCrtSec);
|
||
|
||
//
|
||
// Let us end the session
|
||
//
|
||
try {
|
||
NmsDbCloseTables();
|
||
NmsDbEndSession();
|
||
}
|
||
except (EXCEPTION_EXECUTE_HANDLER) {
|
||
DBGPRINTEXC("DoStaticInit: During wrap up");
|
||
}
|
||
|
||
//
|
||
// Deallocate the memory
|
||
//
|
||
ASSERT(pSvDataFilePtr != NULL);
|
||
WinsMscDealloc(pSvDataFilePtr);
|
||
//
|
||
// Be sure to deallocate the thread param
|
||
//
|
||
WinsMscDealloc(pThdParam);
|
||
|
||
// ExitThread(WINS_SUCCESS);
|
||
return(RetStat); //to shutup compiler warning
|
||
}
|
||
|
||
BOOL
|
||
ChkAdd(
|
||
LPBYTE pstrAdd,
|
||
LPDWORD pAdd
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
This function converts a dotted decimel ip address to
|
||
a DWORD. We don't use inet_addr() to do this, since it
|
||
returns 0xFFFFFFFF for an address that has one of its
|
||
parts > 255 and returns some value for an invalid address
|
||
(for example, one with 3 dots)
|
||
|
||
Arguments:
|
||
|
||
|
||
Externals Used:
|
||
None
|
||
|
||
|
||
Return Value:
|
||
|
||
Success status codes --
|
||
Error status codes --
|
||
|
||
Error Handling:
|
||
|
||
Called by:
|
||
|
||
Side Effects:
|
||
|
||
Comments:
|
||
None
|
||
--*/
|
||
|
||
{
|
||
|
||
BYTE Tmp[WINS_MAX_LINE_SZ];
|
||
DWORD Word[4];
|
||
LPBYTE pPos;
|
||
DWORD Count = 0;
|
||
BOOL fInvalid = FALSE;
|
||
|
||
//
|
||
// We must see three dots
|
||
//
|
||
while(Count < 4)
|
||
{
|
||
if ((pPos = strchr(pstrAdd, (int)'.')) != NULL)
|
||
{
|
||
|
||
do
|
||
{
|
||
//
|
||
// Copy all chars before the dot
|
||
//
|
||
(void)RtlCopyMemory(Tmp, pstrAdd, pPos - pstrAdd);
|
||
|
||
//
|
||
// Put a NULL at the end
|
||
//
|
||
Tmp[pPos - pstrAdd] = EOS;
|
||
Word[Count] = (DWORD)atol(Tmp);
|
||
|
||
//
|
||
//atol returns 0 if it can not convert
|
||
//but 0 can be a valid return too (if we have '0' to
|
||
// connvert
|
||
//
|
||
if (Word[Count] == 0)
|
||
{
|
||
if (Tmp[0] != '0')
|
||
{
|
||
fInvalid = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (Word[Count] > 255)
|
||
{
|
||
fInvalid = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
Count++;
|
||
pstrAdd = ++pPos;
|
||
} while ((Count == 3) && (pPos = pstrAdd + strlen(pstrAdd)));
|
||
if (fInvalid)
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// less than 3 dots seen, break out of the loop
|
||
//
|
||
break;
|
||
}
|
||
} // end of while (Count < 4)
|
||
if ((Count < 4) || fInvalid)
|
||
{
|
||
return(FALSE);
|
||
}
|
||
else
|
||
{
|
||
*pAdd = (LONG)((Word[0] << 24) + (Word[1] << 16) +
|
||
(Word[2] << 8) + Word[3]);
|
||
}
|
||
return(TRUE);
|
||
}
|
||
|
||
|
||
#if 0
|
||
VOID
|
||
GetFullPath(
|
||
IN LPBYTE pTarget,
|
||
OUT LPBYTE pPath
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function returns the full path of the STATIC file. This is done
|
||
by forming a unicode string from the concatenation of the C strings
|
||
DatabasePath and the string, file.
|
||
|
||
You must RtlFreeUnicodeString(path) after calling this function
|
||
successfully !
|
||
|
||
Arguments:
|
||
|
||
target - the name of the file. This can either be a full path name
|
||
or a mere file name.
|
||
path - a pointer to a UNICODE_STRING structure
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS if successful.
|
||
|
||
Notes:
|
||
|
||
RtlMoveMemory() handles overlapped copies; RtlCopyMemory() doesn't.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
ULONG unicodesize;
|
||
STRING directory, file, prefix, remote;
|
||
|
||
RtlInitString(&prefix, "\\DosDevices");
|
||
RtlInitString(&remote, "\\DosDevices\\UNC");
|
||
|
||
//
|
||
// if the target begins with a '\', or contains a DOS drive letter,
|
||
// then assume that it specifies a full path. Otherwise, prepend the
|
||
// default directory, DatabasePath, to create a full path.
|
||
//
|
||
//
|
||
if ((*target == '\\') || (target[1] == ':')) {
|
||
|
||
RtlInitString(&directory, target);
|
||
RtlInitString(&file, NULL);
|
||
}
|
||
else {
|
||
RtlInitString(&directory, DatabasePath);
|
||
RtlInitString(&file, target);
|
||
}
|
||
|
||
ASSERT(RtlAnsiStringToUnicodeSize(&prefix) <=
|
||
RtlAnsiStringToUnicodeSize(&remote));
|
||
|
||
unicodesize = RtlAnsiStringToUnicodeSize(&remote) +
|
||
RtlAnsiStringToUnicodeSize(&directory) +
|
||
RtlAnsiStringToUnicodeSize(&file) +
|
||
2 * sizeof(OBJ_NAME_PATH_SEPARATOR) +
|
||
sizeof(UNICODE_NULL);
|
||
|
||
path->Length = 0;
|
||
path->MaximumLength = (USHORT) unicodesize;
|
||
path->Buffer = ExAllocatePool(NonPagedPool, unicodesize);
|
||
|
||
if (!path->Buffer) {
|
||
return(STATUS_NO_MEMORY);
|
||
}
|
||
|
||
//
|
||
// does the directory specify a DOS drive ?
|
||
//
|
||
// If the second character of directory is a colon, then it must specify
|
||
// a DOS drive. If so, it must be prefixed with "\\DosDevices".
|
||
//
|
||
//
|
||
if (directory.Buffer[1] == ':') {
|
||
status = LmpConcatenate(path, &prefix);
|
||
|
||
if (status != STATUS_SUCCESS) {
|
||
path->MaximumLength = 0;
|
||
ExFreePool(path->Buffer);
|
||
return(status);
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// does the directory specify a remote file ?
|
||
//
|
||
// If so, it must be prefixed with "\\DosDevices\\UNC", and the double
|
||
// slashes of the UNC name eliminated.
|
||
//
|
||
//
|
||
if ((directory.Buffer[0] == '\\') && (directory.Buffer[1] == '\\')) {
|
||
status = LmpConcatenate(path, &remote);
|
||
|
||
if (status != STATUS_SUCCESS) {
|
||
path->MaximumLength = 0;
|
||
ExFreePool(path->Buffer);
|
||
return(status);
|
||
}
|
||
|
||
directory.Length--;
|
||
|
||
ASSERT(((ULONG) directory.Length - 1) > 0);
|
||
|
||
RtlMoveMemory( // overlapped copy
|
||
&(directory.Buffer[1]), // Destination
|
||
&(directory.Buffer[2]), // Source
|
||
(ULONG) directory.Length - 1); // Length
|
||
}
|
||
|
||
|
||
//
|
||
// is the first part of the directory "%SystemRoot%" ?
|
||
//
|
||
// If so, it must be changed to "\\SystemRoot\\".
|
||
//
|
||
// 0123456789 123456789 1
|
||
// %SystemRoot%\somewhere
|
||
//
|
||
//
|
||
if (strncmp(directory.Buffer, "%SystemRoot%", 12) == 0) {
|
||
|
||
directory.Buffer[0] = '\\';
|
||
directory.Buffer[11] = '\\';
|
||
|
||
if (directory.Buffer[12] == '\\') {
|
||
ASSERT(directory.Length >= 13);
|
||
|
||
if (directory.Length > 13) {
|
||
RtlMoveMemory( // overlapped copy
|
||
&(directory.Buffer[12]), // Destination
|
||
&(directory.Buffer[13]), // Source
|
||
(ULONG) directory.Length - 13); // Length
|
||
|
||
directory.Buffer[directory.Length - 1] = (CHAR) NULL;
|
||
}
|
||
|
||
directory.Length--;
|
||
}
|
||
}
|
||
|
||
status = LmpConcatenate(path, &directory);
|
||
|
||
if (status != STATUS_SUCCESS) {
|
||
path->MaximumLength = 0;
|
||
ExFreePool(path->Buffer);
|
||
return(status);
|
||
}
|
||
|
||
if (!(file.Length)) {
|
||
return(status);
|
||
}
|
||
|
||
status = LmpConcatenate(path, &file);
|
||
|
||
if (status != STATUS_SUCCESS) {
|
||
path->MaximumLength = 0;
|
||
ExFreePool(path->Buffer);
|
||
return(status);
|
||
}
|
||
|
||
return(STATUS_SUCCESS);
|
||
|
||
} // LmGetFullPath
|
||
#endif
|
||
|