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.

571 lines
16 KiB

  1. #include "stdafx.h"
  2. #include "KeyObjs.h"
  3. #include "CmnKey.h"
  4. #include "W3Key.h"
  5. #include "W3Serv.h"
  6. #include "resource.h"
  7. #include "kmlsa.h"
  8. // the service image index
  9. extern int g_iServiceImage;
  10. extern HINSTANCE g_hInstance;
  11. //--------------------------------------------------------
  12. CW3KeyService::CW3KeyService():
  13. m_pszwMachineName( NULL )
  14. {
  15. // set the icon id
  16. m_iImage = (WORD)g_iServiceImage;
  17. // load the service name
  18. m_szItemName.LoadString( IDS_SERV_NAME );
  19. }
  20. //--------------------------------------------------------
  21. CW3KeyService::~CW3KeyService()
  22. {
  23. // if the machine name has been cached, release it
  24. if ( m_pszwMachineName )
  25. {
  26. delete m_pszwMachineName;
  27. m_pszwMachineName = NULL;
  28. }
  29. }
  30. //--------------------------------------------------------
  31. void CW3KeyService::LoadKeys( CMachine* pMachine )
  32. {
  33. // specify the resources to use
  34. HINSTANCE hOldRes = AfxGetResourceHandle();
  35. AfxSetResourceHandle( g_hInstance );
  36. HANDLE hPolicy;
  37. DWORD err;
  38. // since we use the machine name several times, set it up only once
  39. if ( !m_pszwMachineName )
  40. {
  41. // get the normal name
  42. CString szName;
  43. pMachine->GetMachineName( szName );
  44. // allocate the cache for the machine name
  45. m_pszwMachineName = new WCHAR[MAX_PATH];
  46. if ( !m_pszwMachineName ) goto cleanup;
  47. // unicodize the name
  48. MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, szName, -1, m_pszwMachineName, MAX_PATH );
  49. }
  50. // attempt to open an LSA policy on the target machine
  51. hPolicy = HOpenLSAPolicy( m_pszwMachineName, &err );
  52. // if we did not open a policy, fail
  53. if ( !hPolicy ) goto cleanup;
  54. // load the keys that were previously saved by key manager
  55. FRestoreNormalKeys( hPolicy );
  56. // load any keys that were created by keyset - not keymanager
  57. FLoadKeySetKeys( hPolicy );
  58. // close the policy
  59. FCloseLSAPolicy( hPolicy, &err );
  60. // restore the resources
  61. cleanup:
  62. AfxSetResourceHandle( hOldRes );
  63. }
  64. //----------------------------------------------------------------
  65. CW3Key* CW3KeyService::PGetDefaultKey( void )
  66. {
  67. // get the first key
  68. CW3Key* pKey = GetFirstW3Key();
  69. // loop through the keys, looking for the default
  70. while( pKey )
  71. {
  72. // test the key
  73. if ( pKey->FIsDefault() )
  74. return pKey;
  75. // get the next key
  76. pKey = GetNextW3Key( pKey );
  77. }
  78. // we did not find the default key, return NULL
  79. return NULL;
  80. }
  81. //----------------------------------------------------------------
  82. // the plan to commit the machine takes place in several steps
  83. // First we write out the current keys to the secrets.
  84. // The keys are written out using a structured naming sequense.
  85. // namely, Key1, Key2, Key3, etc...
  86. // After writing out all the keys, any keys that are still in the
  87. // secrets but are not current keys (i.e. they were deleted) are
  88. // removed from the secrets.
  89. // Next, we build the mapping between the keys and the servers. This part
  90. // is basically what KeySet did.
  91. BOOL CW3KeyService::FCommitChangesNow( void )
  92. {
  93. HANDLE hPolicy;
  94. DWORD err;
  95. // if there is nothing to do, then do nothing
  96. if ( !m_fDirty )
  97. return TRUE;
  98. // this can take a few seconds, so set the hourglass cursor
  99. CWaitCursor waitcursor;
  100. // open a policy to the target machine
  101. hPolicy = HOpenLSAPolicy( m_pszwMachineName, &err );
  102. // make sure it worked
  103. if( !hPolicy )
  104. {
  105. WriteSecretMessageBox();
  106. return FALSE;
  107. }
  108. // commit the changes here
  109. if ( !DeleteAllW3Keys(hPolicy) )
  110. {
  111. FCloseLSAPolicy( hPolicy, &err );
  112. WriteSecretMessageBox();
  113. // even though we failed to delete all the old keys, write out the new
  114. // ones anyway.
  115. }
  116. // commit the changes here
  117. if ( !FWriteOutKeys(hPolicy) )
  118. {
  119. FCloseLSAPolicy( hPolicy, &err );
  120. WriteSecretMessageBox();
  121. return FALSE;
  122. }
  123. // record the new current number of keys in the registry
  124. // now if all the keys are deleted, the right number of
  125. // resources will be purged from the registry
  126. m_nNumKeysRead = GetChildCount();
  127. // close the policy
  128. FCloseLSAPolicy( hPolicy, &err );
  129. // clear the dirty flag
  130. SetDirty( FALSE );
  131. return TRUE;
  132. }
  133. //----------------------------------------------------------------
  134. void CW3KeyService::WriteSecretMessageBox( void )
  135. {
  136. CString szMessage;
  137. // get the message string
  138. szMessage.LoadString( IDS_COMMIT_ERROR );
  139. // tack on the name of the server
  140. szMessage += m_szItemName;
  141. // tack on some punctuation
  142. szMessage += _T(".");
  143. AfxMessageBox( szMessage );
  144. }
  145. //----------------------------------------------------------------
  146. // looks for keys that were installed by keyset, not key manager. These
  147. // keys only exist directly in w3 server form and are unnamed.
  148. BOOL CW3KeyService::FLoadKeySetKeys( HANDLE hPolicy )
  149. {
  150. PLSA_UNICODE_STRING pLSAData;
  151. DWORD err;
  152. BOOL fFoundKeySetKeys = FALSE;
  153. // get the W3 server links data from the secrets database
  154. pLSAData = FRetrieveLSASecret( hPolicy, KEYSET_LIST, &err );
  155. // if we get lucky, there won't be any keys to test
  156. if ( !pLSAData ) return TRUE;
  157. // allocate the name buffer
  158. PWCHAR pWName = (PWCHAR)GlobalAlloc( GPTR, (MAX_PATH+1) * sizeof(WCHAR) );
  159. ASSERT( pWName );
  160. if ( !pWName )
  161. {
  162. AfxThrowMemoryException();
  163. return FALSE;
  164. }
  165. // No such luck. Now we have to walk the list and delete all those secrets
  166. WCHAR* pszAddress = (WCHAR*)(pLSAData->Buffer);
  167. WCHAR* pchKeys;
  168. // loop the items in the list, deleting the associated items
  169. while( pchKeys = wcschr(pszAddress, L',') )
  170. {
  171. // ignore empty segments
  172. if ( *pszAddress != L',' )
  173. {
  174. *pchKeys = L'\0';
  175. // put the wide name into a cstring
  176. CString szTestAddress = pszAddress;
  177. // see if we need to check for the default key
  178. BOOL fCheckForDefault = (wcscmp(pszAddress, KEYSET_DEFAULT) == 0);
  179. // search the keys, looking for the one that matches this
  180. CW3Key* pKey = GetFirstW3Key();
  181. while( pKey )
  182. {
  183. // if it is the default key, check for that
  184. if ( fCheckForDefault )
  185. {
  186. if ( pKey->FIsDefault() )
  187. {
  188. // this is a keyman key
  189. goto incrementKeyList;
  190. }
  191. }
  192. else
  193. {
  194. // otherwise, check the actual ip address
  195. if ( pKey->m_szIPAddress == szTestAddress )
  196. {
  197. // this is a keyman key
  198. goto incrementKeyList;
  199. }
  200. }
  201. // get the next key
  202. pKey = GetNextW3Key( pKey );
  203. }
  204. // if we get here, then we have found a keyset key
  205. fFoundKeySetKeys = TRUE;
  206. // create a new key
  207. pKey = new CW3Key;
  208. // initialize it from the wide address of the key
  209. if ( pKey->FInitKey( hPolicy, pszAddress ) )
  210. {
  211. // add the key to the service
  212. pKey->FAddToTree( this );
  213. // mark the machine object as dirty
  214. SetDirty( TRUE );
  215. }
  216. }
  217. incrementKeyList:
  218. // increment the pointers
  219. pchKeys++;
  220. pszAddress = pchKeys;
  221. }
  222. // free the buffer for the names
  223. GlobalFree( (HANDLE)pWName );
  224. // delete the list key itself
  225. // free the list key itself
  226. if ( pLSAData )
  227. DisposeLSAData( pLSAData );
  228. // if we found any keyset keys, tell the user what to expect
  229. if ( fFoundKeySetKeys )
  230. AfxMessageBox( IDS_FOUND_KEYSET_KEYS, MB_OK|MB_ICONINFORMATION );
  231. return TRUE;
  232. }
  233. //----------------------------------------------------------------
  234. // similar to the routine "DeleteAll" in the KeySet utility
  235. BOOL CW3KeyService::DeleteAllW3Keys( HANDLE hPolicy )
  236. {
  237. DWORD err;
  238. PLSA_UNICODE_STRING pLSAData;
  239. // get the secret list of keys
  240. pLSAData = FRetrieveLSASecret( hPolicy, KEYSET_LIST, &err );
  241. // if we get lucky, there won't be any keys to get rid of
  242. if ( !pLSAData ) return TRUE;
  243. // allocate the name buffer
  244. PWCHAR pWName = (PWCHAR)GlobalAlloc( GPTR, (MAX_PATH+1) * sizeof(WCHAR) );
  245. ASSERT( pWName );
  246. if ( !pWName )
  247. {
  248. AfxThrowMemoryException();
  249. return FALSE;
  250. }
  251. // No such luck. Now we have to walk the list and delete all those secrets
  252. WCHAR* pszAddress = (WCHAR*)(pLSAData->Buffer);
  253. WCHAR* pchKeys;
  254. // loop the items in the list, deleting the associated items
  255. while( pchKeys = wcschr(pszAddress, L',') )
  256. {
  257. // ignore empty segments
  258. if ( *pszAddress != L',' )
  259. {
  260. *pchKeys = L'\0';
  261. // Nuke the secrets, one at a time
  262. swprintf( pWName, KEYSET_PUB_KEY, pszAddress );
  263. FStoreLSASecret( hPolicy, pWName, NULL, 0, &err );
  264. swprintf( pWName, KEYSET_PRIV_KEY, pszAddress );
  265. FStoreLSASecret( hPolicy, pWName, NULL, 0, &err );
  266. swprintf( pWName, KEYSET_PASSWORD, pszAddress );
  267. FStoreLSASecret( hPolicy, pWName, NULL, 0, &err );
  268. }
  269. // increment the pointers
  270. pchKeys++;
  271. pszAddress = pchKeys;
  272. }
  273. // delete the list key itself
  274. FStoreLSASecret( hPolicy, KEYSET_LIST, NULL, 0, &err );
  275. // free the buffer for the names
  276. GlobalFree( (HANDLE)pWName );
  277. // free the info we originally retrieved from the secret
  278. if ( pLSAData )
  279. DisposeLSAData( pLSAData );
  280. // return success
  281. return TRUE;
  282. }
  283. //----------------------------------------------------------------
  284. // utiltiy to append data to an existing handle, thus growing it
  285. BOOL CW3KeyService::FExpandoHandle( HANDLE* ph, PVOID pData, DWORD cbData )
  286. {
  287. HANDLE hNew;
  288. HANDLE hOld = *ph;
  289. ASSERT( ph && *ph && pData && cbData );
  290. if ( !ph || !*ph ) return FALSE;
  291. if ( !pData || !cbData ) return TRUE;
  292. // calculate the new size of the handle
  293. SIZE_T cbSizeOld = GlobalSize( *ph );
  294. SIZE_T cbSizeNew = cbSizeOld + cbData;
  295. // allocate a new handle at the new size
  296. hNew = GlobalAlloc( GHND, cbSizeNew );
  297. // if it didn't work, throw
  298. if ( !hNew )
  299. {
  300. AfxThrowMemoryException();
  301. return FALSE;
  302. }
  303. // lock down the handles and copy over the existing data
  304. PCHAR pNew = (PCHAR)GlobalLock( hNew );
  305. // only copy over the old data if there is some
  306. if ( cbSizeOld > 0 )
  307. {
  308. PCHAR pOld = (PCHAR)GlobalLock( hOld );
  309. CopyMemory( pNew, pOld, cbSizeOld );
  310. GlobalUnlock( hOld );
  311. }
  312. // advance the new pointer and copy in the new data
  313. pNew += cbSizeOld;
  314. CopyMemory( pNew, pData, cbData );
  315. // unlock the new handle
  316. GlobalUnlock( hNew );
  317. // it did work, so set the handle
  318. *ph = hNew;
  319. // finally, dispose of the old handle
  320. GlobalFree( hOld );
  321. // return success
  322. return TRUE;
  323. }
  324. //----------------------------------------------------------------
  325. BOOL CW3KeyService::FWriteOutKeys( HANDLE hPolicy )
  326. {
  327. WORD iKey;
  328. DWORD err;
  329. HANDLE hList = GlobalAlloc( GHND, 0 );
  330. LONG cch;
  331. BOOL fSomethingInList = FALSE;
  332. ASSERT( hPolicy );
  333. ASSERT( hList );
  334. if ( !hList )
  335. AfxThrowMemoryException();
  336. // get the buffer for the wide name
  337. PWCHAR pWName = (PWCHAR)GlobalAlloc( GPTR, (MAX_PATH+1) * sizeof(WCHAR) );
  338. // for each key in the machine, write its data out to the secrets
  339. iKey = 0;
  340. CW3Key* pKey = GetFirstW3Key();
  341. while( pKey )
  342. {
  343. // tell the key to store itself
  344. if ( !pKey->WriteKey(hPolicy, iKey, pWName) )
  345. return FALSE;
  346. // if this key has a link, add it to the w3 links list
  347. cch = wcslen( pWName );
  348. if ( cch )
  349. {
  350. wcscat( pWName, L"," );
  351. cch++;
  352. FExpandoHandle( &hList, pWName, cch * sizeof(WCHAR) ); // terminates later
  353. fSomethingInList = TRUE;
  354. }
  355. // get the next key
  356. pKey = GetNextW3Key( pKey );
  357. iKey++;
  358. }
  359. // save the contents of the list as a secret
  360. if ( fSomethingInList )
  361. {
  362. WORD word = 0;
  363. // terminate the list of named keys
  364. FExpandoHandle( &hList, &word, sizeof(WORD) );
  365. ASSERT( GlobalSize(hList) < 0xFFFF );
  366. PVOID p = GlobalLock(hList);
  367. FStoreLSASecret( hPolicy, KEYSET_LIST, p, (WORD)GlobalSize(hList), &err );
  368. GlobalUnlock(hList);
  369. }
  370. // free the handle for the list
  371. GlobalFree( hList );
  372. hList = NULL;
  373. // once we get here we have already written out all our keys. However, the case could exist where
  374. // we now have fewer keys than we started with. This means that there are keys in the secrets database
  375. // that are no longer needed. If this is the case, get rid of them
  376. WORD numKeys = GetChildCount();
  377. if ( numKeys < m_nNumKeysRead )
  378. {
  379. PCHAR pName = (PCHAR)GlobalAlloc( GPTR, MAX_PATH+1 );
  380. // make sure we got the name buffers
  381. ASSERT( pName && pWName );
  382. if ( pName && pWName )
  383. for ( iKey = numKeys; iKey < m_nNumKeysRead; iKey++ )
  384. {
  385. // prepare the name of the secret. - Base name plus the number+1
  386. sprintf( pName, "%s%d", KEY_NAME_BASE, iKey+1 );
  387. // unicodize the name
  388. MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, pName, -1, pWName, MAX_PATH+1 );
  389. // remove the secret
  390. FStoreLSASecret( hPolicy, pWName, NULL, 0, &err );
  391. }
  392. // free the string buffers
  393. GlobalFree( (HANDLE)pName );
  394. }
  395. // free the string buffers
  396. GlobalFree( (HANDLE)pWName );
  397. // return success
  398. return TRUE;
  399. }
  400. //----------------------------------------------------------------
  401. BOOL CW3KeyService::FRestoreNormalKeys( HANDLE hPolicy )
  402. {
  403. DWORD iKey = 0;
  404. PCHAR pName = (PCHAR)GlobalAlloc( GPTR, MAX_PATH+1 );
  405. PWCHAR pWName = (PWCHAR)GlobalAlloc( GPTR, (MAX_PATH+1) * sizeof(WCHAR) );
  406. PLSA_UNICODE_STRING pLSAData;
  407. DWORD err;
  408. // make sure we got the name buffers
  409. ASSERT( pName && pWName );
  410. if ( !pName || !pWName ) return FALSE;
  411. // clear the number of keys read (we haven't read any yet!)
  412. m_nNumKeysRead = 0;
  413. // load keys until we have loaded them all
  414. while(TRUE)
  415. {
  416. // increment the key counter
  417. iKey++;
  418. // build the key secret name
  419. sprintf( pName, "%s%d", KEY_NAME_BASE, iKey );
  420. // unicodize the name
  421. MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, pName, -1, pWName, MAX_PATH+1 );
  422. // get the secret
  423. pLSAData = FRetrieveLSASecret( hPolicy, pWName, &err );
  424. // if we didn't get anything, leave the loop
  425. if ( !pLSAData )
  426. break;
  427. // there is a key here, so count it
  428. m_nNumKeysRead++;
  429. // ah, but we did get something. Make a new key and add it to the key list
  430. CW3Key* pKey = new CW3Key;
  431. if ( pKey->FInitKey(pLSAData->Buffer, pLSAData->Length) )
  432. {
  433. pKey->FAddToTree( this );
  434. }
  435. else
  436. {
  437. // failed to init key
  438. delete pKey;
  439. }
  440. // dispose of the lsa buffer now that we have loaded from it
  441. if ( pLSAData )
  442. DisposeLSAData( pLSAData );
  443. pLSAData = NULL;
  444. }
  445. // free the buffers
  446. GlobalFree( (HANDLE)pName );
  447. GlobalFree( (HANDLE)pWName );
  448. if ( pLSAData )
  449. DisposeLSAData( pLSAData );
  450. return TRUE;
  451. }
  452. //-------------------------------------------------------------
  453. void DisposeLSAData( PVOID pData )
  454. {
  455. PLSA_UNICODE_STRING pDataLSA = (PLSA_UNICODE_STRING)pData;
  456. if ( !pDataLSA || !pDataLSA->Buffer ) return;
  457. GlobalFree(pDataLSA);
  458. }