Leaked source code of windows server 2003
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.

661 lines
17 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. iiscmr.hxx
  5. Abstract:
  6. Classes to handle IIS client cert wildcard mapping
  7. Author:
  8. Philippe Choquier (phillich) 17-oct-1996
  9. --*/
  10. #if !defined( _IISCMR_HXX )
  11. #define _IISCMR_HXX
  12. #ifndef IISMAP_DLLEXP
  13. # ifdef DLL_IMPLEMENTATION
  14. # define IISMAP_DLLEXP __declspec(IISMAP_DLLEXPort)
  15. # ifdef IMPLEMENTATION_EXPORT
  16. # define IRTL_EXPIMP
  17. # else
  18. # undef IRTL_EXPIMP
  19. # endif
  20. # else // !DLL_IMPLEMENTATION
  21. # define IISMAP_DLLEXP __declspec(dllimport)
  22. # define IRTL_EXPIMP extern
  23. # endif // !DLL_IMPLEMENTATION
  24. #endif // !IISMAP_DLLEXP
  25. VOID InitializeWildcardMapping( HANDLE hModule );
  26. VOID TerminateWildcardMapping();
  27. typedef BOOL
  28. (WINAPI * SSL_GET_ISSUERS_FN)
  29. (
  30. PBYTE,
  31. LPDWORD
  32. ) ;
  33. //
  34. // X.509 cert fields we recognize
  35. //
  36. enum CERT_FIELD_ID
  37. {
  38. CERT_FIELD_ISSUER,
  39. CERT_FIELD_SUBJECT,
  40. CERT_FIELD_SERIAL_NUMBER,
  41. CERT_FIELD_LAST,
  42. CERT_FIELD_ERROR = 0xffff
  43. } ;
  44. #define CERT_FIELD_FLAG_CONTAINS_SUBFIELDS 0x00000001
  45. //
  46. // Mapper between ASN.1 names ( ASCII format ) & well-known abbreviations
  47. //
  48. typedef struct _MAP_ASN {
  49. LPSTR pAsnName;
  50. LPSTR pTextName;
  51. DWORD dwResId;
  52. } MAP_ASN;
  53. #define INDEX_ERROR 0xffffffff
  54. //
  55. // Mapper between field IDs and well-known field names
  56. //
  57. typedef struct _MAP_FIELD {
  58. CERT_FIELD_ID dwId;
  59. DWORD dwResId;
  60. LPSTR pTextName;
  61. } MAP_FIELD;
  62. #define DBLEN_SIZE 2
  63. #define GETDBLEN(a) (WORD)( ((LPBYTE)a)[1] + (((LPBYTE)a)[0]<<8) )
  64. //
  65. // sub-field match types
  66. //
  67. enum MATCH_TYPES
  68. {
  69. MATCH_ALL = 1, // whole content must match
  70. MATCH_FIRST, // beginning of cert subfield must match
  71. MATCH_LAST, // end of cert subfield must match
  72. MATCH_IN // must be matched inside cer subfield
  73. } ;
  74. //
  75. // X.509 DER encoded certificate partially decoded
  76. //
  77. class CDecodedCert {
  78. public:
  79. IISMAP_DLLEXP CDecodedCert( PCERT_CONTEXT );
  80. IISMAP_DLLEXP ~CDecodedCert();
  81. IISMAP_DLLEXP BOOL GetIssuer( LPVOID* ppCert, LPDWORD pcCert );
  82. IISMAP_DLLEXP PCERT_RDN_ATTR* GetSubField( CERT_FIELD_ID fi, LPSTR pszAsnName, LPDWORD pdwLen );
  83. private:
  84. PCCERT_CONTEXT pCertCtx;
  85. CERT_RDN_ATTR SerialNumber;
  86. PCERT_NAME_INFO aniFields[CERT_FIELD_LAST];
  87. } ;
  88. //
  89. // Access to array of issuers recognized by the server SSL implementation
  90. // provide conversion between issuer ID & DER encoded issuer
  91. //
  92. // Issuers were supported only by IIS4.
  93. // For IIS5 and IIS6 CIssuerStore is not really used
  94. // The only reason to keep it around is that serialized Issuers list
  95. // was saved by IIS4 and to maintain compatibility of format
  96. // we still have to read it and write it.
  97. //
  98. class CIssuerStore {
  99. public:
  100. IISMAP_DLLEXP CIssuerStore();
  101. IISMAP_DLLEXP ~CIssuerStore();
  102. IISMAP_DLLEXP VOID Reset();
  103. //
  104. // Unserialize from buffer
  105. //
  106. IISMAP_DLLEXP BOOL Unserialize( LPBYTE* ppb, LPDWORD pc );
  107. IISMAP_DLLEXP BOOL Unserialize( CStoreXBF* pX );
  108. //
  109. // Serialize to buffer
  110. //
  111. IISMAP_DLLEXP BOOL Serialize( CStoreXBF* pX );
  112. //
  113. // Get count of issuers
  114. //
  115. IISMAP_DLLEXP DWORD GetNbIssuers()
  116. { return m_IssuerCerts.GetNbEntry(); }
  117. private:
  118. CStrPtrXBF m_pIssuerNames;
  119. CBlobXBF m_IssuerCerts;
  120. BOOL m_fValid;
  121. } ;
  122. //
  123. // Control information global to all rules :
  124. // - rule ordering while checking for a match
  125. // - rules enabled or nor
  126. //
  127. class CCertGlobalRuleInfo {
  128. public:
  129. // global rule API, used by admin tool
  130. IISMAP_DLLEXP CCertGlobalRuleInfo();
  131. IISMAP_DLLEXP ~CCertGlobalRuleInfo();
  132. IISMAP_DLLEXP BOOL IsValid() { return m_fValid; }
  133. IISMAP_DLLEXP BOOL Reset();
  134. //
  135. // Retrieve ptr to user-editable array of index ( as DWORD ) of rule
  136. // ordering to consider when checking for rule match
  137. // e.g. order is 3, 2, 0, 1 the 4th rule will be considered 1st, then
  138. // the 3rd, ...
  139. //
  140. IISMAP_DLLEXP LPDWORD GetRuleOrderArray() { return (LPDWORD) m_Order.GetBuff(); }
  141. //
  142. // Get count of rule index in array. Is the same as # of rules in
  143. // CIisRuleMapper object
  144. //
  145. // Win64 fixed
  146. IISMAP_DLLEXP DWORD GetRuleOrderCount() { return m_Order.GetUsed() / sizeof(DWORD); }
  147. IISMAP_DLLEXP BOOL AddRuleOrder();
  148. IISMAP_DLLEXP BOOL DeleteRuleById( DWORD dwId, BOOL DecrementAbove );
  149. //
  150. // Set rules enabled flag
  151. // if FALSE, no wildcard matching will take place
  152. //
  153. IISMAP_DLLEXP VOID SetRulesEnabled( BOOL f ) { m_fEnabled = f; }
  154. //
  155. // Get rules enabled flag
  156. //
  157. IISMAP_DLLEXP BOOL GetRulesEnabled() { return m_fEnabled; }
  158. //
  159. // Serialize to buffer
  160. //
  161. IISMAP_DLLEXP BOOL SerializeGlobalRuleInfo( CStoreXBF* pX);
  162. //
  163. // Unserialize from buffer
  164. //
  165. IISMAP_DLLEXP BOOL UnserializeGlobalRuleInfo( LPBYTE* ppB, LPDWORD pC );
  166. private:
  167. // old broken code on Win64
  168. // CPtrXBF m_Order;
  169. // Win64 fixed -- added CPtrDwordXBF class to handle Dwords
  170. CPtrDwordXBF m_Order;
  171. BOOL m_fEnabled;
  172. BOOL m_fValid;
  173. } ;
  174. #define CMR_FLAGS_CASE_INSENSITIVE 0x00000001
  175. //
  176. // Individual rule
  177. //
  178. // Rules have a name, target NT account, enabled/disabled status,
  179. // deny access status
  180. //
  181. // Consists of an array of rule elements, each one being a test
  182. // against a cert field/subfield, such as Issuer.O, Subject.CN
  183. // The field designation is stored as a field ID ( CERT_FIELD_ID )
  184. // The sub-field designation is stored as an ASN.1 name ( ascii format )
  185. // The match checking is stored as a byte array which can either
  186. // - be present at the beginning of the cert subfield
  187. // - be present at the end of the cert subfield
  188. // - be present inside the cert subfield
  189. // - be identical to the cert subfield
  190. //
  191. // An array of issuer (stored as Issuer ID, cf. CIssuerStore for
  192. // conversion to/from DER encoded issuer ) can be associated to a rule.
  193. // Each issuer in this array can be flagged as recognized or not.
  194. // If specified, one of the recognized issuers must match the cert issuer
  195. // for a match to occurs.
  196. //
  197. class CCertMapRule {
  198. public:
  199. // rule API. Field is numeric ID ( Issuer, Subject, ...), subfield is ASN.1 ID
  200. // used by admin tool
  201. IISMAP_DLLEXP CCertMapRule();
  202. IISMAP_DLLEXP ~CCertMapRule();
  203. IISMAP_DLLEXP BOOL IsValid() { return m_fValid; }
  204. //
  205. IISMAP_DLLEXP VOID Reset();
  206. IISMAP_DLLEXP BOOL Unserialize( LPBYTE* ppb, LPDWORD pc );
  207. IISMAP_DLLEXP BOOL Unserialize( CStoreXBF* pX );
  208. IISMAP_DLLEXP BOOL Serialize( CStoreXBF* pX );
  209. // return ERROR_INVALID_NAME if no match
  210. IISMAP_DLLEXP BOOL Match( CDecodedCert* pC, CDecodedCert* pAuth, LPSTR pszAcct, LPSTR pszPwd,
  211. LPBOOL pfDenied );
  212. //
  213. // Set the rule name ( used by UI only )
  214. //
  215. IISMAP_DLLEXP BOOL SetRuleName( LPSTR pszName ) { return m_asRuleName.Set( pszName ); }
  216. //
  217. // Get the rule name
  218. //
  219. IISMAP_DLLEXP LPSTR GetRuleName() { return m_asRuleName.Get(); }
  220. //
  221. // Set the associated NT account
  222. //
  223. // can return FALSE, error ERROR_INVALID_NAME if account syntax invalid
  224. //
  225. IISMAP_DLLEXP BOOL SetRuleAccount( LPSTR pszAcct );
  226. //
  227. // Get the associated NT account
  228. //
  229. IISMAP_DLLEXP LPSTR GetRuleAccount() { return m_asAccount.Get(); }
  230. //
  231. // Set the associated NT pwd
  232. //
  233. IISMAP_DLLEXP BOOL SetRulePassword( LPSTR pszPwd ) { return m_asPassword.Set( pszPwd ); }
  234. //
  235. // Get the associated NT pwd
  236. //
  237. IISMAP_DLLEXP LPSTR GetRulePassword() { return m_asPassword.Get(); }
  238. //
  239. // Set the rule enabled flag. If disabled, this rule will not be
  240. // consider while searching for a match
  241. //
  242. IISMAP_DLLEXP VOID SetRuleEnabled( BOOL f ) { m_fEnabled = f; }
  243. //
  244. // Get the rule enabled flag
  245. //
  246. IISMAP_DLLEXP BOOL GetRuleEnabled() { return m_fEnabled; }
  247. //
  248. // Set the rule deny access flag. If TRUE and a match occurs
  249. // with this rule then access will be denied to the browser
  250. // request
  251. //
  252. IISMAP_DLLEXP VOID SetRuleDenyAccess( BOOL f ) { m_fDenyAccess = f; }
  253. //
  254. // Get the rule deny access flag
  255. //
  256. IISMAP_DLLEXP BOOL GetRuleDenyAccess() { return m_fDenyAccess; }
  257. //
  258. // Get the count of rule elements
  259. //
  260. IISMAP_DLLEXP DWORD GetRuleElemCount() { return m_ElemsContent.GetNbEntry(); }
  261. //
  262. // Retrieve rule element info using index ( 0-based )
  263. // CERT_FIELD_ID, subfield ASN.1 name, content as binary buffer.
  264. // content can be converted to user displayable format using the
  265. // BinaryToMatchRequest() function.
  266. //
  267. IISMAP_DLLEXP BOOL GetRuleElem( DWORD i, CERT_FIELD_ID* pfiField, LPSTR* ppContent,
  268. LPDWORD pcContent, LPSTR* ppSubField, LPDWORD pdwFlags = NULL );
  269. //
  270. // Delete a rule element by its index
  271. //
  272. IISMAP_DLLEXP BOOL DeleteRuleElem( DWORD i );
  273. //
  274. // Delete all rule elements whose CERT_FIELD_ID match the one specified
  275. //
  276. IISMAP_DLLEXP BOOL DeleteRuleElemsByField( CERT_FIELD_ID fiField );
  277. //
  278. // Add a rule element info using index ( 0-based ) where to insert.
  279. // if index is 0xffffffff, rule element is added at the end of
  280. // rule element array
  281. // Must specifiy CERT_FIELD_ID, subfield ASN.1 name,
  282. // content as binary buffer.
  283. // content can be converted from user displayable format using the
  284. // MatchRequestToBinary() function.
  285. //
  286. IISMAP_DLLEXP DWORD AddRuleElem( DWORD iBefore, CERT_FIELD_ID fiField,
  287. LPSTR pszSubField, LPBYTE pContent, DWORD cContent,
  288. DWORD dwFlags = 0 );
  289. //
  290. // Issuer list : we store issuer ID ( linked to schannel reg entries ) + status
  291. // Issuer ID is HEX2ASCII(MD5(issert cert))
  292. //
  293. // Set the match all issuers flag. If set, the issuer array will be
  294. // disregarded and all issuers will match.
  295. //
  296. IISMAP_DLLEXP VOID SetMatchAllIssuer( BOOL f ) { m_fMatchAllIssuers = f; }
  297. //
  298. // Get the match all issuers flag
  299. //
  300. IISMAP_DLLEXP BOOL GetMatchAllIssuer() { return m_fMatchAllIssuers; }
  301. //
  302. // Get count of issuer in array
  303. //
  304. IISMAP_DLLEXP DWORD GetIssuerCount() { return m_Issuers.GetNbEntry(); }
  305. //
  306. // Retrieve issuer info by index ( 0-based )
  307. // ID ( cf. CIssuerStore for conversion
  308. // to/from ID <> DER encoded issuer ), accept flag
  309. // The ID is returned as a ptr to internal storage, not to be
  310. // alloced or freed.
  311. //
  312. IISMAP_DLLEXP BOOL GetIssuerEntry( DWORD i, LPBOOL pfS, LPSTR* ppszI);
  313. //
  314. // Retrieve issuer accept status by ID
  315. //
  316. IISMAP_DLLEXP BOOL GetIssuerEntryByName( LPSTR pszName, LPBOOL pfS );
  317. //
  318. // Set issue accept flag using index ( 0-based )
  319. //
  320. IISMAP_DLLEXP BOOL SetIssuerEntryAcceptStatus( DWORD, BOOL );
  321. //
  322. // Add issuer entry : ID, accept status
  323. // ID must come from CIssuerStore
  324. //
  325. IISMAP_DLLEXP BOOL AddIssuerEntry( LPSTR pszName, BOOL fAcceptStatus );
  326. //
  327. // Delete issuer entry by index ( 0-based )
  328. //
  329. IISMAP_DLLEXP BOOL DeleteIssuerEntry( DWORD i );
  330. private:
  331. static
  332. LPBYTE
  333. CertMapMemstr(
  334. LPBYTE pStr,
  335. UINT cStr,
  336. LPBYTE pSub,
  337. UINT cSub,
  338. BOOL fCaseInsensitive
  339. );
  340. private:
  341. CAllocString m_asRuleName;
  342. CAllocString m_asAccount;
  343. CAllocString m_asPassword;
  344. BOOL m_fEnabled;
  345. BOOL m_fDenyAccess;
  346. CBlobXBF m_ElemsContent; // content to match
  347. // prefix ( MATCH_TYPES ) :
  348. // MATCH_ALL : must be exact match
  349. // MATCH_FIRST : must match 1st n char
  350. // MATCH_LAST : must match last n char
  351. // MATCH_IN : must match n char in content
  352. // followed by length of match, then match
  353. CStrPtrXBF m_ElemsSubfield; // ASN.1 ID
  354. CPtrXBF m_ElemsField; // field ID ( CERT_FIELD_ID )
  355. CPtrXBF m_ElemsFlags;
  356. //
  357. // NOTE : In IIS 5, IIS6 we no longer use any of these fields but we're keeping them
  358. // so that we can still read out and use IIS 4 mappings
  359. //
  360. CStrPtrXBF m_Issuers;
  361. CPtrXBF m_IssuersAcceptStatus;
  362. BOOL m_fMatchAllIssuers;
  363. BOOL m_fValid;
  364. } ;
  365. class CReaderWriterLock3;
  366. class CIisRuleMapper {
  367. public:
  368. IISMAP_DLLEXP CIisRuleMapper();
  369. IISMAP_DLLEXP ~CIisRuleMapper();
  370. IISMAP_DLLEXP BOOL IsValid() { return m_fValid; }
  371. IISMAP_DLLEXP BOOL Reset();
  372. //
  373. // Lock rules. Must be called before modifying any information
  374. // or calling Match()
  375. //
  376. IISMAP_DLLEXP VOID WriteLockRules();
  377. IISMAP_DLLEXP VOID ReadLockRules();
  378. //
  379. // Unlock rules
  380. //
  381. IISMAP_DLLEXP VOID WriteUnlockRules();
  382. IISMAP_DLLEXP VOID ReadUnlockRules();
  383. //
  384. // Serialize all rules info to buffer
  385. //
  386. IISMAP_DLLEXP BOOL Serialize( CStoreXBF* pX );
  387. //
  388. // Un-serialize all rules from buffer ( using extensible buffer class )
  389. //
  390. IISMAP_DLLEXP BOOL Unserialize( CStoreXBF* pX );
  391. //
  392. // Un-serialize all rules from buffer
  393. //
  394. IISMAP_DLLEXP BOOL Unserialize( LPBYTE*, LPDWORD );
  395. //
  396. // Get count of rules
  397. //
  398. IISMAP_DLLEXP DWORD GetRuleCount()
  399. { return m_fValid ? m_Rules.GetNbPtr() : 0; }
  400. //
  401. // Delete a rule by index ( 0-based )
  402. //
  403. IISMAP_DLLEXP BOOL DeleteRule( DWORD dwI );
  404. //
  405. // Add an empty new rule at end of rule array.
  406. // Use GetGlobalRulesInfo()->GetRuleOrderArray() to access/update
  407. // array specifying rule ordering.
  408. // Use GetRule() then CCertMapRule API to access/update the created rule.
  409. //
  410. IISMAP_DLLEXP DWORD AddRule(); // @ end, use SetRuleOrder ( default is last pos )
  411. IISMAP_DLLEXP DWORD AddRule(CCertMapRule*); // @ end, use SetRuleOrder ( default is last pos )
  412. //
  413. // look for a matching rule and resulting NT account
  414. // given DER encoded cert.
  415. // If returns error ( FALSE ), GetLastError() can be the following :
  416. // - ERROR_ACCESS_DENIED if access denied
  417. // - ERROR_INVALID_NAME if not found
  418. // - ERROR_ARENA_TRASHED if invalid internal state
  419. // returns addr of NT account in pszAcct, buffer assumed to be big enough
  420. // before to insure ptr remains valid until Unlock()
  421. //
  422. IISMAP_DLLEXP BOOL Match( PCERT_CONTEXT pCert, PCERT_CONTEXT pAuth, LPWSTR pszAcct, LPWSTR pszPwd );
  423. //
  424. // Retrieve ptr to rule by index ( 0-based )
  425. // You can then use the CCertMapRule API to access/update rule properties
  426. //
  427. IISMAP_DLLEXP CCertMapRule* GetRule( DWORD dwI ) // for ser/unser/set/get purpose
  428. { return m_fValid && dwI < m_Rules.GetNbPtr() ? (CCertMapRule*)m_Rules.GetPtr(dwI) : NULL; }
  429. //
  430. // Access global rule info ( common to all rules )
  431. // cf. CCertGlobalRuleInfo
  432. //
  433. IISMAP_DLLEXP CCertGlobalRuleInfo* GetGlobalRulesInfo() // for ser/unser/set/get purpose
  434. { return &m_GlobalRuleInfo; }
  435. private:
  436. CReaderWriterLock3 * m_pRWLock;
  437. CCertGlobalRuleInfo m_GlobalRuleInfo;
  438. CPtrXBF m_Rules;
  439. BOOL m_fValid;
  440. } ;
  441. //
  442. // Helper functions
  443. //
  444. //
  445. // convert match request to/from internal format
  446. //
  447. //
  448. // Map user displayable sub-field content to internal format
  449. // result must be freed using FreeMatchConversion
  450. //
  451. IISMAP_DLLEXP BOOL MatchRequestToBinary( LPSTR pszReq, LPBYTE* ppbBin, LPDWORD pdwBin );
  452. //
  453. // Map internal format to user displayable content
  454. // result must be freed using FreeMatchConversion
  455. //
  456. IISMAP_DLLEXP BOOL BinaryToMatchRequest( LPBYTE pbBin, DWORD dwBin, LPSTR* ppszReq );
  457. //
  458. // Free result of the 2 previous map API
  459. //
  460. IISMAP_DLLEXP VOID FreeMatchConversion( LPVOID );
  461. //
  462. // Map field displayable name ( from a MAP_FIELD array )
  463. // to CERT_FIELD_ID. returns CERT_FIELD_ERROR if no match
  464. //
  465. IISMAP_DLLEXP CERT_FIELD_ID MapFieldToId( LPSTR pField );
  466. //
  467. // Map CERT_FIELD_ID to field displayable name ( from a MAP_FIELD array )
  468. //
  469. IISMAP_DLLEXP LPSTR MapIdToField( CERT_FIELD_ID dwId );
  470. //
  471. // Get flags for specified CERT_FIELD_ID
  472. //
  473. IISMAP_DLLEXP DWORD GetIdFlags( CERT_FIELD_ID dwId );
  474. //
  475. // Map sub field displayable name ( e.g. O, OU, CN, ... )
  476. // to ASN.1 name ( as an ascii string )
  477. // returns NULL if no match
  478. //
  479. IISMAP_DLLEXP LPSTR MapSubFieldToAsn1( LPSTR pszSubField );
  480. //
  481. // Map ASN.1 name ( as an ascii string )
  482. // to sub field displayable name ( e.g. O, OU, CN, ... )
  483. // returns ASN.1 name if no match
  484. //
  485. IISMAP_DLLEXP LPSTR MapAsn1ToSubField( LPSTR pszAsn1 );
  486. //
  487. // Enumerate known subfields
  488. //
  489. IISMAP_DLLEXP LPSTR EnumerateKnownSubFields( DWORD dwIndex );
  490. LPBYTE
  491. memstr(
  492. LPBYTE pStr,
  493. UINT cStr,
  494. LPBYTE pSub,
  495. UINT cSub,
  496. BOOL fCaseInsensitive
  497. );
  498. #endif