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.

836 lines
19 KiB

  1. /********************************************************************/
  2. /** Copyright(c) 1995 Microsoft Corporation. **/
  3. /********************************************************************/
  4. //***
  5. //
  6. // Filename: creds.c
  7. //
  8. // Description: Routines for storing and retrieving user Lsa secret
  9. // dial parameters.
  10. //
  11. //
  12. // History: 11/02/95 Anthony Discolo created
  13. // May 11,1995 NarenG modified for router.
  14. //
  15. #include <nt.h>
  16. #include <ntrtl.h>
  17. #include <nturtl.h>
  18. #include <ntlsa.h>
  19. #include <ntmsv1_0.h>
  20. #include <llinfo.h>
  21. #include <rasman.h>
  22. #include <raserror.h>
  23. #include <mprerror.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #define MPR_CREDENTIALS_KEY TEXT("MprCredentials%d")
  27. #define MAX_REGISTRY_VALUE_LENGTH ((64*1024) - 1)
  28. typedef struct _MPRPARAMSENTRY
  29. {
  30. LIST_ENTRY ListEntry;
  31. WCHAR szPhoneBookEntryName[MAX_INTERFACE_NAME_LEN + 1];
  32. WCHAR szUserName[UNLEN + 1];
  33. WCHAR szPassword[PWLEN + 1];
  34. WCHAR szDomain[DNLEN + 1];
  35. } MPRPARAMSENTRY, *PMPRPARAMSENTRY;
  36. //**
  37. //
  38. // Call: ReadDialParamsBlob
  39. //
  40. // Returns: NO_ERROR - Success
  41. // Non-zero returns - Failure
  42. //
  43. // Description:
  44. //
  45. DWORD
  46. ReadDialParamsBlob(
  47. IN LPWSTR lpwsServer,
  48. OUT PVOID *ppvData,
  49. OUT LPDWORD lpdwSize
  50. )
  51. {
  52. NTSTATUS status;
  53. DWORD dwRetCode = NO_ERROR;
  54. DWORD dwIndex;
  55. DWORD dwSize = 0;
  56. PVOID pvData = NULL;
  57. PVOID pvNewData = NULL;
  58. UNICODE_STRING unicodeKey;
  59. UNICODE_STRING unicodeServer;
  60. PUNICODE_STRING punicodeValue = NULL;
  61. OBJECT_ATTRIBUTES objectAttributes;
  62. LSA_HANDLE hPolicy;
  63. WCHAR wchKey[sizeof(MPR_CREDENTIALS_KEY) + 10 ];
  64. //
  65. // Initialize return value.
  66. //
  67. *ppvData = NULL;
  68. *lpdwSize = 0;
  69. //
  70. // Open the LSA secret space for reading.
  71. //
  72. InitializeObjectAttributes( &objectAttributes, NULL, 0L, NULL, NULL );
  73. RtlInitUnicodeString( &unicodeServer, lpwsServer );
  74. status = LsaOpenPolicy( &unicodeServer,
  75. &objectAttributes,
  76. POLICY_READ,
  77. &hPolicy );
  78. if ( status != STATUS_SUCCESS )
  79. {
  80. return( LsaNtStatusToWinError( status ) );
  81. }
  82. for( dwIndex = 0; TRUE; dwIndex++ )
  83. {
  84. //
  85. // Format the key string.
  86. //
  87. wsprintf( wchKey, MPR_CREDENTIALS_KEY, dwIndex );
  88. RtlInitUnicodeString( &unicodeKey, wchKey );
  89. //
  90. // Get the value.
  91. //
  92. status = LsaRetrievePrivateData( hPolicy, &unicodeKey, &punicodeValue );
  93. if ( status != STATUS_SUCCESS )
  94. {
  95. dwRetCode = LsaNtStatusToWinError( status );
  96. if ( dwRetCode == ERROR_FILE_NOT_FOUND )
  97. {
  98. dwRetCode = NO_ERROR;
  99. }
  100. break;
  101. }
  102. if ( punicodeValue == NULL )
  103. {
  104. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  105. break;
  106. }
  107. //
  108. // Concatenate the strings.
  109. //
  110. pvNewData = LocalAlloc( LPTR, dwSize + punicodeValue->Length );
  111. if ( pvNewData == NULL )
  112. {
  113. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  114. break;
  115. }
  116. if ( pvData != NULL )
  117. {
  118. RtlCopyMemory( pvNewData, pvData, dwSize );
  119. ZeroMemory( pvData, dwSize );
  120. LocalFree( pvData );
  121. pvData = NULL;
  122. }
  123. RtlCopyMemory( (PBYTE)pvNewData + dwSize,
  124. punicodeValue->Buffer,
  125. punicodeValue->Length );
  126. pvData = pvNewData;
  127. dwSize += punicodeValue->Length;
  128. SecureZeroMemory(punicodeValue->Buffer, punicodeValue->Length);
  129. LsaFreeMemory( punicodeValue );
  130. punicodeValue = NULL;
  131. }
  132. LsaClose( hPolicy );
  133. if ( dwRetCode != NO_ERROR )
  134. {
  135. if ( pvData != NULL )
  136. {
  137. ZeroMemory( pvData, dwSize );
  138. LocalFree( pvData );
  139. }
  140. pvData = NULL;
  141. dwSize = 0;
  142. }
  143. if ( punicodeValue != NULL )
  144. {
  145. LsaFreeMemory( punicodeValue );
  146. }
  147. *ppvData = pvData;
  148. *lpdwSize = dwSize;
  149. return( dwRetCode );
  150. }
  151. //**
  152. //
  153. // Call: WriteDialParamsBlob
  154. //
  155. // Returns: NO_ERROR - Success
  156. // Non-zero returns - Failure
  157. //
  158. // Description:
  159. //
  160. DWORD
  161. WriteDialParamsBlob(
  162. IN LPWSTR lpwsServer,
  163. IN PVOID pvData,
  164. IN DWORD dwcbData
  165. )
  166. {
  167. NTSTATUS status;
  168. DWORD dwIndex = 0;
  169. DWORD dwRetCode = NO_ERROR;
  170. DWORD dwcb = 0;
  171. UNICODE_STRING unicodeKey, unicodeValue;
  172. UNICODE_STRING unicodeServer;
  173. OBJECT_ATTRIBUTES objectAttributes;
  174. LSA_HANDLE hPolicy;
  175. WCHAR wchKey[sizeof(MPR_CREDENTIALS_KEY) + 10 ];
  176. //
  177. // Open the LSA secret space for writing.
  178. //
  179. InitializeObjectAttributes( &objectAttributes, NULL, 0L, NULL, NULL );
  180. RtlInitUnicodeString( &unicodeServer, lpwsServer );
  181. status = LsaOpenPolicy( &unicodeServer,
  182. &objectAttributes,
  183. POLICY_WRITE,
  184. &hPolicy);
  185. if (status != STATUS_SUCCESS)
  186. {
  187. return LsaNtStatusToWinError(status);
  188. }
  189. while( dwcbData )
  190. {
  191. //
  192. // Format the key string.
  193. //
  194. wsprintf( wchKey, MPR_CREDENTIALS_KEY, dwIndex++ );
  195. RtlInitUnicodeString( &unicodeKey, wchKey );
  196. //
  197. // Write some of the key.
  198. //
  199. dwcb = ( dwcbData > MAX_REGISTRY_VALUE_LENGTH )
  200. ? MAX_REGISTRY_VALUE_LENGTH
  201. : dwcbData;
  202. unicodeValue.Length = unicodeValue.MaximumLength = (USHORT)dwcb;
  203. unicodeValue.Buffer = pvData;
  204. status = LsaStorePrivateData( hPolicy, &unicodeKey, &unicodeValue );
  205. if ( status != STATUS_SUCCESS )
  206. {
  207. dwRetCode = LsaNtStatusToWinError(status);
  208. break;
  209. }
  210. //
  211. // Move the pointer to the unwritten part
  212. // of the value.
  213. //
  214. pvData = (PBYTE)pvData + dwcb;
  215. dwcbData -= dwcb;
  216. }
  217. if ( dwRetCode != NO_ERROR )
  218. {
  219. LsaClose( hPolicy );
  220. return( dwRetCode );
  221. }
  222. //
  223. // Delete any extra keys.
  224. //
  225. for (;;)
  226. {
  227. //
  228. // Format the key string.
  229. //
  230. wsprintf( wchKey, MPR_CREDENTIALS_KEY, dwIndex++ );
  231. RtlInitUnicodeString( &unicodeKey, wchKey );
  232. //
  233. // Delete the key.
  234. //
  235. status = LsaStorePrivateData( hPolicy, &unicodeKey, NULL );
  236. if ( status != STATUS_SUCCESS )
  237. {
  238. break;
  239. }
  240. }
  241. LsaClose( hPolicy );
  242. return( NO_ERROR );
  243. }
  244. //**
  245. //
  246. // Call: DialParamsBlobToList
  247. //
  248. // Returns: NO_ERROR - Success
  249. // Non-zero returns - Failure
  250. //
  251. // Description: Take a string read from the user's registry key and produce
  252. // a list of MPRPARAMSENTRY structures. If one of the structures
  253. // has the same dwUID field as the dwUID passed in, then this
  254. // function returns a pointer to this structure.
  255. //
  256. // This string encodes the data for multiple MPRPARAMSENTRY
  257. // structures. The format of an encoded MPRPARAMSENTRY is as
  258. // follows:
  259. //
  260. // <szPhoneBookEntryName>\0<szUserName>\0<szPassword>\0<szDomain>\0
  261. //
  262. PMPRPARAMSENTRY
  263. DialParamsBlobToList(
  264. IN PVOID pvData,
  265. IN LPWSTR lpwsPhoneBookEntryName,
  266. OUT PLIST_ENTRY pHead
  267. )
  268. {
  269. PWCHAR p;
  270. PMPRPARAMSENTRY pParams, pFoundParams;
  271. p = (PWCHAR)pvData;
  272. pFoundParams = NULL;
  273. for (;;)
  274. {
  275. pParams = LocalAlloc(LPTR, sizeof (MPRPARAMSENTRY));
  276. if ( pParams == NULL )
  277. {
  278. break;
  279. }
  280. wcscpy( pParams->szPhoneBookEntryName, p );
  281. if (_wcsicmp(pParams->szPhoneBookEntryName,lpwsPhoneBookEntryName) == 0)
  282. {
  283. pFoundParams = pParams;
  284. }
  285. while (*p) p++; p++;
  286. wcscpy(pParams->szUserName, p);
  287. while (*p) p++; p++;
  288. wcscpy(pParams->szPassword, p);
  289. while (*p) p++; p++;
  290. wcscpy(pParams->szDomain, p);
  291. while (*p) p++; p++;
  292. InsertTailList(pHead, &pParams->ListEntry);
  293. if (*p == L'\0') break;
  294. }
  295. return( pFoundParams );
  296. }
  297. //**
  298. //
  299. // Call: DialParamsListToBlob
  300. //
  301. // Returns: NO_ERROR - Success
  302. // Non-zero returns - Failure
  303. //
  304. // Description:
  305. //
  306. PVOID
  307. DialParamsListToBlob(
  308. IN PLIST_ENTRY pHead,
  309. OUT LPDWORD lpcb
  310. )
  311. {
  312. DWORD dwcb, dwSize;
  313. PVOID pvData;
  314. PWCHAR p;
  315. PLIST_ENTRY pEntry;
  316. PMPRPARAMSENTRY pParams;
  317. //
  318. // Estimate a buffer size large enough to hold the new entry.
  319. //
  320. dwSize = *lpcb + sizeof (MPRPARAMSENTRY) + 32;
  321. if ( ( pvData = LocalAlloc(LPTR, dwSize) ) == NULL )
  322. {
  323. return( NULL );
  324. }
  325. //
  326. // Enumerate the list and convert each entry back to a string.
  327. //
  328. dwSize = 0;
  329. p = (PWCHAR)pvData;
  330. for (pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink )
  331. {
  332. pParams = CONTAINING_RECORD(pEntry, MPRPARAMSENTRY, ListEntry);
  333. wcscpy(p, pParams->szPhoneBookEntryName);
  334. dwcb = wcslen(pParams->szPhoneBookEntryName) + 1;
  335. p += dwcb; dwSize += dwcb;
  336. wcscpy(p, pParams->szUserName);
  337. dwcb = wcslen(pParams->szUserName) + 1;
  338. p += dwcb; dwSize += dwcb;
  339. wcscpy(p, pParams->szPassword);
  340. dwcb = wcslen(pParams->szPassword) + 1;
  341. p += dwcb; dwSize += dwcb;
  342. wcscpy(p, pParams->szDomain);
  343. dwcb = wcslen(pParams->szDomain) + 1;
  344. p += dwcb; dwSize += dwcb;
  345. }
  346. *p = L'\0';
  347. dwSize++;
  348. dwSize *= sizeof (WCHAR);
  349. //
  350. // Set the exact length here.
  351. //
  352. *lpcb = dwSize;
  353. return( pvData );
  354. }
  355. //**
  356. //
  357. // Call: FreeParamsList
  358. //
  359. // Returns: NO_ERROR - Success
  360. // Non-zero returns - Failure
  361. //
  362. // Description: Will free the list of structures.
  363. //
  364. VOID
  365. FreeParamsList(
  366. IN PLIST_ENTRY pHead
  367. )
  368. {
  369. PLIST_ENTRY pEntry;
  370. PMPRPARAMSENTRY pParams;
  371. while( !IsListEmpty(pHead) )
  372. {
  373. pEntry = RemoveHeadList(pHead);
  374. pParams = CONTAINING_RECORD(pEntry, MPRPARAMSENTRY, ListEntry);
  375. SecureZeroMemory( pParams, sizeof( MPRPARAMSENTRY ) );
  376. LocalFree(pParams);
  377. }
  378. }
  379. //**
  380. //
  381. // Call: RemoveCredentials
  382. //
  383. // Returns: NO_ERROR - Success
  384. // Non-zero returns - Failure
  385. //
  386. // Description:
  387. //
  388. DWORD
  389. RemoveCredentials(
  390. IN LPWSTR lpwsInterfaceName,
  391. IN LPVOID pvData,
  392. IN OUT LPDWORD lpdwSize
  393. )
  394. {
  395. PWCHAR pWalker = (PWCHAR)pvData;
  396. DWORD dwIndex;
  397. //
  398. // There is no list to remove from.
  399. //
  400. if ( pvData == NULL )
  401. {
  402. return( ERROR_NO_SUCH_INTERFACE );
  403. }
  404. for (;;)
  405. {
  406. //
  407. // If we found the interface we want to remove, we jump past it
  408. //
  409. if ( _wcsicmp( (LPWSTR)pWalker, lpwsInterfaceName ) == 0 )
  410. {
  411. PWCHAR pInterface = pWalker;
  412. DWORD dwEntrySize = 0;
  413. //
  414. // Jump past the 4 fields.
  415. //
  416. for ( dwIndex = 0; dwIndex < 4; dwIndex++ )
  417. {
  418. while (*pWalker) pWalker++, dwEntrySize++;
  419. pWalker++, dwEntrySize++;
  420. }
  421. //
  422. // If this was the last entry in the list
  423. //
  424. if (*pWalker == L'\0')
  425. {
  426. ZeroMemory( pInterface, dwEntrySize );
  427. }
  428. else
  429. {
  430. CopyMemory( pInterface,
  431. pWalker,
  432. *lpdwSize - ( (PBYTE)pWalker - (PBYTE)pvData ) );
  433. }
  434. *lpdwSize -= dwEntrySize;
  435. return( NO_ERROR );
  436. }
  437. else
  438. {
  439. //
  440. // Not found so skip over this entry
  441. //
  442. for ( dwIndex = 0; dwIndex < 4; dwIndex++ )
  443. {
  444. while (*pWalker) pWalker++; pWalker++;
  445. }
  446. }
  447. if (*pWalker == L'\0') break;
  448. }
  449. return( ERROR_NO_SUCH_INTERFACE );
  450. }
  451. //**
  452. //
  453. // Call: MprAdminInterfaceSetCredentials
  454. //
  455. // Returns: NO_ERROR - success
  456. // ERROR_INVALID_PARAMETER
  457. //
  458. // Description:
  459. //
  460. DWORD APIENTRY
  461. MprAdminInterfaceSetCredentialsInternal(
  462. IN LPWSTR lpwsServer OPTIONAL,
  463. IN LPWSTR lpwsInterfaceName,
  464. IN LPWSTR lpwsUserName OPTIONAL,
  465. IN LPWSTR lpwsDomainName OPTIONAL,
  466. IN LPWSTR lpwsPassword OPTIONAL
  467. )
  468. {
  469. DWORD dwRetCode;
  470. DWORD dwSize;
  471. PVOID pvData;
  472. LIST_ENTRY paramList;
  473. PMPRPARAMSENTRY pParams = NULL;
  474. if ( lpwsInterfaceName == NULL )
  475. {
  476. return( ERROR_INVALID_PARAMETER );
  477. }
  478. if ( wcslen( lpwsInterfaceName ) > MAX_INTERFACE_NAME_LEN )
  479. {
  480. return( ERROR_INVALID_PARAMETER );
  481. }
  482. if ( lpwsUserName != NULL )
  483. {
  484. if ( wcslen( lpwsUserName ) > UNLEN )
  485. {
  486. return( ERROR_INVALID_PARAMETER );
  487. }
  488. }
  489. if ( lpwsPassword != NULL )
  490. {
  491. if ( wcslen( lpwsPassword ) > PWLEN )
  492. {
  493. return( ERROR_INVALID_PARAMETER );
  494. }
  495. }
  496. if ( lpwsDomainName != NULL )
  497. {
  498. if ( wcslen( lpwsDomainName ) > DNLEN )
  499. {
  500. return( ERROR_INVALID_PARAMETER );
  501. }
  502. }
  503. //
  504. // Read the existing dial params string from the registry.
  505. //
  506. dwRetCode = ReadDialParamsBlob( lpwsServer, &pvData, &dwSize );
  507. if ( dwRetCode != NO_ERROR )
  508. {
  509. return( dwRetCode );
  510. }
  511. //
  512. // If everything was NULL, we want to delete credentials for this interface
  513. //
  514. if ( ( lpwsUserName == NULL ) &&
  515. ( lpwsDomainName == NULL ) &&
  516. ( lpwsPassword == NULL ) )
  517. {
  518. dwRetCode = RemoveCredentials( lpwsInterfaceName, pvData, &dwSize );
  519. if ( dwRetCode != NO_ERROR )
  520. {
  521. ZeroMemory ( pvData, dwSize );
  522. LocalFree( pvData );
  523. return( dwRetCode );
  524. }
  525. }
  526. else
  527. {
  528. //
  529. // Parse the string into a list, and search for the phonebook entry.
  530. //
  531. InitializeListHead( &paramList );
  532. if ( pvData != NULL )
  533. {
  534. pParams = DialParamsBlobToList(pvData,lpwsInterfaceName,&paramList);
  535. //
  536. // We're done with pvData, so free it.
  537. //
  538. ZeroMemory ( pvData, dwSize );
  539. LocalFree( pvData );
  540. pvData = NULL;
  541. }
  542. //
  543. // If there is no existing information for this entry, create a new one.
  544. //
  545. if ( pParams == NULL )
  546. {
  547. pParams = LocalAlloc(LPTR, sizeof (MPRPARAMSENTRY) );
  548. if (pParams == NULL)
  549. {
  550. FreeParamsList( &paramList );
  551. return( ERROR_NOT_ENOUGH_MEMORY );
  552. }
  553. InsertTailList( &paramList, &pParams->ListEntry );
  554. }
  555. //
  556. // Set the new uid for the entry.
  557. //
  558. wcscpy( pParams->szPhoneBookEntryName, lpwsInterfaceName );
  559. if ( lpwsUserName != NULL )
  560. {
  561. wcscpy( pParams->szUserName, lpwsUserName );
  562. }
  563. if ( lpwsPassword != NULL )
  564. {
  565. wcscpy( pParams->szPassword, lpwsPassword );
  566. }
  567. if ( lpwsDomainName != NULL )
  568. {
  569. wcscpy( pParams->szDomain, lpwsDomainName );
  570. }
  571. //
  572. // Convert the new list back to a string, so we can store it back into
  573. // the registry.
  574. //
  575. pvData = DialParamsListToBlob( &paramList, &dwSize );
  576. FreeParamsList( &paramList );
  577. if ( pvData == NULL )
  578. {
  579. return( ERROR_NOT_ENOUGH_MEMORY );
  580. }
  581. }
  582. //
  583. // Write it back to the registry.
  584. //
  585. dwRetCode = WriteDialParamsBlob( lpwsServer, pvData, dwSize );
  586. if ( pvData != NULL )
  587. {
  588. SecureZeroMemory( pvData, dwSize );
  589. LocalFree( pvData );
  590. }
  591. return( dwRetCode );
  592. }
  593. //**
  594. //
  595. // Call: MprAdminInterfaceGetCredentials
  596. //
  597. // Returns: NO_ERROR - success
  598. // ERROR_INVALID_PARAMETER
  599. //
  600. // Description:
  601. //
  602. DWORD APIENTRY
  603. MprAdminInterfaceGetCredentialsInternal(
  604. IN LPWSTR lpwsServer OPTIONAL,
  605. IN LPWSTR lpwsInterfaceName,
  606. IN LPWSTR lpwsUserName OPTIONAL,
  607. IN LPWSTR lpwsPassword OPTIONAL,
  608. IN LPWSTR lpwsDomainName OPTIONAL
  609. )
  610. {
  611. DWORD dwRetCode;
  612. DWORD dwSize;
  613. PVOID pvData;
  614. LIST_ENTRY paramList;
  615. PMPRPARAMSENTRY pParams = NULL;
  616. if ( lpwsInterfaceName == NULL )
  617. {
  618. return( ERROR_INVALID_PARAMETER );
  619. }
  620. if ( ( lpwsUserName == NULL ) &&
  621. ( lpwsDomainName == NULL ) &&
  622. ( lpwsPassword == NULL ) )
  623. {
  624. return( ERROR_INVALID_PARAMETER );
  625. }
  626. //
  627. // Read the existing dial params string from the registry.
  628. //
  629. dwRetCode = ReadDialParamsBlob( lpwsServer, &pvData, &dwSize );
  630. if ( dwRetCode != NO_ERROR )
  631. {
  632. return( dwRetCode );
  633. }
  634. //
  635. // Parse the string into a list, and search for the lpwsInterfaceName entry.
  636. //
  637. InitializeListHead( &paramList );
  638. if ( pvData != NULL )
  639. {
  640. pParams = DialParamsBlobToList( pvData, lpwsInterfaceName, &paramList );
  641. //
  642. // We're done with pvData, so free it.
  643. //
  644. ZeroMemory( pvData, dwSize );
  645. LocalFree( pvData );
  646. }
  647. //
  648. // If the entry doesn't have any saved parameters, then return.
  649. //
  650. if ( pParams == NULL )
  651. {
  652. FreeParamsList( &paramList );
  653. return( ERROR_CANNOT_FIND_PHONEBOOK_ENTRY );
  654. }
  655. //
  656. // Otherwise, copy the fields to the caller's buffer.
  657. //
  658. if ( lpwsUserName != NULL )
  659. {
  660. wcscpy( lpwsUserName, pParams->szUserName );
  661. }
  662. if ( lpwsPassword != NULL )
  663. {
  664. wcscpy( lpwsPassword, pParams->szPassword );
  665. }
  666. if ( lpwsDomainName != NULL )
  667. {
  668. wcscpy( lpwsDomainName, pParams->szDomain );
  669. }
  670. FreeParamsList( &paramList );
  671. return( NO_ERROR );
  672. }