Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

744 lines
15 KiB

  1. /*++
  2. Copyright (c) 1994-1999 Microsoft Corporation
  3. Module Name :
  4. sitesecu.cpp
  5. Abstract:
  6. Site Security property page
  7. Author:
  8. Ronald Meijer (ronaldm)
  9. Project:
  10. Internet Services Manager (cluster edition)
  11. Revision History:
  12. --*/
  13. //
  14. // Include Files
  15. //
  16. #include "stdafx.h"
  17. #include "common.h"
  18. #undef dllexp
  19. #include <tcpdllp.hxx>
  20. #define _RDNS_STANDALONE
  21. #include <rdns.hxx>
  22. #ifdef _DEBUG
  23. #undef THIS_FILE
  24. static char BASED_CODE THIS_FILE[] = __FILE__;
  25. #endif // _DEBUG
  26. //#ifdef _DEBUG
  27. //
  28. // Careful here... This may cause build failure
  29. //
  30. extern "C" DEBUG_PRINTS * g_pDebug = NULL;
  31. //#endif // _DEBUG
  32. #define new DEBUG_NEW
  33. CIPAccessDescriptor::CIPAccessDescriptor(
  34. IN BOOL fGranted
  35. )
  36. /*++
  37. Routine Description:
  38. Dummy Constructor for access description object. Assumes a single IP
  39. address of 0.0.0.0
  40. Arguments:
  41. BOOL fGranted : TRUE for 'grant' access, FALSE for 'deny' access
  42. Return Value:
  43. N/A
  44. --*/
  45. : m_fGranted(fGranted),
  46. m_adtType(CIPAccessDescriptor::ADT_SINGLE),
  47. m_iaIPAddress(NULL_IP_ADDRESS),
  48. m_iaSubnetMask(NULL_IP_MASK),
  49. m_strDomain()
  50. {
  51. }
  52. CIPAccessDescriptor::CIPAccessDescriptor(
  53. IN const CIPAccessDescriptor & ac
  54. )
  55. /*++
  56. Routine Description:
  57. Copy constructor for access description object
  58. Arguments:
  59. const CIPAccessDescriptor & ac : Source access description object
  60. Return Value:
  61. N/A
  62. --*/
  63. : m_fGranted(ac.m_fGranted),
  64. m_adtType(ac.m_adtType),
  65. m_iaIPAddress(ac.m_iaIPAddress),
  66. m_iaSubnetMask(ac.m_iaSubnetMask),
  67. m_strDomain(ac.m_strDomain)
  68. {
  69. }
  70. CIPAccessDescriptor::CIPAccessDescriptor(
  71. IN BOOL fGranted,
  72. IN DWORD dwIPAddress,
  73. IN DWORD dwSubnetMask, OPTIONAL
  74. IN BOOL fNetworkByteOrder OPTIONAL
  75. )
  76. /*++
  77. Routine Description:
  78. Constructor for ip range (ip address/subnet mask pair)
  79. access description object.
  80. Arguments:
  81. BOOL fGranted : TRUE for 'grant' access, FALSE for 'deny' access
  82. DWORD dwIPAddress : IP Address
  83. DWORD dwSubnetMask : The subnet mask or 0xffffffff
  84. BOOL fNetworkByteOrder : If TRUE, the ip address and subnet mask are in
  85. network byte order
  86. Return Value:
  87. N/A
  88. --*/
  89. {
  90. SetValues(fGranted, dwIPAddress, dwSubnetMask, fNetworkByteOrder);
  91. }
  92. CIPAccessDescriptor::CIPAccessDescriptor(
  93. IN BOOL fGranted,
  94. IN LPCTSTR lpstrDomain
  95. )
  96. /*++
  97. Routine Description:
  98. Constructor for domain name access description object.
  99. Arguments:
  100. BOOL fGranted : TRUE for 'grant' access, FALSE for 'deny' access
  101. LPCTSTR lpstrDomain : The domain name
  102. Return Value:
  103. N/A
  104. --*/
  105. {
  106. SetValues(fGranted, lpstrDomain);
  107. }
  108. void
  109. CIPAccessDescriptor::SetValues(
  110. IN BOOL fGranted,
  111. IN DWORD dwIPAddress,
  112. IN DWORD dwSubnetMask,
  113. IN BOOL fNetworkByteOrder OPTIONAL
  114. )
  115. /*++
  116. Routine Description:
  117. Set values for 'ip range (ip address and subnet mask)' access descriptor,
  118. or a single ip address if the mask is 0xffffffff
  119. Arguments:
  120. BOOL fGranted : TRUE for 'grant' access, FALSE for 'deny' access
  121. DWORD dwIPAddress : IP Address
  122. DWORD dwSubnetMask : The subnet mask or ffffffff
  123. BOOL fNetworkByteOrder : If TRUE, the ip address and subnet mask are in
  124. network byte order
  125. Return Value:
  126. None
  127. Notes:
  128. If the subnetmask is 0xffffffff this describes a single ip address.
  129. --*/
  130. {
  131. m_fGranted = fGranted;
  132. m_adtType = (dwSubnetMask == NULL_IP_MASK) ? ADT_SINGLE : ADT_MULTIPLE;
  133. m_iaIPAddress = CIPAddress(dwIPAddress, fNetworkByteOrder);
  134. m_iaSubnetMask = CIPAddress(dwSubnetMask, fNetworkByteOrder);
  135. //
  136. // Not used:
  137. //
  138. m_strDomain.Empty();
  139. }
  140. void
  141. CIPAccessDescriptor::SetValues(
  142. IN BOOL fGranted,
  143. IN LPCTSTR lpstrDomain
  144. )
  145. /*++
  146. Routine Description:
  147. Set values for 'domain name' access descriptor
  148. Arguments:
  149. BOOL fGranted : TRUE for 'grant' access, FALSE for 'deny' access
  150. LPCTSTR lpstrDomain : The domain name
  151. Return Value:
  152. None
  153. --*/
  154. {
  155. m_fGranted = fGranted;
  156. m_adtType = ADT_DOMAIN;
  157. try
  158. {
  159. m_strDomain = lpstrDomain;
  160. }
  161. catch(CMemoryException * e)
  162. {
  163. TRACEEOLID("!!!exception assigning domain name");
  164. e->ReportError();
  165. e->Delete();
  166. }
  167. //
  168. // Not used:
  169. //
  170. m_iaIPAddress.SetZeroValue();
  171. m_iaSubnetMask.SetZeroValue();
  172. }
  173. BOOL
  174. CIPAccessDescriptor::DuplicateInList(
  175. IN CObListPlus & oblList
  176. )
  177. /*++
  178. Routine Description:
  179. Check to see if a duplicate exists in the provided oblist
  180. Arguments:
  181. CObListPlus & oblList
  182. Return Value:
  183. TRUE if a duplicate exists, FALSE otherwise.
  184. Notes:
  185. As there's no information how this list might be sorted at this point,
  186. and the list is likely to be small, the search is sequential.
  187. --*/
  188. {
  189. CObListIter obli(oblList);
  190. CIPAccessDescriptor * pAccess;
  191. TRACEEOLID("Looking for duplicate access descriptors");
  192. while (pAccess = (CIPAccessDescriptor *)obli.Next())
  193. {
  194. ASSERT_READ_PTR(pAccess);
  195. //
  196. // Eliminate the item itself from the list, and look
  197. // only for duplicates.
  198. //
  199. if (pAccess != this && *this == *pAccess)
  200. {
  201. TRACEEOLID("Duplicate access descriptor found");
  202. return TRUE;
  203. }
  204. }
  205. TRACEEOLID("No duplicate access descriptor found");
  206. return FALSE;
  207. }
  208. BOOL
  209. CIPAccessDescriptor::operator ==(
  210. IN const CIPAccessDescriptor & ac
  211. ) const
  212. /*++
  213. Routine Description:
  214. Compare against another access descriptor.
  215. Arguments:
  216. const CIPAccessDescriptor & ac : Object to be compared against
  217. Return Value:
  218. TRUE if the two are identical
  219. --*/
  220. {
  221. if ( m_fGranted != ac.m_fGranted
  222. || m_adtType != ac.m_adtType)
  223. {
  224. return FALSE;
  225. }
  226. if (IsDomainName())
  227. {
  228. return m_strDomain.CompareNoCase(ac.m_strDomain) == 0;
  229. }
  230. return m_iaIPAddress == ac.m_iaIPAddress
  231. && m_iaSubnetMask == ac.m_iaSubnetMask;
  232. }
  233. int
  234. CIPAccessDescriptor::OrderByAddress(
  235. IN const CObjectPlus * pobAccess
  236. ) const
  237. /*++
  238. Routine Description:
  239. Compare two access descriptors against each other.
  240. Sorting criteria are in the following order:
  241. 1) 'Granted' sorts before 'Denied'
  242. 2) Domain names are sorted before ip addresses, and are
  243. sorted alphabetically.
  244. 3) IP Address and IP Address/subnet mask pairs are sorted
  245. by ip address.
  246. Arguments:
  247. const CObjectPlus * pobAccess : This really refers to another
  248. CIPAccessDescriptor to be compared to.
  249. Return Value:
  250. Sort (+1, 0, -1) return value
  251. --*/
  252. {
  253. const CIPAccessDescriptor * pob = (CIPAccessDescriptor *)pobAccess;
  254. //
  255. // First sort by access/denied
  256. //
  257. int n1 = HasAccess() ? 1 : 0;
  258. int n2 = pob->HasAccess() ? 1 : 0;
  259. if (n2 != n1)
  260. {
  261. //
  262. // Grant sorts before denied
  263. //
  264. return n2 - n1;
  265. }
  266. //
  267. // Secondly, try to sort by domain name (domain name sorts before
  268. // ip address and ip address/subnet mask objects)
  269. //
  270. n1 = IsDomainName() ? 1 : 0;
  271. n2 = pob->IsDomainName() ? 1 : 0;
  272. if (n1 != n2)
  273. {
  274. //
  275. // Domain names sort before ip addresses
  276. //
  277. return n2 - n1;
  278. }
  279. if (n1 && n2)
  280. {
  281. //
  282. // Both are domain names. Sort alphabetically
  283. //
  284. return ::lstrcmpi(QueryDomainName(), pob->QueryDomainName());
  285. }
  286. //
  287. // IP address is the third key.
  288. //
  289. return QueryIPAddress().CompareItem(pob->QueryIPAddress());
  290. }
  291. DWORD
  292. AddAccessEntries(
  293. IN ADDRESS_CHECK & ac,
  294. IN BOOL fName,
  295. IN BOOL fGrant,
  296. OUT CObListPlus & oblAccessList,
  297. OUT DWORD & cEntries
  298. )
  299. /*++
  300. Routine Description:
  301. Add specific kind of addresses from the list to the oblist of
  302. access entries
  303. Arguments:
  304. ADDRESS_CHECK & ac : Address list input object
  305. BOOL fName : TRUE for names, FALSE for ip
  306. BOOL fGrant : TRUE for granted, FALSE for denied
  307. CObListPlus & oblAccessList : ObList to add access entries to
  308. int & cEntries : Returns the number of entries
  309. Return Value:
  310. Error code
  311. Notes:
  312. Sentinel entries (ip 0.0.0.0) are not added to the oblist, but
  313. are reflected in the cEntries return value
  314. --*/
  315. {
  316. DWORD i;
  317. DWORD dwFlags;
  318. if (fName)
  319. {
  320. //
  321. // Domain names
  322. //
  323. LPSTR lpName;
  324. cEntries = ac.GetNbName(fGrant);
  325. for (i = 0L; i < cEntries; ++i)
  326. {
  327. if (ac.GetName(fGrant, i, &lpName, &dwFlags))
  328. {
  329. CString strDomain(lpName);
  330. if (!(dwFlags & DNSLIST_FLAG_NOSUBDOMAIN))
  331. {
  332. strDomain = _T("*.") + strDomain;
  333. }
  334. oblAccessList.AddTail(new CIPAccessDescriptor(fGrant, strDomain));
  335. }
  336. }
  337. }
  338. else
  339. {
  340. //
  341. // IP Addresses
  342. //
  343. LPBYTE lpMask;
  344. LPBYTE lpAddr;
  345. cEntries = ac.GetNbAddr(fGrant);
  346. for (i = 0L; i < cEntries; ++i)
  347. {
  348. if (ac.GetAddr(fGrant, i, &dwFlags, &lpMask, &lpAddr))
  349. {
  350. DWORD dwIP = MAKEIPADDRESS(lpAddr[0], lpAddr[1], lpAddr[2], lpAddr[3]);
  351. DWORD dwMask = MAKEIPADDRESS(lpMask[0], lpMask[1], lpMask[2], lpMask[3]);
  352. if (dwIP == NULL_IP_ADDRESS && dwMask == NULL_IP_MASK)
  353. {
  354. //
  355. // Sentinel in the grant list is not added, but
  356. // also not subtracted from the count of entries,
  357. // which is correct behaviour, since this is
  358. // how default grant/deny by default is determined.
  359. //
  360. TRACEEOLID("Ignoring sentinel");
  361. }
  362. else
  363. {
  364. oblAccessList.AddTail(
  365. new CIPAccessDescriptor(
  366. fGrant,
  367. dwIP,
  368. dwMask,
  369. FALSE
  370. )
  371. );
  372. }
  373. }
  374. }
  375. }
  376. return ERROR_SUCCESS;
  377. }
  378. DWORD
  379. BuildIplOblistFromBlob(
  380. IN CBlob & blob,
  381. OUT CObListPlus & oblAccessList,
  382. OUT BOOL & fGrantByDefault
  383. )
  384. /*++
  385. Routine Description:
  386. Convert a blob to an oblist of access descriptors.
  387. Arguments:
  388. CBlob & blob : Input binary large object(blob)
  389. CObListPlus & oblAccessList : Output oblist of access descriptors
  390. BOOL & fGrantByDefault : Returns TRUE if access is granted
  391. by default, FALSE otherwise
  392. Return Value:
  393. Error Return Code
  394. --*/
  395. {
  396. oblAccessList.RemoveAll();
  397. if (blob.IsEmpty())
  398. {
  399. return ERROR_SUCCESS;
  400. }
  401. ADDRESS_CHECK ac;
  402. ac.BindCheckList(blob.GetData(), blob.GetSize());
  403. DWORD cGrantAddr, cGrantName, cDenyAddr, cDenyName;
  404. // Name/IP Granted/Deny
  405. // ============================================================
  406. AddAccessEntries(ac, TRUE, TRUE, oblAccessList, cGrantName);
  407. AddAccessEntries(ac, FALSE, TRUE, oblAccessList, cGrantAddr);
  408. AddAccessEntries(ac, TRUE, FALSE, oblAccessList, cDenyName);
  409. AddAccessEntries(ac, FALSE, FALSE, oblAccessList, cDenyAddr);
  410. ac.UnbindCheckList();
  411. fGrantByDefault = (cDenyAddr + cDenyName != 0L)
  412. || (cGrantAddr + cGrantName == 0L);
  413. return ERROR_SUCCESS;
  414. }
  415. LPSTR
  416. PrepareDomainName(
  417. IN LPSTR lpName,
  418. OUT DWORD * pdwFlags
  419. )
  420. /*++
  421. Routine Description:
  422. Check to see if the domain name contains a wild card,
  423. if so remove it. Set the flags based on the domain name
  424. Arguments:
  425. LPSTR lpName : Input domain name
  426. DWORD * pdwFlags : Return the flags for AddName
  427. Return:
  428. Pointer to the cleaned up domain name
  429. --*/
  430. {
  431. *pdwFlags = 0L;
  432. if (!strncmp(lpName, "*.", 2))
  433. {
  434. return lpName + 2;
  435. }
  436. *pdwFlags |= DNSLIST_FLAG_NOSUBDOMAIN;
  437. return lpName;
  438. }
  439. void
  440. BuildIplBlob(
  441. IN CObListPlus & oblAccessList,
  442. IN BOOL fGrantByDefault,
  443. OUT CBlob & blob
  444. )
  445. /*++
  446. Routine Description:
  447. Build a blob from an oblist of access descriptors
  448. Arguments:
  449. CObListPlus & oblAccessList : Input oblist of access descriptors
  450. BOOL fGrantByDefault : TRUE if access is granted by default
  451. CBlob & blob : Output blob
  452. Return Value:
  453. None
  454. Notes:
  455. If fGrantByDefault is FALSE, e.g. access is to be denied by
  456. default, but nobody is specifically granted access, then add
  457. a dummy entry 0.0.0.0 to the grant list.
  458. If grant by default is on, then granted entries will not be
  459. added to the blob. Similart for denied entries if deny by
  460. default is on.
  461. --*/
  462. {
  463. ADDRESS_CHECK ac;
  464. ac.BindCheckList();
  465. int cItems = 0;
  466. CObListIter obli(oblAccessList);
  467. const CIPAccessDescriptor * pAccess;
  468. //
  469. // Should be empty to start with.
  470. //
  471. ASSERT(blob.IsEmpty());
  472. blob.CleanUp();
  473. BYTE bMask[4];
  474. BYTE bIp[4];
  475. while (pAccess = (CIPAccessDescriptor *)obli.Next())
  476. {
  477. ASSERT_READ_PTR(pAccess);
  478. if (pAccess->HasAccess() == fGrantByDefault)
  479. {
  480. //
  481. // Skip this entry -- it's irrelevant
  482. //
  483. continue;
  484. }
  485. if (pAccess->IsDomainName())
  486. {
  487. LPSTR lpName = AllocAnsiString(pAccess->QueryDomainName());
  488. if (lpName)
  489. {
  490. DWORD dwFlags;
  491. LPSTR lpDomain = PrepareDomainName(lpName, &dwFlags);
  492. ac.AddName(
  493. pAccess->HasAccess(),
  494. lpDomain,
  495. dwFlags
  496. );
  497. FreeMem(lpName);
  498. }
  499. }
  500. else
  501. {
  502. //
  503. // Build with network byte order
  504. //
  505. ac.AddAddr(
  506. pAccess->HasAccess(),
  507. AF_INET,
  508. CIPAddress::DWORDtoLPBYTE(pAccess->QuerySubnetMask(FALSE), bMask),
  509. CIPAddress::DWORDtoLPBYTE(pAccess->QueryIPAddress(FALSE), bIp)
  510. );
  511. }
  512. ++cItems;
  513. }
  514. if (cItems == 0 && !fGrantByDefault)
  515. {
  516. //
  517. // List is empty. If deny by default is on, create
  518. // a dummy sentinel entry to grant access to single
  519. // address 0.0.0.0, otherwise we're ok.
  520. //
  521. ac.AddAddr(
  522. TRUE,
  523. AF_INET,
  524. CIPAddress::DWORDtoLPBYTE(NULL_IP_MASK, bMask),
  525. CIPAddress::DWORDtoLPBYTE(NULL_IP_ADDRESS, bIp)
  526. );
  527. ++cItems;
  528. }
  529. if (cItems > 0)
  530. {
  531. blob.SetValue(ac.QueryCheckListSize(), ac.QueryCheckListPtr(), TRUE);
  532. }
  533. ac.UnbindCheckList();
  534. }