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.

1127 lines
45 KiB

  1. /* code to upgrade SSL keys to the latest mechanism
  2. Since there have been several mechanisms to do this in the past we need
  3. several mechanisms to store and retrieve the private and public portions
  4. of the keys.
  5. IIS2/3 used the LSA mechanism to store the keys as secrets in the registry.
  6. IIS4 stored the keys directly in the metabase as secured data objects.
  7. IIS5 will be using the native NT5 Protected Storage mechanism to keep the keys.
  8. This means that we are no longer in the business of storing, protecting and
  9. retrieving the keys. It will all be done in NT maintained facilities. However,
  10. we still need to migrate the keys over to the new storage mechanism, which is
  11. what this code is all about.
  12. One more thing. Previously the keys were associated with the virtual servers
  13. in an indirect manner. The keys (IIS4) were stored in a metabase location that
  14. was parallel to the virtual servers. Then each key had an IP\Port binding
  15. associated with it that mapped the key back to the original server.
  16. This has caused no end of confusion for the users as they struggle to associate
  17. keys with virtual servers.
  18. Now the references to the keys in the PStore are stored directly on each virtual
  19. server, creating a implicit releationship between the key and the server.
  20. The old mapping scheme also supported the concept of wildcarded IP or Port
  21. address. Whereas this new scheme does not. This means the upgrading will be done
  22. as a several stop process. First, we look for all the existing keys that are bound
  23. to a specific IP/Port combination. This takes precedence over wildcards and is
  24. applied to the keys first. Then IP/wild is applied to any matching virtual server
  25. that does not already have a key on it. Then wile/Port. Since we have always
  26. required that there can only be one default key at a time, as soon as we encounter
  27. it in the process we can just apply it to the master-properties level.
  28. Fortunately, this whole file is on NT only, so we can assume everything is UNICODE always
  29. */
  30. #include "stdafx.h"
  31. // this file is also only used on NT, so don't do anything if its win9X
  32. #ifndef _CHICAGO_
  33. #include <ole2.h>
  34. #include "iadm.h"
  35. #include "iiscnfgp.h"
  36. #include "mdkey.h"
  37. #include "lsaKeys.h"
  38. #undef MAX_SERVICE_NAME_LEN
  39. #include "elem.h"
  40. #include "mdentry.h"
  41. #include "inetinfo.h"
  42. #include "inetcom.h"
  43. #include "logtype.h"
  44. #include "ilogobj.hxx"
  45. #include "sslkeys.h"
  46. extern OCMANAGER_ROUTINES gHelperRoutines;
  47. #include <wincrypt.h>
  48. #define SECURITY_WIN32
  49. #include <sspi.h>
  50. #include <spseal.h>
  51. #include <issperr.h>
  52. #include <schnlsp.h>
  53. #include "certupgr.h"
  54. const LPCTSTR MDNAME_INCOMPLETE = _T("incomplete");
  55. const LPCTSTR MDNAME_DISABLED = _T("disabled");
  56. const LPCTSTR MDNAME_DEFAULT = _T("default");
  57. const LPCTSTR SZ_SERVER_KEYTYPE = _T("IIsWebServer");
  58. const LPTSTR SZ_SSLKEYS_NODE = _T("SSLKeys");
  59. const LPTSTR SZ_W3SVC_PATH = _T("LM/W3SVC");
  60. const LPTSTR SZ_SSLKEYS_PATH = _T("LM/W3SVC/SSLKeys");
  61. const LPWSTR SZ_CAPI_STORE = L"MY";
  62. #define ALLOW_DELETE_KEYS // Normally defined. Don't define for test purposes.
  63. //------------------------------------------------------------------------------
  64. // Given the name of a key in the metabase migrate it to the PStore. At this point we
  65. // are actually only loading and preparing the raw data. The routines to stick it in the
  66. // right place are in an external library so they can be shared with other utilities.
  67. // since the metabase key is already opened by the calling routine, pass it in as a
  68. // parameter.
  69. // returns TRUE for success
  70. PCCERT_CONTEXT MigrateKeyToPStore( CMDKey* pmdKey, CString& csMetaKeyName )
  71. {
  72. iisDebugOut((LOG_TYPE_TRACE, _T("MigrateKeyToPStore():Start.%s."), (LPCTSTR)csMetaKeyName));
  73. BOOL fSuccess = FALSE;
  74. BOOL f;
  75. DWORD dwAttr, dwUType, dwDType, cbLen;
  76. PVOID pbPrivateKey = NULL;
  77. DWORD cbPrivateKey = 0;
  78. PVOID pbPublicKey = NULL;
  79. DWORD cbPublicKey = 0;
  80. PVOID pbRequest = NULL;
  81. DWORD cbRequest = 0;
  82. PCHAR pszPassword = NULL;
  83. PCCERT_CONTEXT pcCertContext = NULL;
  84. // the actual sub key path this the sslkeys dir plus the key name. The actual metabase
  85. // object is opened to the w3svc level
  86. CString csSubKeyPath = _T("SSLKeys/");
  87. csSubKeyPath += csMetaKeyName;
  88. // get the private key - required ---------
  89. dwAttr = 0;
  90. dwUType = IIS_MD_UT_SERVER;
  91. dwDType = BINARY_METADATA;
  92. // this first call is just to get the size of the pointer we need
  93. f = pmdKey->GetData(MD_SSL_PRIVATE_KEY,&dwAttr,&dwUType,&dwDType,&cbPrivateKey,NULL,0,(PWCHAR)(LPCTSTR)csSubKeyPath);
  94. // if the get data fails on the private key, we have nothing to do
  95. if ( cbPrivateKey == 0 )
  96. {
  97. iisDebugOut((LOG_TYPE_ERROR, _T("MigrateKeyToPStore():FAILED: Unable to read private key for %s"), (LPCTSTR)csMetaKeyName));
  98. return NULL;
  99. }
  100. // allocate the buffer for the private key
  101. pbPrivateKey = GlobalAlloc( GPTR, cbPrivateKey );
  102. if ( !pbPrivateKey )
  103. {
  104. iisDebugOut((LOG_TYPE_ERROR, _T("MigrateKeyToPStore():FAILED to allocate memory for private key.")));
  105. return NULL;
  106. }
  107. // do the real call to get the data from the metabase
  108. f = pmdKey->GetData(MD_SSL_PRIVATE_KEY,&dwAttr,&dwUType,&dwDType,&cbPrivateKey,(PUCHAR)pbPrivateKey,cbPrivateKey,(PWCHAR)(LPCTSTR)csSubKeyPath);
  109. // if the get data fails on the private key, we have nothing to do
  110. if ( !f )
  111. {
  112. iisDebugOut((LOG_TYPE_ERROR, _T("MigrateKeyToPStore():FAILED: Unable to read private key for %s"), (LPCTSTR)csMetaKeyName));
  113. goto cleanup;
  114. }
  115. // get the password -required ------------
  116. // the password is stored as an ansi binary secure item.
  117. dwAttr = 0;
  118. dwUType = IIS_MD_UT_SERVER;
  119. dwDType = BINARY_METADATA;
  120. cbLen = 0;
  121. // this first call is just to get the size of the pointer we need
  122. f = pmdKey->GetData(MD_SSL_KEY_PASSWORD,&dwAttr,&dwUType,&dwDType,&cbLen,NULL,0,(PWCHAR)(LPCTSTR)csSubKeyPath);
  123. // if the get data fails on the password, we have nothing to do
  124. if ( cbLen == 0 )
  125. {
  126. iisDebugOut((LOG_TYPE_ERROR, _T("MigrateKeyToPStore():FAILED retrieve password. Nothing to do.")));
  127. goto cleanup;
  128. }
  129. // allocate the buffer for the password
  130. pszPassword = (PCHAR)GlobalAlloc( GPTR, cbLen );
  131. if ( !pszPassword )
  132. {
  133. iisDebugOut((LOG_TYPE_ERROR, _T("MigrateKeyToPStore():FAILED to allocate memory for password.")));
  134. goto cleanup;
  135. }
  136. // do the real call to get the data from the metabase
  137. f = pmdKey->GetData(MD_SSL_KEY_PASSWORD,&dwAttr,&dwUType,&dwDType,&cbLen,(PUCHAR)pszPassword,cbLen,(PWCHAR)(LPCTSTR)csSubKeyPath);
  138. // if the get data fails on the password, we have nothing to do
  139. if ( !f )
  140. {
  141. iisDebugOut((LOG_TYPE_ERROR, _T("MigrateKeyToPStore():FAILED: Unable to read ssl password for %s"), (LPCTSTR)csMetaKeyName));
  142. goto cleanup;
  143. }
  144. // get the public key -optional -----------
  145. dwAttr = 0;
  146. dwUType = IIS_MD_UT_SERVER;
  147. dwDType = BINARY_METADATA;
  148. // this first call is just to get the size of the pointer we need
  149. f = pmdKey->GetData(MD_SSL_PUBLIC_KEY,&dwAttr,&dwUType,&dwDType,&cbPublicKey,NULL,0,(PWCHAR)(LPCTSTR)csSubKeyPath);
  150. // the public key is optional, so don't fail if we don't get it
  151. if ( cbPublicKey )
  152. {
  153. // allocate the buffer for the private key
  154. pbPublicKey = GlobalAlloc( GPTR, cbPublicKey );
  155. if ( !pbPublicKey )
  156. {
  157. iisDebugOut((LOG_TYPE_ERROR, _T("MigrateKeyToPStore():FAILED to allocate memory for public key.")));
  158. }
  159. else
  160. {
  161. // do the real call to get the data from the metabase
  162. f = pmdKey->GetData(MD_SSL_PUBLIC_KEY,&dwAttr,&dwUType,&dwDType,&cbPublicKey,(PUCHAR)pbPublicKey,cbPublicKey,(PWCHAR)(LPCTSTR)csSubKeyPath);
  163. // if the get data fails on the public key, clean it up and reset it to null
  164. if ( !f )
  165. {
  166. if ( pbPublicKey )
  167. {
  168. GlobalFree( pbPublicKey );
  169. pbPublicKey = NULL;
  170. }
  171. cbPublicKey = 0;
  172. }
  173. }
  174. }
  175. // get the request -optional -----------
  176. dwAttr = 0;
  177. dwUType = IIS_MD_UT_SERVER;
  178. dwDType = BINARY_METADATA;
  179. // this first call is just to get the size of the pointer we need
  180. f = pmdKey->GetData(MD_SSL_KEY_REQUEST,&dwAttr,&dwUType,&dwDType,
  181. &cbRequest,NULL,0,(PWCHAR)(LPCTSTR)csSubKeyPath);
  182. // the request is optional, so don't fail if we don't get it
  183. if ( cbRequest )
  184. {
  185. // allocate the buffer for the private key
  186. pbRequest = GlobalAlloc( GPTR, cbRequest );
  187. if ( !pbRequest )
  188. {
  189. iisDebugOut((LOG_TYPE_ERROR, _T("MigrateKeyToPStore():FAILED to allocate memory for key request.")));
  190. }
  191. else
  192. {
  193. // do the real call to get the data from the metabase
  194. f = pmdKey->GetData(MD_SSL_KEY_REQUEST,&dwAttr,&dwUType,&dwDType,
  195. &cbRequest,(PUCHAR)pbRequest,cbRequest,(PWCHAR)(LPCTSTR)csSubKeyPath);
  196. // if the get data fails on the key request, clean it up and reset it to null
  197. if ( !f )
  198. {
  199. if ( pbRequest )
  200. {
  201. GlobalFree( pbRequest );
  202. pbRequest = NULL;
  203. }
  204. cbRequest = 0;
  205. }
  206. }
  207. }
  208. // ------------------------------------------------------------------
  209. // Now that we've loaded the data, we can call the conversion utility
  210. // ------------------------------------------------------------------
  211. pcCertContext = CopyKRCertToCAPIStore(
  212. pbPrivateKey, cbPrivateKey,
  213. pbPublicKey, cbPublicKey,
  214. pbRequest, cbRequest,
  215. pszPassword,
  216. SZ_CAPI_STORE,
  217. TRUE
  218. );
  219. if ( pcCertContext )
  220. {
  221. iisDebugOut((LOG_TYPE_TRACE, _T("MigrateKeyToPStore():CopyKRCertToCAPIStore():Upgrade KR key to CAPI for %s. Success."), (LPCTSTR)csMetaKeyName));
  222. }
  223. else
  224. {
  225. iisDebugOut((LOG_TYPE_ERROR, _T("MigrateKeyToPStore():CopyKRCertToCAPIStore():Upgrade KR key to CAPI for %s. FAILED."), (LPCTSTR)csMetaKeyName));
  226. }
  227. cleanup:
  228. if ( pbPrivateKey ) {GlobalFree( pbPrivateKey );}
  229. if ( pbPublicKey ) {GlobalFree( pbPublicKey );}
  230. if ( pszPassword ) {GlobalFree( pszPassword );}
  231. iisDebugOut((LOG_TYPE_TRACE, _T("MigrateKeyToPStore():End.%s."), (LPCTSTR)csMetaKeyName));
  232. return pcCertContext;
  233. }
  234. //------------------------------------------------------------------------------
  235. // write a reference to a PStore key on a specific node in the metabase
  236. void WriteKeyReference( CMDKey& cmdW3SVC, PWCHAR pwchSubPath, PCCERT_CONTEXT pCert )
  237. {
  238. // get the hash that we need to write out
  239. //
  240. // SHA produces 160 bit hash for any message < 2^64 bits in length
  241. BYTE HashBuffer[40]; // give it some extra size
  242. DWORD dwHashSize = sizeof(HashBuffer);
  243. iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("CRYPT32.dll:CertGetCertificateContextProperty().Start.")));
  244. if ( !CertGetCertificateContextProperty( pCert,
  245. CERT_SHA1_HASH_PROP_ID,
  246. (VOID *) HashBuffer,
  247. &dwHashSize ) )
  248. {
  249. iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("CRYPT32.dll:CertGetCertificateContextProperty().End.")));
  250. if ( GetLastError() == ERROR_MORE_DATA )
  251. {
  252. //Very odd, cert wants more space ..
  253. iisDebugOut((LOG_TYPE_ERROR, _T("FAILED: StoreCertInfoInMetabase Unable to get hash property")));
  254. }
  255. // We definitely need to store the hash of the cert, so error out
  256. return;
  257. }
  258. else
  259. {
  260. iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("CRYPT32.dll:CertGetCertificateContextProperty().End.")));
  261. }
  262. // write out the hash of the certificate
  263. cmdW3SVC.SetData( MD_SSL_CERT_HASH, METADATA_INHERIT, IIS_MD_UT_SERVER, BINARY_METADATA,
  264. dwHashSize, (PUCHAR)&HashBuffer, pwchSubPath );
  265. // write out the name of the store
  266. cmdW3SVC.SetData( MD_SSL_CERT_STORE_NAME, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA,
  267. (_tcslen(SZ_CAPI_STORE)+1) * sizeof(TCHAR), (PUCHAR)SZ_CAPI_STORE, pwchSubPath );
  268. }
  269. //------------------------------------------------------------------------------
  270. // store a reference to a PStore key on all the appropriate virtual servers. If csIP
  271. // or csPort is empty, then that item is a wildcard and applies to all virtual servers.
  272. void StoreKeyReference( CMDKey& cmdW3SVC, PCCERT_CONTEXT pCert, CString& csIP, CString& csPort )
  273. {
  274. TCHAR szForDebug[100];
  275. if (csIP)
  276. {
  277. if (csPort){_stprintf(szForDebug, _T("ip:%s port:%s"), csIP, csPort);}
  278. else{_stprintf(szForDebug, _T("ip:%s port:(null)"), csIP);}
  279. }
  280. else
  281. {
  282. if (csPort){_stprintf(szForDebug, _T("ip:(null) port:%s"), csPort);}
  283. else{_stprintf(szForDebug, _T("ip:(null) port:(null)"));}
  284. }
  285. iisDebugOut((LOG_TYPE_TRACE, _T("StoreKeyReference.Start.%s."),szForDebug));
  286. // if it was unable to open the node, then there are no keys to upgrade.
  287. if ( (METADATA_HANDLE)cmdW3SVC == NULL )
  288. {
  289. iisDebugOut((LOG_TYPE_ERROR, _T("FAILED: passed in invalid metabase handle")));
  290. iisDebugOut((LOG_TYPE_TRACE, _T("StoreKeyReference End")));
  291. return;
  292. }
  293. // generate the iterator for retrieving the virtual servers
  294. CMDKeyIter cmdKeyEnum( cmdW3SVC );
  295. CString csNodeName; // Metabase name for the virtual server
  296. CString csNodeType; // node type indicator string
  297. CString csBinding;
  298. PVOID pData = NULL;
  299. BOOL f;
  300. DWORD dwAttr, dwUType, dwDType, cbLen, dwLength;
  301. // iterate through the virtual servers
  302. iisDebugOut((LOG_TYPE_TRACE, _T("StoreKeyReference.Start.%s.iterate through the virtual servers"),szForDebug));
  303. while (cmdKeyEnum.Next(&csNodeName) == ERROR_SUCCESS)
  304. {
  305. // some of the keys under this node are not virutal servers. Thus
  306. // we first need to check the node type property. If it is not a
  307. // virtual server then we can just contiue on to the next node.
  308. // get the string that indicates the node type
  309. dwAttr = 0;
  310. dwUType = IIS_MD_UT_SERVER;
  311. dwDType = STRING_METADATA;
  312. cbLen = 200;
  313. f = cmdW3SVC.GetData(MD_KEY_TYPE,
  314. &dwAttr,
  315. &dwUType,
  316. &dwDType,
  317. &cbLen,
  318. (PUCHAR)csNodeType.GetBuffer(cbLen),
  319. cbLen,
  320. (PWCHAR)(LPCTSTR)csNodeName);
  321. csNodeType.ReleaseBuffer();
  322. // check it - if the node is not a virutal server, then continue on to the next node
  323. if ( csNodeType != SZ_SERVER_KEYTYPE )
  324. {
  325. iisDebugOut((LOG_TYPE_TRACE, _T("StoreKeyReference.Start.%s.%s not a virtualserver, skip."),szForDebug,csNodeName));
  326. continue;
  327. }
  328. // before we do anything else, check if this virtual server already has a key on it.
  329. // if it does then do not do anything to it. Continue on to the next one
  330. // we don't actually need to load any data for this to work, so we can call GetData
  331. // with a size of zero as if we are querying for the size. If that succeedes, then
  332. // we know that it is there and can continue on
  333. dwAttr = 0; // do not inherit
  334. dwUType = IIS_MD_UT_SERVER;
  335. dwDType = BINARY_METADATA;
  336. dwLength = 0;
  337. cmdW3SVC.GetData( MD_SSL_CERT_HASH,
  338. &dwAttr,
  339. &dwUType,
  340. &dwDType,
  341. &dwLength,
  342. NULL,
  343. 0,
  344. 0, // do not inherit
  345. IIS_MD_UT_SERVER,
  346. BINARY_METADATA,
  347. (PWCHAR)(LPCTSTR)csNodeName);
  348. // if there is a key there already - continue to the next node
  349. if ( dwLength > 0 )
  350. {
  351. iisDebugOut((LOG_TYPE_TRACE, _T("StoreKeyReference.Start.%s.%s already has a key there, skip."),szForDebug,csNodeName));
  352. continue;
  353. }
  354. // this is a valid virtual server with no pre-existing key. Now we need to load
  355. // the bindings and see if we have a match
  356. dwAttr = 0; // do not inherit
  357. dwUType = IIS_MD_UT_SERVER;
  358. dwDType = MULTISZ_METADATA;
  359. dwLength = 0;
  360. // The bindings are in a multi-sz. So, first we need to figure out how much space we need
  361. f = cmdW3SVC.GetData( MD_SECURE_BINDINGS,
  362. &dwAttr,
  363. &dwUType,
  364. &dwDType,
  365. &dwLength,
  366. NULL,
  367. 0,
  368. 0, // do not inherit
  369. IIS_MD_UT_SERVER,
  370. MULTISZ_METADATA,
  371. (PWCHAR)(LPCTSTR)csNodeName);
  372. // if the length is zero, then there are no bindings
  373. if ( dwLength == 0 )
  374. {
  375. iisDebugOut((LOG_TYPE_TRACE, _T("StoreKeyReference.Start.%s.%s data len=0 no bindings, skip."),szForDebug,csNodeName));
  376. continue;
  377. }
  378. // Prepare some space to receive the bindings
  379. TCHAR* pBindings;
  380. // if pData is pointing to something, then we need to free it so that we don't leak
  381. if ( pData )
  382. {
  383. GlobalFree( pData );
  384. pData = NULL;
  385. }
  386. // allocate the space, if it fails, we fail
  387. // note that GPTR causes it to be initialized to zero
  388. pData = GlobalAlloc( GPTR, dwLength + 2 );
  389. if ( !pData )
  390. {
  391. iisDebugOut((LOG_TYPE_ERROR, _T("StoreKeyReference.Start.%s.%s GlobalAlloc failed."),szForDebug,csNodeName));
  392. continue;
  393. }
  394. pBindings = (TCHAR*)pData;
  395. // now get the real data from the metabase
  396. f = cmdW3SVC.GetData( MD_SECURE_BINDINGS,
  397. &dwAttr,
  398. &dwUType,
  399. &dwDType,
  400. &dwLength,
  401. (PUCHAR)pBindings,
  402. dwLength,
  403. 0, // do not inherit
  404. IIS_MD_UT_SERVER,
  405. MULTISZ_METADATA,
  406. (PWCHAR)(LPCTSTR)csNodeName );
  407. // if we did not get the bindings, then this node doesn't have any security
  408. // options set on it. We can continue on to the next virtual server
  409. if ( FALSE == f )
  410. {
  411. iisDebugOut((LOG_TYPE_TRACE, _T("StoreKeyReference.Start.%s.%s No security options set on it, skip."),szForDebug,csNodeName));
  412. continue;
  413. }
  414. // OK. We do have bindings. Now we get to parse them out and check them
  415. // against the binding strings that were passed in. Note: if a binding
  416. // matches, but has a host-header at the end, then it does not qualify
  417. // got the existing bindings, scan them now - pBindings will be pointing at the second end \0
  418. // when it is time to exit the loop.
  419. while ( *pBindings )
  420. {
  421. csBinding = pBindings;
  422. csBinding.TrimRight();
  423. CString csBindIP;
  424. CString csBindPort; // don't actually care about this one
  425. // get the binding's IP and port sections so we can look for wildcards in the binding itself
  426. PrepIPPortName( csBinding, csBindIP, csBindPort );
  427. // if there is a specified IP, look for it. If we don't find it, go to the next binding.
  428. if ( !csIP.IsEmpty() && !csBindIP.IsEmpty() )
  429. {
  430. // if the IP is not in the binding then bail on this binding
  431. if ( csBinding.Find( csIP ) < 0 )
  432. {
  433. iisDebugOut((LOG_TYPE_TRACE, _T("StoreKeyReference.Start.%s.%s:org=%s,findIP=%s bail."),szForDebug,csNodeName,csBinding,csIP));
  434. goto NextBinding;
  435. }
  436. }
  437. // if there is a specified Port, look for it. If we don't find it, go to the next binding.\
  438. // secure bindings themselves always have a port
  439. if ( !csPort.IsEmpty() )
  440. {
  441. // if the Port is not in the binding then bail on this binding
  442. if ( csBinding.Find( csPort ) < 0 )
  443. {
  444. iisDebugOut((LOG_TYPE_TRACE, _T("StoreKeyReference.Start.%s.%s:org=%s,findport=%s bail."),szForDebug,csNodeName,csBinding,csPort));
  445. goto NextBinding;
  446. }
  447. }
  448. // test if host headers are there by doing a reverse find for the last colon. Then
  449. // check if it is the last character. If it isn't, then there is a host-header and
  450. // we should go to a different binding
  451. if ( csBinding.ReverseFind(_T(':')) < (csBinding.GetLength()-1) )
  452. {
  453. iisDebugOut((LOG_TYPE_TRACE, _T("StoreKeyReference.Start.%s.%s:bail2."),szForDebug,csNodeName));
  454. goto NextBinding;
  455. }
  456. // Well, this is a valid binding on a valid virtual server, we can now write out the key
  457. iisDebugOut((LOG_TYPE_TRACE, _T("StoreKeyReference.%s.%s:Write out the key!"),szForDebug,csNodeName));
  458. WriteKeyReference( cmdW3SVC, (PWCHAR)(LPCTSTR)csNodeName, pCert );
  459. // we can break to get out of the specific bindings loop
  460. break;
  461. NextBinding:
  462. // increment pBindings to the next string
  463. pBindings = _tcsninc( pBindings, _tcslen(pBindings))+1;
  464. }
  465. }
  466. // if pData is pointing to something, then we need to free it so that we don't leak
  467. if ( pData )
  468. {
  469. GlobalFree( pData );
  470. pData = NULL;
  471. }
  472. iisDebugOut((LOG_TYPE_TRACE, _T("StoreKeyReference.End.%s."),szForDebug));
  473. }
  474. //------------------------------------------------------------------------------
  475. // given a metabase key name, create strings that can be used to search the virutal servers
  476. // an empty string is a wildcard.
  477. BOOL PrepIPPortName( CString& csKeyMetaName, CString& csIP, CString& csPort )
  478. {
  479. int iColon;
  480. // the first thing we are going to do is seperate the IP and PORT into seperate strings
  481. // actually, thats not true. Prep the string by putting a colon in it.
  482. csIP.Empty();
  483. csPort = _T(':');
  484. // look for the first ':' and seperate
  485. iColon = csKeyMetaName.Find( _T(':') );
  486. // if we got the colon, we can seperate easy
  487. if ( iColon >= 0 )
  488. {
  489. csIP = csKeyMetaName.Left(iColon);
  490. csPort += csKeyMetaName.Right(csKeyMetaName.GetLength() - iColon - 1);
  491. }
  492. // we did not get the colon, so it is one or the other, look for a '.' to get the IP
  493. else
  494. {
  495. if ( csKeyMetaName.Find( _T('.') ) >= 0 )
  496. csIP = csKeyMetaName;
  497. else
  498. csPort += csKeyMetaName;
  499. }
  500. // finish decorating the strings with colons if appropriate.
  501. if ( !csIP.IsEmpty() )
  502. csIP += _T(':');
  503. // If the only thing in the port string is a : then it is a wildcard. Clear it out.
  504. if ( csPort.GetLength() == 1 )
  505. {
  506. csPort.Empty();
  507. }
  508. else
  509. {
  510. // add a final colon to it
  511. csPort += _T(':');
  512. }
  513. return TRUE;
  514. }
  515. //------------------------------------------------------------------------------
  516. // used when upgrading from IIS2 or IIS3
  517. // this code was in the K2 setup program that shipped. It used to reside in mdentry.cpp and
  518. // has now been encapsulted into its own routine and moved here. The only change to it has been
  519. // to add the Upgradeiis4Toiis5MetabaseSSLKeys call at the end.
  520. void UpgradeLSAKeys( PWCHAR pszwTargetMachine )
  521. {
  522. iisDebugOut((LOG_TYPE_TRACE, _T("UpgradeLSAKeys Start")));
  523. DWORD retCode = KEYLSA_SUCCESS;
  524. MDEntry stMDEntry;
  525. CString csMDPath;
  526. TCHAR tchFriendlyName[_MAX_PATH], tchMetaName[_MAX_PATH];
  527. BOOL fUpgradedAKey = FALSE;
  528. CLSAKeys lsaKeys;
  529. WCHAR wchMachineName[UNLEN + 1];
  530. memset( (PVOID)wchMachineName, 0, sizeof(wchMachineName));
  531. #if defined(UNICODE) || defined(_UNICODE)
  532. wcsncpy(wchMachineName, g_pTheApp->m_csMachineName, UNLEN);
  533. #else
  534. MultiByteToWideChar(CP_ACP, 0, (LPCSTR)g_pTheApp->m_csMachineName, -1, (LPWSTR)wchMachineName, UNLEN);
  535. #endif
  536. retCode = lsaKeys.LoadFirstKey(wchMachineName);
  537. while (retCode == KEYLSA_SUCCESS) {
  538. #if defined(UNICODE) || defined(_UNICODE)
  539. MultiByteToWideChar(CP_ACP, 0, (LPCSTR)lsaKeys.m_szMetaName, -1, (LPWSTR)tchMetaName, _MAX_PATH);
  540. MultiByteToWideChar(CP_ACP, 0, (LPCSTR)lsaKeys.m_szFriendlyName, -1, (LPWSTR)tchFriendlyName, _MAX_PATH);
  541. #else
  542. _tcscpy(tchMetaName, lsaKeys.m_szMetaName);
  543. _tcscpy(tchFriendlyName, lsaKeys.m_szFriendlyName);
  544. #endif
  545. iisDebugOut((LOG_TYPE_TRACE, _T("lsaKeys: FriendName=%s MetaName=%s\n"), tchFriendlyName, tchMetaName));
  546. csMDPath = SZ_SSLKEYS_PATH;
  547. csMDPath += _T("/");
  548. csMDPath += (CString)tchMetaName;
  549. stMDEntry.szMDPath = (LPTSTR)(LPCTSTR)csMDPath;
  550. stMDEntry.dwMDIdentifier = MD_SSL_FRIENDLY_NAME;
  551. stMDEntry.dwMDAttributes = METADATA_INHERIT;
  552. stMDEntry.dwMDUserType = IIS_MD_UT_SERVER;
  553. stMDEntry.dwMDDataType = STRING_METADATA;
  554. stMDEntry.dwMDDataLen = (_tcslen(tchFriendlyName) + 1) * sizeof(TCHAR);
  555. stMDEntry.pbMDData = (LPBYTE)tchFriendlyName;
  556. SetMDEntry(&stMDEntry);
  557. stMDEntry.dwMDIdentifier = MD_SSL_PUBLIC_KEY;
  558. stMDEntry.dwMDAttributes = METADATA_INHERIT | METADATA_SECURE;
  559. stMDEntry.dwMDUserType = IIS_MD_UT_SERVER;
  560. stMDEntry.dwMDDataType = BINARY_METADATA;
  561. stMDEntry.dwMDDataLen = lsaKeys.m_cbPublic;
  562. stMDEntry.pbMDData = (LPBYTE)lsaKeys.m_pPublic;
  563. SetMDEntry(&stMDEntry);
  564. stMDEntry.dwMDIdentifier = MD_SSL_PRIVATE_KEY;
  565. stMDEntry.dwMDDataLen = lsaKeys.m_cbPrivate;
  566. stMDEntry.pbMDData = (LPBYTE)lsaKeys.m_pPrivate;
  567. SetMDEntry(&stMDEntry);
  568. stMDEntry.dwMDIdentifier = MD_SSL_KEY_PASSWORD;
  569. stMDEntry.dwMDDataLen = lsaKeys.m_cbPassword;
  570. stMDEntry.pbMDData = (LPBYTE)lsaKeys.m_pPassword;
  571. SetMDEntry(&stMDEntry);
  572. stMDEntry.dwMDIdentifier = MD_SSL_KEY_REQUEST;
  573. stMDEntry.dwMDDataLen = lsaKeys.m_cbRequest;
  574. stMDEntry.pbMDData = (LPBYTE)lsaKeys.m_pRequest;
  575. SetMDEntry(&stMDEntry);
  576. fUpgradedAKey = TRUE;
  577. retCode = lsaKeys.LoadNextKey();
  578. }
  579. if (retCode == KEYLSA_NO_MORE_KEYS) {
  580. iisDebugOut((LOG_TYPE_TRACE, _T("No More Keys\n")));
  581. lsaKeys.DeleteAllLSAKeys();
  582. }
  583. // Now that the keys have been upgraded to the metabase, upgrade again from
  584. // the metabase to the PStore
  585. if ( fUpgradedAKey )
  586. Upgradeiis4Toiis5MetabaseSSLKeys();
  587. iisDebugOut((LOG_TYPE_TRACE, _T("UpgradeLSAKeys End")));
  588. }
  589. //------------------------------------------------------------------------------
  590. // the plan here is to enumerate all the server keys under the SSLKEYS key in the metabase.
  591. // Then they need to be migrated to the PStore and have their references resaved into
  592. // the correct virtual server.
  593. //
  594. // How the heck does all this work?
  595. //
  596. // iis4.0 metabase looks like this:
  597. // w3svc
  598. // w3svc/1
  599. // w3svc/2
  600. // sslkeys
  601. // sslkeys/(entry1) <--could be one of either of the ssl key types list below
  602. // sslkeys/(entry2) <--
  603. // sslkeys/(entry3) <--
  604. //
  605. // sslkey types:
  606. // sslkeys/MDNAME_DISABLED
  607. // sslkeys/MDNAME_INCOMPLETE
  608. // sslkeys/MDNAME_DEFAULT
  609. // sslkeys/ip:port
  610. //
  611. // step 1. Grab all these sslkeys/entries and move them into the new storage (MigrateKeyToPStore)
  612. // (for each entry we move into the new storage, we add an entry to a Cstring List to say (we did this one already) )
  613. // a. do it in iteration#1 for In this loop we look for the default key, disabled keys, incomplete keys, and keys specified by specific IP/Port pairs.
  614. // b. do it in iteration#2 for IP/wild port keys.
  615. // c. do it in iteration#3 the rest of the keys, which should all be wild ip/Port keys.
  616. // step 2. for each of these keys which we moved to the new storage: store the reference which we get back from CAPI
  617. // in our metabase (StoreKeyReference)
  618. // step 3. Make sure to keep the metabasekeys around, because setup may actually fail: so we don't want to delete the keys
  619. // until we are sure that setup is completed.
  620. // step 4. after setup completes without any errors, we delete all the sslkeys
  621. //
  622. void Upgradeiis4Toiis5MetabaseSSLKeys()
  623. {
  624. iisDebugOut_Start(_T("Upgradeiis4Toiis5MetabaseSSLKeys"), LOG_TYPE_TRACE);
  625. iisDebugOut((LOG_TYPE_TRACE, _T("--------------------------------------")));
  626. CString csMDPath;
  627. // start by testing that the sslkeys node exists.
  628. CMDKey cmdKey;
  629. cmdKey.OpenNode( SZ_SSLKEYS_PATH );
  630. if ( (METADATA_HANDLE)cmdKey == NULL )
  631. {
  632. // there is nothing to do
  633. iisDebugOut((LOG_TYPE_TRACE, _T("Nothing to do.")));
  634. return;
  635. }
  636. cmdKey.Close();
  637. // create a key object for the SSLKeys level in the metabase. Open it too.
  638. cmdKey.OpenNode( SZ_W3SVC_PATH );
  639. if ( (METADATA_HANDLE)cmdKey == NULL )
  640. {
  641. // if it was unable to open the node, then there are no keys to upgrade.
  642. iisDebugOut((LOG_TYPE_WARN, _T("could not open lm/w3svc")));
  643. iisDebugOut_End(_T("Upgradeiis4Toiis5MetabaseSSLKeys,No keys to upgrade"),LOG_TYPE_TRACE);
  644. return;
  645. }
  646. // create and prepare a metadata iterator object for the sslkeys
  647. CMDKeyIter cmdKeyEnum(cmdKey);
  648. CString csKeyName; // Metabase name for the key
  649. // used to parse out the name information
  650. CString csIP;
  651. CString csPort;
  652. //CString csSubPath;
  653. PCCERT_CONTEXT pCert = NULL;
  654. PCCERT_CONTEXT pDefaultCert = NULL;
  655. BOOL bUpgradeToPStoreIsGood = TRUE;
  656. // do the first iteration. In this loop we look for the default key, disabled keys,
  657. // incomplete keys, and keys specified by specific IP/Port pairs.
  658. // Note: cmdKeyEnum.m_index is the index member for the iterator
  659. iisDebugOut((LOG_TYPE_TRACE, _T("1.first interate for default,disabled,incomplete,and keys specified by specific IP/Port pairs.")));
  660. while (cmdKeyEnum.Next(&csKeyName, SZ_SSLKEYS_NODE ) == ERROR_SUCCESS)
  661. {
  662. iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("KeyName=%s."),csKeyName));
  663. pCert = NULL;
  664. // look for disabled keys
  665. if ( csKeyName.Find(MDNAME_DISABLED) >= 0)
  666. {
  667. pCert = MigrateKeyToPStore( &cmdKey, csKeyName );
  668. if (!pCert){bUpgradeToPStoreIsGood = FALSE;}
  669. }
  670. // look for incomplete keys
  671. else if ( csKeyName.Find(MDNAME_INCOMPLETE) >= 0)
  672. {
  673. pCert = MigrateKeyToPStore( &cmdKey, csKeyName );
  674. if (!pCert){bUpgradeToPStoreIsGood = FALSE;}
  675. }
  676. // look for the default key
  677. else if ( csKeyName.Find(MDNAME_DEFAULT) >= 0)
  678. {
  679. pDefaultCert = MigrateKeyToPStore( &cmdKey, csKeyName );
  680. if (!pDefaultCert){bUpgradeToPStoreIsGood = FALSE;}
  681. }
  682. // parse the IP/Port name
  683. else
  684. {
  685. // we are only taking keys that have both the IP and the Port specified at this time
  686. PrepIPPortName( csKeyName, csIP, csPort );
  687. if ( !csIP.IsEmpty() && !csPort.IsEmpty() )
  688. {
  689. // move the key from the metabase to the
  690. pCert = MigrateKeyToPStore( &cmdKey, csKeyName );
  691. if ( pCert )
  692. {StoreKeyReference( cmdKey, pCert, csIP, csPort );}
  693. else
  694. {bUpgradeToPStoreIsGood = FALSE;}
  695. }
  696. }
  697. // don't leak CAPI certificate contexts now that we are done with it
  698. if ( pCert )
  699. {
  700. iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("CRYPT32.dll:CertFreeCertificateContext().Start.")));
  701. CertFreeCertificateContext( pCert );
  702. iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("CRYPT32.dll:CertFreeCertificateContext().End.")));
  703. }
  704. } // end while part 1
  705. // do the second iteration looking only for IP/wild port keys.
  706. iisDebugOut((LOG_TYPE_TRACE, _T("2.Second iteration looking only for IP/wild port keys.")));
  707. cmdKeyEnum.Reset();
  708. while (cmdKeyEnum.Next(&csKeyName, SZ_SSLKEYS_NODE ) == ERROR_SUCCESS)
  709. {
  710. pCert = NULL;
  711. // parse the IP/Port name
  712. // we are only taking keys that have the IP specified at this time
  713. PrepIPPortName( csKeyName, csIP, csPort );
  714. if ( !csIP.IsEmpty() && csPort.IsEmpty() )
  715. {
  716. // move the key from the metabase to the
  717. pCert = MigrateKeyToPStore( &cmdKey, csKeyName );
  718. if ( pCert )
  719. {StoreKeyReference( cmdKey, pCert, csIP, csPort );}
  720. else
  721. {bUpgradeToPStoreIsGood = FALSE;}
  722. }
  723. // don't leak CAPI certificate contexts now that we are done with it
  724. if ( pCert )
  725. {
  726. iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("CRYPT32.dll:CertFreeCertificateContext().Start.")));
  727. CertFreeCertificateContext( pCert );
  728. iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("CRYPT32.dll:CertFreeCertificateContext().End.")));
  729. }
  730. }
  731. // upgrade the rest of the keys, which should all be wild ip/Port keys.
  732. iisDebugOut((LOG_TYPE_TRACE, _T("3.upgrade the rest of the keys, which should all be wild ip/Port keys.")));
  733. cmdKeyEnum.Reset();
  734. while (cmdKeyEnum.Next(&csKeyName, SZ_SSLKEYS_NODE) == ERROR_SUCCESS)
  735. {
  736. pCert = NULL;
  737. // parse the IP/Port name
  738. // we are only taking keys that have the PORT specified at this time
  739. PrepIPPortName( csKeyName, csIP, csPort );
  740. if ( !csPort.IsEmpty() && csIP.IsEmpty())
  741. {
  742. // move the key from the metabase to the
  743. pCert = MigrateKeyToPStore( &cmdKey, csKeyName );
  744. if ( pCert )
  745. {StoreKeyReference( cmdKey, pCert, csIP, csPort );}
  746. else
  747. {bUpgradeToPStoreIsGood = FALSE;}
  748. }
  749. // don't leak CAPI certificate contexts now that we are done with it
  750. if ( pCert )
  751. {
  752. iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("CRYPT32.dll:CertFreeCertificateContext().Start.")));
  753. CertFreeCertificateContext( pCert );
  754. iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("CRYPT32.dll:CertFreeCertificateContext().End.")));
  755. }
  756. }
  757. // if there is one, write the default key reference out
  758. if ( pDefaultCert )
  759. {
  760. iisDebugOut((LOG_TYPE_TRACE, _T("4.write default key reference out")));
  761. CString csPortDefault;
  762. // old way which used to put it on the lm/w3svc node.
  763. // but we can't do that anymore since that node can't be accessed by the iis snap-in!
  764. //WriteKeyReference( cmdKey, L"", pDefaultCert );
  765. csPortDefault = _T(":443:");
  766. StoreKeyReference_Default( cmdKey, pDefaultCert, csPortDefault );
  767. // don't leak CAPI certificate contexts now that we are done with it
  768. iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("CRYPT32.dll:CertFreeCertificateContext().Start.")));
  769. CertFreeCertificateContext( pDefaultCert );
  770. iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("CRYPT32.dll:CertFreeCertificateContext().End.")));
  771. }
  772. //#ifdef ALLOW_DELETE_KEYS
  773. if (TRUE == bUpgradeToPStoreIsGood)
  774. {
  775. iisDebugOut((LOG_TYPE_TRACE, _T("Upgradeiis4Toiis5MetabaseSSLKeys. 5. Removing upgraded sslkeys node.")));
  776. // delete the sslkeys node in the metabase
  777. cmdKey.DeleteNode( SZ_SSLKEYS_NODE );
  778. }
  779. else
  780. {
  781. iisDebugOut((LOG_TYPE_TRACE, _T("Upgradeiis4Toiis5MetabaseSSLKeys. 6. MigrateKeyToPStore failed so keeping ssl key in metabase.")));
  782. }
  783. //#endif //ALLOW_DELETE_KEYS
  784. // close the master properties key.
  785. cmdKey.Close();
  786. iisDebugOut_End(_T("Upgradeiis4Toiis5MetabaseSSLKeys"), LOG_TYPE_TRACE);
  787. iisDebugOut((LOG_TYPE_TRACE, _T("--------------------------------------")));
  788. // force the metabase to write.
  789. WriteToMD_ForceMetabaseToWriteToDisk();
  790. return;
  791. }
  792. //------------------------------------------------------------------------------
  793. // store a reference to a PStore key on all the appropriate virtual servers.
  794. void StoreKeyReference_Default( CMDKey& cmdW3SVC, PCCERT_CONTEXT pCert, CString& csPort )
  795. {
  796. iisDebugOut_Start(_T("StoreKeyReference_Default"), LOG_TYPE_TRACE);
  797. // generate the iterator for retrieving the virtual servers
  798. CMDKeyIter cmdKeyEnum( cmdW3SVC );
  799. CString csNodeName; // Metabase name for the virtual server
  800. CString csNodeType; // node type indicator string
  801. CString csBinding;
  802. PVOID pData = NULL;
  803. BOOL f;
  804. DWORD dwAttr, dwUType, dwDType, cbLen, dwLength;
  805. // We are looking for a particular port which is stored in csPort.
  806. // if there is no csPort passed in then lets get out of here!
  807. if ( csPort.IsEmpty() )
  808. {
  809. goto StoreKeyReference_Default_Exit;
  810. }
  811. // if it was unable to open the node, then there are no keys to upgrade.
  812. if ( (METADATA_HANDLE)cmdW3SVC == NULL )
  813. {
  814. iisDebugOut((LOG_TYPE_ERROR, _T("passed in invalid metabase handle")));
  815. goto StoreKeyReference_Default_Exit;
  816. }
  817. // iterate through the virtual servers
  818. while (cmdKeyEnum.Next(&csNodeName) == ERROR_SUCCESS)
  819. {
  820. // some of the keys under this node are not virutal servers. Thus
  821. // we first need to check the node type property. If it is not a
  822. // virtual server then we can just contiue on to the next node.
  823. // get the string that indicates the node type
  824. dwAttr = 0;
  825. dwUType = IIS_MD_UT_SERVER;
  826. dwDType = STRING_METADATA;
  827. cbLen = 200;
  828. f = cmdW3SVC.GetData(MD_KEY_TYPE,
  829. &dwAttr,
  830. &dwUType,
  831. &dwDType,
  832. &cbLen,
  833. (PUCHAR)csNodeType.GetBuffer(cbLen),
  834. cbLen,
  835. (PWCHAR)(LPCTSTR)csNodeName);
  836. csNodeType.ReleaseBuffer();
  837. // check it - if the node is not a virutal server, then continue on to the next node
  838. if ( csNodeType != SZ_SERVER_KEYTYPE )
  839. {
  840. continue;
  841. }
  842. // before we do anything else, check if this virtual server already has a key on it.
  843. // if it does then do not do anything to it. Continue on to the next one
  844. // we don't actually need to load any data for this to work, so we can call GetData
  845. // with a size of zero as if we are querying for the size. If that succeedes, then
  846. // we know that it is there and can continue on
  847. dwAttr = 0; // do not inherit
  848. dwUType = IIS_MD_UT_SERVER;
  849. dwDType = BINARY_METADATA;
  850. dwLength = 0;
  851. cmdW3SVC.GetData(MD_SSL_CERT_HASH,
  852. &dwAttr,
  853. &dwUType,
  854. &dwDType,
  855. &dwLength,
  856. NULL,
  857. 0,
  858. 0, // do not inherit
  859. IIS_MD_UT_SERVER,
  860. BINARY_METADATA,
  861. (PWCHAR)(LPCTSTR)csNodeName);
  862. // if there is a key there already - continue to the next node
  863. if ( dwLength > 0 )
  864. {
  865. continue;
  866. }
  867. // this is a valid virtual server with no pre-existing key. Now we need to load
  868. // the bindings and see if we have a match
  869. dwAttr = 0; // do not inherit
  870. dwUType = IIS_MD_UT_SERVER;
  871. dwDType = MULTISZ_METADATA;
  872. dwLength = 0;
  873. // The bindings are in a multi-sz. So, first we need to figure out how much space we need
  874. f = cmdW3SVC.GetData( MD_SECURE_BINDINGS,
  875. &dwAttr,
  876. &dwUType,
  877. &dwDType,
  878. &dwLength,
  879. NULL,
  880. 0,
  881. 0, // do not inherit
  882. IIS_MD_UT_SERVER,
  883. MULTISZ_METADATA,
  884. (PWCHAR)(LPCTSTR)csNodeName);
  885. // if the length is zero, then there are no bindings
  886. if ( dwLength == 0 )
  887. {
  888. continue;
  889. }
  890. // Prepare some space to receive the bindings
  891. TCHAR* pBindings;
  892. // if pData is pointing to something, then we need to free it so that we don't leak
  893. if ( pData )
  894. {
  895. GlobalFree( pData );
  896. pData = NULL;
  897. }
  898. // allocate the space, if it fails, we fail
  899. // note that GPTR causes it to be initialized to zero
  900. pData = GlobalAlloc( GPTR, dwLength + 2 );
  901. if ( !pData )
  902. {
  903. iisDebugOut((LOG_TYPE_ERROR, _T("%s GlobalAlloc failed."),csNodeName));
  904. continue;
  905. }
  906. pBindings = (TCHAR*)pData;
  907. // now get the real data from the metabase
  908. f = cmdW3SVC.GetData( MD_SECURE_BINDINGS,
  909. &dwAttr,
  910. &dwUType,
  911. &dwDType,
  912. &dwLength,
  913. (PUCHAR)pBindings,
  914. dwLength,
  915. 0, // do not inherit
  916. IIS_MD_UT_SERVER,
  917. MULTISZ_METADATA,
  918. (PWCHAR)(LPCTSTR)csNodeName );
  919. // if we did not get the bindings, then this node doesn't have any security
  920. // options set on it. We can continue on to the next virtual server
  921. if ( FALSE == f )
  922. {
  923. continue;
  924. }
  925. // OK. We do have bindings. Now we get to parse them out and check them
  926. // against the binding strings that were passed in. Note: if a binding
  927. // matches, but has a host-header at the end, then it does not qualify
  928. // got the existing bindings, scan them now - pBindings will be pointing at the second end \0
  929. // when it is time to exit the loop.
  930. while ( *pBindings )
  931. {
  932. csBinding = pBindings;
  933. csBinding.TrimRight();
  934. // We are looking for a particular port which is stored in csPort.
  935. // if there is no csPort passed in then lets get out of here!
  936. if ( csPort.IsEmpty() )
  937. {
  938. break;
  939. }
  940. else
  941. {
  942. // if the Port is not in the binding then bail on this binding
  943. if ( csBinding.Find( csPort ) < 0 )
  944. {
  945. iisDebugOut((LOG_TYPE_TRACE, _T("%s:org=%s,findport=%s bail."),csNodeName,csBinding,csPort));
  946. goto NextBinding;
  947. }
  948. }
  949. // test if host headers are there by doing a reverse find for the last colon. Then
  950. // check if it is the last character. If it isn't, then there is a host-header and
  951. // we should go to a different binding
  952. if ( csBinding.ReverseFind(_T(':')) < (csBinding.GetLength()-1) )
  953. {
  954. iisDebugOut((LOG_TYPE_TRACE, _T("%s:bail2."),csNodeName));
  955. goto NextBinding;
  956. }
  957. // Well, this is a valid binding on a valid virtual server, we can now write out the key
  958. iisDebugOut((LOG_TYPE_TRACE, _T("%s:Write out the key!"),csNodeName));
  959. WriteKeyReference( cmdW3SVC, (PWCHAR)(LPCTSTR)csNodeName, pCert );
  960. // we can break to get out of the specific bindings loop
  961. break;
  962. NextBinding:
  963. // increment pBindings to the next string
  964. pBindings = _tcsninc( pBindings, _tcslen(pBindings))+1;
  965. }
  966. }
  967. // if pData is pointing to something, then we need to free it so that we don't leak
  968. if ( pData )
  969. {
  970. GlobalFree( pData );
  971. pData = NULL;
  972. }
  973. StoreKeyReference_Default_Exit:
  974. iisDebugOut_End(_T("StoreKeyReference_Default"), LOG_TYPE_TRACE);
  975. }
  976. #endif //_CHICAGO_