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.

944 lines
18 KiB

  1. /*++
  2. Copyright (c) 1994-1998 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
  11. Revision History:
  12. --*/
  13. //
  14. // Include Files
  15. //
  16. #include "stdafx.h"
  17. #include "comprop.h"
  18. #include "accessdl.h"
  19. #undef dllexp
  20. #include "tcpdllp.hxx"
  21. #define _RDNS_STANDALONE
  22. #include <rdns.hxx>
  23. #ifdef _DEBUG
  24. #undef THIS_FILE
  25. static char BASED_CODE THIS_FILE[] = __FILE__;
  26. #endif
  27. //#ifdef _DEBUG
  28. //
  29. // Careful here... This may cause build failure
  30. //
  31. extern "C" DEBUG_PRINTS * g_pDebug = NULL;
  32. //#endif // _DEBUG
  33. //
  34. // Registry key name for this dialog
  35. //
  36. const TCHAR g_szRegKey[] = _T("Advanced");
  37. //
  38. // Site Security Listbox Column Definitions
  39. //
  40. // Note: IDS_IP_ADDRESS_SUBNET_MASK is overridden
  41. // in w3scfg
  42. //
  43. static const ODL_COLUMN_DEF g_aColumns[] =
  44. {
  45. // ===============================================
  46. // Weight Label
  47. // ===============================================
  48. { 4, IDS_ACCESS, },
  49. { 15, IDS_IP_ADDRESS_SUBNET_MASK, },
  50. };
  51. #define NUM_COLUMNS (sizeof(g_aColumns) / sizeof(g_aColumns[0]))
  52. CIPAccessDescriptor::CIPAccessDescriptor(
  53. IN BOOL fGranted
  54. )
  55. /*++
  56. Routine Description:
  57. Dummy Constructor for access description object. Assumes a single IP
  58. address of 0.0.0.0
  59. Arguments:
  60. BOOL fGranted : TRUE for 'grant' access, FALSE for 'deny' access
  61. Return Value:
  62. N/A
  63. --*/
  64. : m_fGranted(fGranted),
  65. m_adtType(CIPAccessDescriptor::ADT_SINGLE),
  66. m_iaIPAddress(NULL_IP_ADDRESS),
  67. m_iaSubnetMask(NULL_IP_MASK),
  68. m_strDomain()
  69. {
  70. }
  71. CIPAccessDescriptor::CIPAccessDescriptor(
  72. IN const CIPAccessDescriptor & ac
  73. )
  74. /*++
  75. Routine Description:
  76. Copy constructor for access description object
  77. Arguments:
  78. const CIPAccessDescriptor & ac : Source access description object
  79. Return Value:
  80. N/A
  81. --*/
  82. : m_fGranted(ac.m_fGranted),
  83. m_adtType(ac.m_adtType),
  84. m_iaIPAddress(ac.m_iaIPAddress),
  85. m_iaSubnetMask(ac.m_iaSubnetMask),
  86. m_strDomain(ac.m_strDomain)
  87. {
  88. }
  89. CIPAccessDescriptor::CIPAccessDescriptor(
  90. IN BOOL fGranted,
  91. IN DWORD dwIPAddress,
  92. IN DWORD dwSubnetMask, OPTIONAL
  93. IN BOOL fNetworkByteOrder OPTIONAL
  94. )
  95. /*++
  96. Routine Description:
  97. Constructor for ip range (ip address/subnet mask pair)
  98. access description object.
  99. Arguments:
  100. BOOL fGranted : TRUE for 'grant' access, FALSE for 'deny' access
  101. DWORD dwIPAddress : IP Address
  102. DWORD dwSubnetMask : The subnet mask or 0xffffffff
  103. BOOL fNetworkByteOrder : If TRUE, the ip address and subnet mask are in
  104. network byte order
  105. Return Value:
  106. N/A
  107. --*/
  108. {
  109. SetValues(fGranted, dwIPAddress, dwSubnetMask, fNetworkByteOrder);
  110. }
  111. CIPAccessDescriptor::CIPAccessDescriptor(
  112. IN BOOL fGranted,
  113. IN LPCTSTR lpstrDomain
  114. )
  115. /*++
  116. Routine Description:
  117. Constructor for domain name access description object.
  118. Arguments:
  119. BOOL fGranted : TRUE for 'grant' access, FALSE for 'deny' access
  120. LPCTSTR lpstrDomain : The domain name
  121. Return Value:
  122. N/A
  123. --*/
  124. {
  125. SetValues(fGranted, lpstrDomain);
  126. }
  127. void
  128. CIPAccessDescriptor::SetValues(
  129. IN BOOL fGranted,
  130. IN DWORD dwIPAddress,
  131. IN DWORD dwSubnetMask,
  132. IN BOOL fNetworkByteOrder OPTIONAL
  133. )
  134. /*++
  135. Routine Description:
  136. Set values for 'ip range (ip address and subnet mask)' access descriptor,
  137. or a single ip address if the mask is 0xffffffff
  138. Arguments:
  139. BOOL fGranted : TRUE for 'grant' access, FALSE for 'deny' access
  140. DWORD dwIPAddress : IP Address
  141. DWORD dwSubnetMask : The subnet mask or ffffffff
  142. BOOL fNetworkByteOrder : If TRUE, the ip address and subnet mask are in
  143. network byte order
  144. Return Value:
  145. None
  146. Notes:
  147. If the subnetmask is 0xffffffff this describes a single ip address.
  148. --*/
  149. {
  150. m_fGranted = fGranted;
  151. m_adtType = (dwSubnetMask == NULL_IP_MASK) ? ADT_SINGLE : ADT_MULTIPLE;
  152. m_iaIPAddress = CIPAddress(dwIPAddress, fNetworkByteOrder);
  153. m_iaSubnetMask = CIPAddress(dwSubnetMask, fNetworkByteOrder);
  154. //
  155. // Not used:
  156. //
  157. m_strDomain.Empty();
  158. }
  159. void
  160. CIPAccessDescriptor::SetValues(
  161. IN BOOL fGranted,
  162. IN LPCTSTR lpstrDomain
  163. )
  164. /*++
  165. Routine Description:
  166. Set values for 'domain name' access descriptor
  167. Arguments:
  168. BOOL fGranted : TRUE for 'grant' access, FALSE for 'deny' access
  169. LPCTSTR lpstrDomain : The domain name
  170. Return Value:
  171. None
  172. --*/
  173. {
  174. m_fGranted = fGranted;
  175. m_adtType = ADT_DOMAIN;
  176. try
  177. {
  178. m_strDomain = lpstrDomain;
  179. }
  180. catch(CMemoryException * e)
  181. {
  182. TRACEEOLID("!!!exception assigning domain name");
  183. e->ReportError();
  184. e->Delete();
  185. }
  186. //
  187. // Not used:
  188. //
  189. m_iaIPAddress.SetZeroValue();
  190. m_iaSubnetMask.SetZeroValue();
  191. }
  192. BOOL
  193. CIPAccessDescriptor::DuplicateInList(
  194. IN CObListPlus & oblList
  195. )
  196. /*++
  197. Routine Description:
  198. Check to see if a duplicate exists in the provided oblist
  199. Arguments:
  200. CObListPlus & oblList
  201. Return Value:
  202. TRUE if a duplicate exists, FALSE otherwise.
  203. Notes:
  204. As there's no information how this list might be sorted at this point,
  205. and the list is likely to be small, the search is sequential.
  206. --*/
  207. {
  208. CObListIter obli(oblList);
  209. CIPAccessDescriptor * pAccess;
  210. TRACEEOLID("Looking for duplicate access descriptors");
  211. while (pAccess = (CIPAccessDescriptor *)obli.Next())
  212. {
  213. ASSERT(pAccess != NULL);
  214. //
  215. // Eliminate the item itself from the list, and look
  216. // only for duplicates.
  217. //
  218. if (pAccess != this && *this == *pAccess)
  219. {
  220. TRACEEOLID("Duplicate access descriptor found");
  221. return TRUE;
  222. }
  223. }
  224. TRACEEOLID("No duplicate access descriptor found");
  225. return FALSE;
  226. }
  227. BOOL
  228. CIPAccessDescriptor::operator ==(
  229. IN const CIPAccessDescriptor & ac
  230. ) const
  231. /*++
  232. Routine Description:
  233. Compare against another access descriptor.
  234. Arguments:
  235. const CIPAccessDescriptor & ac : Object to be compared against
  236. Return Value:
  237. TRUE if the two are identical
  238. --*/
  239. {
  240. if ( m_fGranted != ac.m_fGranted
  241. || m_adtType != ac.m_adtType)
  242. {
  243. return FALSE;
  244. }
  245. if (IsDomainName())
  246. {
  247. return m_strDomain.CompareNoCase(ac.m_strDomain) == 0;
  248. }
  249. return m_iaIPAddress == ac.m_iaIPAddress
  250. && m_iaSubnetMask == ac.m_iaSubnetMask;
  251. }
  252. int
  253. CIPAccessDescriptor::OrderByAddress(
  254. IN const CObjectPlus * pobAccess
  255. ) const
  256. /*++
  257. Routine Description:
  258. Compare two access descriptors against each other.
  259. Sorting criteria are in the following order:
  260. 1) 'Granted' sorts before 'Denied'
  261. 2) Domain names are sorted before ip addresses, and are
  262. sorted alphabetically.
  263. 3) IP Address and IP Address/subnet mask pairs are sorted
  264. by ip address.
  265. Arguments:
  266. const CObjectPlus * pobAccess : This really refers to another
  267. CIPAccessDescriptor to be compared to.
  268. Return Value:
  269. Sort (+1, 0, -1) return value
  270. --*/
  271. {
  272. const CIPAccessDescriptor * pob = (CIPAccessDescriptor *)pobAccess;
  273. //
  274. // First sort by access/denied
  275. //
  276. int n1 = HasAccess() ? 1 : 0;
  277. int n2 = pob->HasAccess() ? 1 : 0;
  278. if (n2 != n1)
  279. {
  280. //
  281. // Grant sorts before denied
  282. //
  283. return n2 - n1;
  284. }
  285. //
  286. // Secondly, try to sort by domain name (domain name sorts before
  287. // ip address and ip address/subnet mask objects)
  288. //
  289. n1 = IsDomainName() ? 1 : 0;
  290. n2 = pob->IsDomainName() ? 1 : 0;
  291. if (n1 != n2)
  292. {
  293. //
  294. // Domain names sort before ip addresses
  295. //
  296. return n2 - n1;
  297. }
  298. if (n1 && n2)
  299. {
  300. //
  301. // Both are domain names. Sort alphabetically
  302. //
  303. return ::lstrcmpi(QueryDomainName(), pob->QueryDomainName());
  304. }
  305. //
  306. // IP address is the third key.
  307. //
  308. return QueryIPAddress().CompareItem(pob->QueryIPAddress());
  309. }
  310. DWORD
  311. AddAccessEntries(
  312. IN ADDRESS_CHECK & ac,
  313. IN BOOL fName,
  314. IN BOOL fGrant,
  315. OUT CObListPlus & oblAccessList,
  316. OUT DWORD & cEntries
  317. )
  318. /*++
  319. Routine Description:
  320. Add specific kind of addresses from the list to the oblist of
  321. access entries
  322. Arguments:
  323. ADDRESS_CHECK & ac : Address list input object
  324. BOOL fName : TRUE for names, FALSE for ip
  325. BOOL fGrant : TRUE for granted, FALSE for denied
  326. CObListPlus & oblAccessList : ObList to add access entries to
  327. int & cEntries : Returns the number of entries
  328. Return Value:
  329. Error code
  330. Notes:
  331. Sentinel entries (ip 0.0.0.0) are not added to the oblist, but
  332. are reflected in the cEntries return value
  333. --*/
  334. {
  335. DWORD i;
  336. DWORD dwFlags;
  337. if (fName)
  338. {
  339. //
  340. // Domain names
  341. //
  342. LPSTR lpName;
  343. cEntries = ac.GetNbName(fGrant);
  344. for (i = 0L; i < cEntries; ++i)
  345. {
  346. if (ac.GetName(fGrant, i, &lpName, &dwFlags))
  347. {
  348. CString strDomain(lpName);
  349. if (!(dwFlags & DNSLIST_FLAG_NOSUBDOMAIN))
  350. {
  351. strDomain = _T("*.") + strDomain;
  352. }
  353. oblAccessList.AddTail(new CIPAccessDescriptor(fGrant, strDomain));
  354. }
  355. }
  356. }
  357. else
  358. {
  359. //
  360. // IP Addresses
  361. //
  362. LPBYTE lpMask;
  363. LPBYTE lpAddr;
  364. cEntries = ac.GetNbAddr(fGrant);
  365. for (i = 0L; i < cEntries; ++i)
  366. {
  367. if (ac.GetAddr(fGrant, i, &dwFlags, &lpMask, &lpAddr))
  368. {
  369. DWORD dwIP = MAKEIPADDRESS(lpAddr[0], lpAddr[1], lpAddr[2], lpAddr[3]);
  370. DWORD dwMask = MAKEIPADDRESS(lpMask[0], lpMask[1], lpMask[2], lpMask[3]);
  371. if (dwIP == NULL_IP_ADDRESS && dwMask == NULL_IP_MASK)
  372. {
  373. //
  374. // Sentinel in the grant list is not added, but
  375. // also not subtracted from the count of entries,
  376. // which is correct behaviour, since this is
  377. // how default grant/deny by default is determined.
  378. //
  379. TRACEEOLID("Ignoring sentinel");
  380. }
  381. else
  382. {
  383. oblAccessList.AddTail(
  384. new CIPAccessDescriptor(
  385. fGrant,
  386. dwIP,
  387. dwMask,
  388. FALSE
  389. )
  390. );
  391. }
  392. }
  393. }
  394. }
  395. return ERROR_SUCCESS;
  396. }
  397. DWORD
  398. BuildIplOblistFromBlob(
  399. IN CBlob & blob,
  400. OUT CObListPlus & oblAccessList,
  401. OUT BOOL & fGrantByDefault
  402. )
  403. /*++
  404. Routine Description:
  405. Convert a blob to an oblist of access descriptors.
  406. Arguments:
  407. CBlob & blob : Input binary large object(blob)
  408. CObListPlus & oblAccessList : Output oblist of access descriptors
  409. BOOL & fGrantByDefault : Returns TRUE if access is granted
  410. by default, FALSE otherwise
  411. Return Value:
  412. Error Return Code
  413. --*/
  414. {
  415. oblAccessList.RemoveAll();
  416. if (blob.IsEmpty())
  417. {
  418. return ERROR_SUCCESS;
  419. }
  420. ADDRESS_CHECK ac;
  421. ac.BindCheckList(blob.GetData(), blob.GetSize());
  422. DWORD cGrantAddr, cGrantName, cDenyAddr, cDenyName;
  423. // Name/IP Granted/Deny
  424. // ============================================================
  425. AddAccessEntries(ac, TRUE, TRUE, oblAccessList, cGrantName);
  426. AddAccessEntries(ac, FALSE, TRUE, oblAccessList, cGrantAddr);
  427. AddAccessEntries(ac, TRUE, FALSE, oblAccessList, cDenyName);
  428. AddAccessEntries(ac, FALSE, FALSE, oblAccessList, cDenyAddr);
  429. ac.UnbindCheckList();
  430. fGrantByDefault = (cDenyAddr + cDenyName != 0L)
  431. || (cGrantAddr + cGrantName == 0L);
  432. return ERROR_SUCCESS;
  433. }
  434. LPSTR
  435. PrepareDomainName(
  436. IN LPSTR lpName,
  437. OUT DWORD * pdwFlags
  438. )
  439. /*++
  440. Routine Description:
  441. Check to see if the domain name contains a wild card,
  442. if so remove it. Set the flags based on the domain name
  443. Arguments:
  444. LPSTR lpName : Input domain name
  445. DWORD * pdwFlags : Return the flags for AddName
  446. Return:
  447. Pointer to the cleaned up domain name
  448. --*/
  449. {
  450. *pdwFlags = 0L;
  451. if (!strncmp(lpName, "*.", 2))
  452. {
  453. return lpName + 2;
  454. }
  455. *pdwFlags |= DNSLIST_FLAG_NOSUBDOMAIN;
  456. return lpName;
  457. }
  458. void
  459. BuildIplBlob(
  460. IN CObListPlus & oblAccessList,
  461. IN BOOL fGrantByDefault,
  462. OUT CBlob & blob
  463. )
  464. /*++
  465. Routine Description:
  466. Build a blob from an oblist of access descriptors
  467. Arguments:
  468. CObListPlus & oblAccessList : Input oblist of access descriptors
  469. BOOL fGrantByDefault : TRUE if access is granted by default
  470. CBlob & blob : Output blob
  471. Return Value:
  472. None
  473. Notes:
  474. If fGrantByDefault is FALSE, e.g. access is to be denied by
  475. default, but nobody is specifically granted access, then add
  476. a dummy entry 0.0.0.0 to the grant list.
  477. If grant by default is on, then granted entries will not be
  478. added to the blob. Similart for denied entries if deny by
  479. default is on.
  480. --*/
  481. {
  482. ADDRESS_CHECK ac;
  483. ac.BindCheckList();
  484. int cItems = 0;
  485. CObListIter obli(oblAccessList);
  486. const CIPAccessDescriptor * pAccess;
  487. //
  488. // Should be empty to start with.
  489. //
  490. ASSERT(blob.IsEmpty());
  491. blob.CleanUp();
  492. BYTE bMask[4];
  493. BYTE bIp[4];
  494. while (pAccess = (CIPAccessDescriptor *)obli.Next())
  495. {
  496. ASSERT(pAccess != NULL);
  497. if (pAccess->HasAccess() == fGrantByDefault)
  498. {
  499. //
  500. // Skip this entry -- it's irrelevant
  501. //
  502. continue;
  503. }
  504. if (pAccess->IsDomainName())
  505. {
  506. LPSTR lpName = AllocAnsiString(pAccess->QueryDomainName());
  507. if (lpName)
  508. {
  509. DWORD dwFlags;
  510. LPSTR lpDomain = PrepareDomainName(lpName, &dwFlags);
  511. ac.AddName(
  512. pAccess->HasAccess(),
  513. lpDomain,
  514. dwFlags
  515. );
  516. FreeMem(lpName);
  517. }
  518. }
  519. else
  520. {
  521. //
  522. // Build with network byte order
  523. //
  524. ac.AddAddr(
  525. pAccess->HasAccess(),
  526. AF_INET,
  527. CIPAddress::DWORDtoLPBYTE(pAccess->QuerySubnetMask(FALSE), bMask),
  528. CIPAddress::DWORDtoLPBYTE(pAccess->QueryIPAddress(FALSE), bIp)
  529. );
  530. }
  531. ++cItems;
  532. }
  533. if (cItems == 0 && !fGrantByDefault)
  534. {
  535. //
  536. // List is empty. If deny by default is on, create
  537. // a dummy sentinel entry to grant access to single
  538. // address 0.0.0.0, otherwise we're ok.
  539. //
  540. ac.AddAddr(
  541. TRUE,
  542. AF_INET,
  543. CIPAddress::DWORDtoLPBYTE(NULL_IP_MASK, bMask),
  544. CIPAddress::DWORDtoLPBYTE(NULL_IP_ADDRESS, bIp)
  545. );
  546. ++cItems;
  547. }
  548. if (cItems > 0)
  549. {
  550. blob.SetValue(ac.QueryCheckListSize(), ac.QueryCheckListPtr(), TRUE);
  551. }
  552. ac.UnbindCheckList();
  553. }
  554. IMPLEMENT_DYNAMIC(CIPAccessDescriptorListBox, CHeaderListBox);
  555. //
  556. // Bitmap indices
  557. //
  558. enum
  559. {
  560. BMPID_GRANTED = 0,
  561. BMPID_DENIED,
  562. BMPID_SINGLE,
  563. BMPID_MULTIPLE,
  564. //
  565. // Don't move this one
  566. //
  567. BMPID_TOTAL
  568. };
  569. const int CIPAccessDescriptorListBox::nBitmaps = BMPID_TOTAL;
  570. CIPAccessDescriptorListBox::CIPAccessDescriptorListBox(
  571. IN BOOL fDomainsAllowed
  572. )
  573. /*++
  574. Routine Description:
  575. Constructor
  576. Arguments:
  577. fDomainsAllowed : TRUE if domain names are legal.
  578. Return Value:
  579. N/A
  580. --*/
  581. : m_fDomainsAllowed(fDomainsAllowed),
  582. CHeaderListBox(HLS_STRETCH, g_szRegKey)
  583. {
  584. m_strGranted.LoadString(IDS_GRANTED);
  585. m_strDenied.LoadString(IDS_DENIED);
  586. m_strFormat.LoadString(IDS_FMT_SECURITY);
  587. }
  588. void
  589. CIPAccessDescriptorListBox::DrawItemEx(
  590. IN CRMCListBoxDrawStruct & ds
  591. )
  592. /*++
  593. Routine Description:
  594. Draw item in the listbox
  595. Arguments:
  596. CRMCListBoxDrawStruct & ds : Draw item structure
  597. Return Value:
  598. None
  599. --*/
  600. {
  601. CIPAccessDescriptor * p = (CIPAccessDescriptor *)ds.m_ItemData;
  602. ASSERT(p != NULL);
  603. //
  604. // Display Granted/Denied with appropriate bitmap
  605. //
  606. DrawBitmap(ds, 0, p->HasAccess() ? BMPID_GRANTED : BMPID_DENIED);
  607. ColumnText(ds, 0, TRUE, p->HasAccess() ? m_strGranted : m_strDenied);
  608. //
  609. // Display IP Address with multiple/single bitmap
  610. //
  611. DrawBitmap(ds, 1, p->IsSingle() ? BMPID_SINGLE : BMPID_MULTIPLE);
  612. if (p->IsDomainName())
  613. {
  614. ColumnText(ds, 1, TRUE, p->QueryDomainName());
  615. }
  616. else if (p->IsSingle())
  617. {
  618. //
  619. // Display only ip address
  620. //
  621. ColumnText(ds, 1, TRUE, p->QueryIPAddress());
  622. }
  623. else
  624. {
  625. //
  626. // Display ip address/subnet mask
  627. //
  628. CString str, strIP, strMask;
  629. str.Format(
  630. m_strFormat,
  631. (LPCTSTR)p->QueryIPAddress().QueryIPAddress(strIP),
  632. (LPCTSTR)p->QuerySubnetMask().QueryIPAddress(strMask)
  633. );
  634. ColumnText(ds, 1, TRUE, str);
  635. }
  636. }
  637. /* virtual */
  638. BOOL
  639. CIPAccessDescriptorListBox::Initialize()
  640. /*++
  641. Routine Description:
  642. Initialize the listbox. Insert the columns as requested, and lay
  643. them out appropriately
  644. Arguments:
  645. None
  646. Return Value:
  647. TRUE for succesful initialisation, FALSE otherwise
  648. --*/
  649. {
  650. if (!CHeaderListBox::Initialize())
  651. {
  652. return FALSE;
  653. }
  654. //
  655. // Build all columns
  656. //
  657. for (int nCol = 0; nCol < NUM_COLUMNS; ++nCol)
  658. {
  659. InsertColumn(nCol, g_aColumns[nCol].nWeight, g_aColumns[nCol].nLabelID);
  660. }
  661. //
  662. // Try to set the widths from the stored registry value,
  663. // otherwise distribute according to column weights specified
  664. //
  665. if (!SetWidthsFromReg())
  666. {
  667. DistributeColumns();
  668. }
  669. return TRUE;
  670. }