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.

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