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.

2344 lines
62 KiB

  1. /********************************************************************/
  2. /** Copyright(c) 1989 Microsoft Corporation. **/
  3. /********************************************************************/
  4. //***
  5. //
  6. // Filename: srvrhlpr.c
  7. //
  8. // Description: This module will contain code to process specific security
  9. // information requests by the server. This is done because
  10. // the api's required to obtain this information cannot be
  11. // called from kernel mode. The following functionality is
  12. // supported:
  13. //
  14. // 1) Name to Sid Lookup.
  15. // 2) Sid to Name lookup.
  16. // 3) Enumerate Posix offsets of all domains.
  17. // 4) Change password.
  18. // 5) Log an event.
  19. //
  20. // History: August 18,1992. NarenG Created original version.
  21. //
  22. #include <afpsvcp.h>
  23. #include <lm.h>
  24. #include <logonmsv.h> // prototype of I_NetGetDCList
  25. #include <seposix.h>
  26. #include <dsgetdc.h>
  27. static PPOLICY_ACCOUNT_DOMAIN_INFO pAccountDomainInfo = NULL;
  28. static PPOLICY_PRIMARY_DOMAIN_INFO pPrimaryDomainInfo = NULL;
  29. static HANDLE hmutexThreadCount = NULL;
  30. NTSTATUS
  31. AfpNameToSid(
  32. IN LSA_HANDLE hLsa,
  33. IN PAFP_FSD_CMD_PKT pAfpFsdCmd,
  34. OUT PAFP_FSD_CMD_PKT *ppAfpFsdCmdResponse,
  35. OUT LPDWORD pcbResponse
  36. );
  37. NTSTATUS
  38. AfpSidToName(
  39. IN LSA_HANDLE hLsa,
  40. IN PPOLICY_ACCOUNT_DOMAIN_INFO pAccountDomainInfo,
  41. IN PPOLICY_PRIMARY_DOMAIN_INFO pPrimaryDomainInfo,
  42. IN PAFP_FSD_CMD_PKT pAfpFsdCmd,
  43. OUT PAFP_FSD_CMD_PKT *ppAfpFsdCmdResponse,
  44. OUT LPDWORD pcbResponse
  45. );
  46. NTSTATUS
  47. AfpChangePassword(
  48. IN LSA_HANDLE hLsa,
  49. IN PPOLICY_ACCOUNT_DOMAIN_INFO pAccountDomainInfo,
  50. IN PPOLICY_PRIMARY_DOMAIN_INFO pPrimaryDomainInfo,
  51. IN PAFP_FSD_CMD_PKT pAfpFsdCmd,
  52. OUT PAFP_FSD_CMD_PKT *ppAfpFsdCmdResponse,
  53. OUT LPDWORD pcbResponse
  54. );
  55. NTSTATUS
  56. AfpChangePasswordOnDomain(
  57. IN PAFP_PASSWORD_DESC pPassword,
  58. IN PUNICODE_STRING pDomainName,
  59. IN PSID pDomainSid
  60. );
  61. NTSTATUS
  62. AfpCreateWellknownSids(
  63. OUT AFP_SID_OFFSET pWellKnownSids[]
  64. );
  65. NTSTATUS
  66. AfpInsertSidOffset(
  67. IN PAFP_SID_OFFSET pSidOffset,
  68. IN LPBYTE pbVariableData,
  69. IN PSID pSid,
  70. IN DWORD Offset,
  71. IN AFP_SID_TYPE SidType
  72. );
  73. DWORD
  74. AfpGetDomainInfo(
  75. IN LSA_HANDLE hLsa,
  76. IN OUT PLSA_HANDLE phLsaController,
  77. IN OUT PPOLICY_ACCOUNT_DOMAIN_INFO* ppAccountDomainInfo,
  78. IN OUT PPOLICY_PRIMARY_DOMAIN_INFO* ppPrimaryDomainInfo
  79. );
  80. DWORD
  81. AfpIOCTLDomainOffsets(
  82. IN LSA_HANDLE hLsa,
  83. IN PPOLICY_ACCOUNT_DOMAIN_INFO pAccountDomainInfo,
  84. IN PPOLICY_PRIMARY_DOMAIN_INFO pPrimaryDomainInfo
  85. );
  86. DWORD
  87. AfpOpenLsa(
  88. IN PUNICODE_STRING pSystem OPTIONAL,
  89. IN OUT PLSA_HANDLE phLsa
  90. );
  91. NTSTATUS
  92. AfpChangePwdArapStyle(
  93. IN PAFP_PASSWORD_DESC pPassword,
  94. IN PUNICODE_STRING pDomainName,
  95. IN PSID pDomainSid
  96. );
  97. //**
  98. //
  99. // Call: AfpServerHelper
  100. //
  101. // Returns: NO_ERROR
  102. //
  103. // Description: This is the main function for each helper thread. If sits
  104. // in a loop processing commands from the server. It is terminated
  105. // by command from the server.
  106. //
  107. DWORD
  108. AfpServerHelper(
  109. IN LPVOID fFirstThread
  110. )
  111. {
  112. NTSTATUS ntStatus;
  113. DWORD dwRetCode;
  114. PAFP_FSD_CMD_PKT pAfpFsdCmdResponse;
  115. AFP_FSD_CMD_HEADER AfpCmdHeader;
  116. PAFP_FSD_CMD_PKT pAfpFsdCmd;
  117. PBYTE pOutputBuffer;
  118. DWORD cbOutputBuffer;
  119. PBYTE pInputBuffer;
  120. DWORD cbInputBuffer;
  121. IO_STATUS_BLOCK IoStatus;
  122. BYTE OutputBuffer[MAX_FSD_CMD_SIZE];
  123. HANDLE hFSD = NULL;
  124. LSA_HANDLE hLsa = NULL;
  125. BOOLEAN fFirstLoop=TRUE;
  126. // Open the AFP Server FSD and obtain a handle to it
  127. //
  128. if ( ( dwRetCode = AfpFSDOpen( &hFSD ) ) != NO_ERROR ) {
  129. AfpGlobals.dwSrvrHlprCode = dwRetCode;
  130. AfpLogEvent( AFPLOG_OPEN_FSD, 0, NULL, dwRetCode, EVENTLOG_ERROR_TYPE );
  131. SetEvent( AfpGlobals.heventSrvrHlprThread );
  132. return( dwRetCode );
  133. }
  134. // Open the Local LSA
  135. //
  136. if ( ( dwRetCode = AfpOpenLsa( NULL, &hLsa ) ) != NO_ERROR ) {
  137. AfpFSDClose( hFSD );
  138. AfpGlobals.dwSrvrHlprCode = dwRetCode;
  139. AfpLogEvent( AFPLOG_OPEN_LSA, 0, NULL, dwRetCode, EVENTLOG_ERROR_TYPE );
  140. SetEvent( AfpGlobals.heventSrvrHlprThread );
  141. return( dwRetCode );
  142. }
  143. // If this is the first server helper thread then enumerate and
  144. // IOCTL down the list of domains and their offsets.
  145. //
  146. if ( (BOOL)(ULONG_PTR)fFirstThread )
  147. {
  148. LSA_HANDLE hLsaController = NULL;
  149. //
  150. // Create the event object for mutual exclusion around the thread
  151. // count
  152. //
  153. if ( (hmutexThreadCount = CreateMutex( NULL, FALSE, NULL ) ) == NULL)
  154. {
  155. AFP_PRINT( ( "SFMSVC: CreateMutex failed\n"));
  156. return( GetLastError() );
  157. }
  158. while (1)
  159. {
  160. // Get the account, primary and all trusted domain info
  161. //
  162. dwRetCode = AfpGetDomainInfo( hLsa,
  163. &hLsaController,
  164. &pAccountDomainInfo,
  165. &pPrimaryDomainInfo);
  166. AfpGlobals.dwSrvrHlprCode = dwRetCode;
  167. if (dwRetCode == NO_ERROR)
  168. {
  169. break;
  170. }
  171. else if (dwRetCode != ERROR_CANT_ACCESS_DOMAIN_INFO)
  172. {
  173. AFP_PRINT( ( "SFMSVC: Get Domain Info failed %ld\n",dwRetCode));
  174. AfpLogEvent( AFPLOG_CANT_GET_DOMAIN_INFO, 0, NULL,
  175. dwRetCode, EVENTLOG_ERROR_TYPE );
  176. AfpFSDClose( hFSD );
  177. LsaClose( hLsa );
  178. SetEvent( AfpGlobals.heventSrvrHlprThread );
  179. return( dwRetCode );
  180. }
  181. // ok, we couldn't access domain info. keep retrying until we
  182. // are successful (or until the service is stopped!)
  183. AfpGlobals.dwServerState |= AFPSTATE_BLOCKED_ON_DOMINFO;
  184. if (fFirstLoop)
  185. {
  186. fFirstLoop = FALSE;
  187. AFP_PRINT( ( "SFMSVC: first loop, telling service controller to go ahead\n"));
  188. // tell the service controller we're running, so the user
  189. // doesn't have to wait as long as we're blocked here!
  190. //
  191. AfpGlobals.ServiceStatus.dwCurrentState = SERVICE_RUNNING;
  192. AfpGlobals.ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
  193. SERVICE_ACCEPT_PAUSE_CONTINUE;
  194. AfpGlobals.ServiceStatus.dwCheckPoint = 0;
  195. AfpGlobals.ServiceStatus.dwWaitHint = 0;
  196. AfpAnnounceServiceStatus();
  197. // log an event to give the bad news..
  198. AfpLogEvent( AFPLOG_DOMAIN_INFO_RETRY, 0, NULL,
  199. dwRetCode, EVENTLOG_WARNING_TYPE );
  200. }
  201. AFP_PRINT( ( "SFMSVC: sleeping 20 sec before retrying domain info\n"));
  202. // wait for 20 seconds before retrying for the domain info
  203. // Meanwhile, watch to see if the service is stopping. If so, we
  204. // must do the necessary setevent and get out
  205. if (WaitForSingleObject( AfpGlobals.heventSrvrHlprSpecial, 20000 ) == 0)
  206. {
  207. AfpFSDClose( hFSD );
  208. LsaClose( hLsa );
  209. SetEvent( AfpGlobals.heventSrvrHlprThread );
  210. return( dwRetCode );
  211. }
  212. AFP_PRINT( ( "SFMSVC: retrying getdomain info\n"));
  213. }
  214. // if we were blocked retrying the domain-info, log an event that we
  215. // are ok now
  216. if (AfpGlobals.dwServerState & AFPSTATE_BLOCKED_ON_DOMINFO)
  217. {
  218. AFP_PRINT( ( "SFMSVC: domain info stuff finally worked\n"));
  219. AfpGlobals.dwServerState &= ~AFPSTATE_BLOCKED_ON_DOMINFO;
  220. AfpLogEvent( AFPLOG_SFM_STARTED_OK, 0, NULL, 0, EVENTLOG_SUCCESS );
  221. }
  222. //
  223. // IOCTL all the domain offsets
  224. // if hLsaController is NULL, the server is in a WorkGroup, not domain
  225. //
  226. if ( ( dwRetCode = AfpIOCTLDomainOffsets(
  227. hLsaController,
  228. pAccountDomainInfo,
  229. pPrimaryDomainInfo) ) != NO_ERROR )
  230. {
  231. AFP_PRINT( ( "SFMSVC: Ioctl Domain Offsets failed.\n"));
  232. AfpLogEvent( AFPLOG_CANT_INIT_DOMAIN_INFO, 0, NULL,
  233. dwRetCode, EVENTLOG_ERROR_TYPE );
  234. // First clean up
  235. //
  236. AfpFSDClose( hFSD );
  237. // If the local machine is not a controller
  238. //
  239. if ( (hLsaController != NULL) && (hLsa != hLsaController) )
  240. {
  241. LsaClose( hLsaController );
  242. }
  243. LsaClose( hLsa );
  244. if ( pAccountDomainInfo != NULL )
  245. {
  246. LsaFreeMemory( pAccountDomainInfo );
  247. }
  248. if ( pPrimaryDomainInfo != NULL )
  249. {
  250. LsaFreeMemory( pPrimaryDomainInfo );
  251. }
  252. AfpGlobals.dwSrvrHlprCode = dwRetCode;
  253. SetEvent( AfpGlobals.heventSrvrHlprThread );
  254. return( dwRetCode );
  255. }
  256. // If the local machine is not a controller, then close the handle
  257. // since we have all the information we need.
  258. //
  259. if ( (hLsaController != NULL) && (hLsa != hLsaController) )
  260. {
  261. LsaClose( hLsaController );
  262. }
  263. }
  264. // OK everything initialize OK. Tell parent (init) thread that it may
  265. // continue.
  266. //
  267. AfpGlobals.dwSrvrHlprCode = dwRetCode;
  268. SetEvent( AfpGlobals.heventSrvrHlprThread );
  269. WaitForSingleObject( hmutexThreadCount, INFINITE );
  270. AfpGlobals.nThreadCount++;
  271. ReleaseMutex( hmutexThreadCount );
  272. pOutputBuffer = OutputBuffer;
  273. cbOutputBuffer = sizeof( OutputBuffer );
  274. pAfpFsdCmd = (PAFP_FSD_CMD_PKT)pOutputBuffer;
  275. pInputBuffer = NULL;
  276. cbInputBuffer = 0;
  277. pAfpFsdCmdResponse = (PAFP_FSD_CMD_PKT)NULL;
  278. while( TRUE ) {
  279. // IOCTL the FSD
  280. //
  281. ntStatus = NtFsControlFile( hFSD,
  282. NULL,
  283. NULL,
  284. NULL,
  285. &IoStatus,
  286. OP_GET_FSD_COMMAND,
  287. pInputBuffer,
  288. cbInputBuffer,
  289. pOutputBuffer,
  290. cbOutputBuffer
  291. );
  292. if (!NT_SUCCESS(ntStatus))
  293. AFP_PRINT(("SFMSVC: NtFsControlFile Returned %lx\n",
  294. ntStatus));
  295. ASSERT( NT_SUCCESS( ntStatus ));
  296. // Free previous call's input buffer
  297. //
  298. if ( pAfpFsdCmdResponse != NULL )
  299. LocalFree( pAfpFsdCmdResponse );
  300. // Process the command
  301. //
  302. switch( pAfpFsdCmd->Header.FsdCommand ) {
  303. case AFP_FSD_CMD_NAME_TO_SID:
  304. ntStatus = AfpNameToSid( hLsa,
  305. pAfpFsdCmd,
  306. &pAfpFsdCmdResponse,
  307. &cbInputBuffer );
  308. if ( NT_SUCCESS( ntStatus ))
  309. pInputBuffer = (PBYTE)pAfpFsdCmdResponse;
  310. else {
  311. pInputBuffer = (PBYTE)&AfpCmdHeader;
  312. cbInputBuffer = sizeof( AFP_FSD_CMD_HEADER );
  313. pAfpFsdCmdResponse = NULL;
  314. }
  315. break;
  316. case AFP_FSD_CMD_SID_TO_NAME:
  317. ntStatus = AfpSidToName( hLsa,
  318. pAccountDomainInfo,
  319. pPrimaryDomainInfo,
  320. pAfpFsdCmd,
  321. &pAfpFsdCmdResponse,
  322. &cbInputBuffer );
  323. if ( NT_SUCCESS( ntStatus ))
  324. pInputBuffer = (PBYTE)pAfpFsdCmdResponse;
  325. else {
  326. pInputBuffer = (PBYTE)&AfpCmdHeader;
  327. cbInputBuffer = sizeof( AFP_FSD_CMD_HEADER );
  328. pAfpFsdCmdResponse = NULL;
  329. }
  330. break;
  331. case AFP_FSD_CMD_CHANGE_PASSWORD:
  332. ntStatus = AfpChangePassword(
  333. hLsa,
  334. pAccountDomainInfo,
  335. pPrimaryDomainInfo,
  336. pAfpFsdCmd,
  337. &pAfpFsdCmdResponse,
  338. &cbInputBuffer );
  339. pInputBuffer = (PBYTE)&AfpCmdHeader;
  340. cbInputBuffer = sizeof( AFP_FSD_CMD_HEADER );
  341. pAfpFsdCmdResponse = NULL;
  342. break;
  343. case AFP_FSD_CMD_LOG_EVENT:
  344. AfpLogServerEvent(pAfpFsdCmd);
  345. pInputBuffer = (PBYTE)&AfpCmdHeader;
  346. cbInputBuffer = sizeof( AFP_FSD_CMD_HEADER );
  347. pAfpFsdCmdResponse = NULL;
  348. ntStatus = STATUS_SUCCESS;
  349. break;
  350. case AFP_FSD_CMD_TERMINATE_THREAD:
  351. // Do clean up
  352. //
  353. LsaClose( hLsa );
  354. AfpFSDClose( hFSD );
  355. WaitForSingleObject( hmutexThreadCount, INFINITE );
  356. AfpGlobals.nThreadCount --;
  357. // This is the last thread so clean up all the global stuff.
  358. //
  359. if ( AfpGlobals.nThreadCount == 0 ) {
  360. if ( pAccountDomainInfo != NULL )
  361. {
  362. LsaFreeMemory( pAccountDomainInfo );
  363. pAccountDomainInfo = NULL;
  364. }
  365. if ( pPrimaryDomainInfo != NULL )
  366. LsaFreeMemory( pPrimaryDomainInfo );
  367. SetEvent(AfpGlobals.heventSrvrHlprThreadTerminate);
  368. }
  369. ReleaseMutex( hmutexThreadCount );
  370. return( NO_ERROR );
  371. break;
  372. default:
  373. ntStatus = STATUS_NOT_SUPPORTED;
  374. pInputBuffer = (PBYTE)&AfpCmdHeader;
  375. cbInputBuffer = sizeof( AFP_FSD_CMD_HEADER );
  376. pAfpFsdCmdResponse = NULL;
  377. break;
  378. }
  379. CopyMemory( pInputBuffer, pAfpFsdCmd, sizeof( AFP_FSD_CMD_HEADER ) );
  380. ((PAFP_FSD_CMD_HEADER)pInputBuffer)->ntStatus = ntStatus;
  381. }
  382. return( NO_ERROR );
  383. }
  384. //**
  385. //
  386. // Call: AfpGetDomainInfo
  387. //
  388. // Returns: LsaQueryInformationPolicy, I_NetGetDCList and AfpOpenLsa
  389. //
  390. // Description: Will retrieve information regarding the account, primary and
  391. // trusted domains.
  392. //
  393. DWORD
  394. AfpGetDomainInfo(
  395. IN LSA_HANDLE hLsa,
  396. IN OUT PLSA_HANDLE phLsaController,
  397. IN OUT PPOLICY_ACCOUNT_DOMAIN_INFO* ppAccountDomainInfo,
  398. IN OUT PPOLICY_PRIMARY_DOMAIN_INFO* ppPrimaryDomainInfo
  399. )
  400. {
  401. DWORD dwRetCode = 0;
  402. NTSTATUS ntStatus = STATUS_SUCCESS;
  403. LSA_ENUMERATION_HANDLE hLsaEnum = 0;
  404. LPWSTR DomainName = NULL;
  405. PDOMAIN_CONTROLLER_INFO pDCInfo = NULL;
  406. UNICODE_STRING DCName;
  407. // This is not a loop.
  408. //
  409. do {
  410. *phLsaController = NULL;
  411. *ppAccountDomainInfo = NULL;
  412. *ppPrimaryDomainInfo = NULL;
  413. // Get the account domain
  414. //
  415. ntStatus = LsaQueryInformationPolicy(
  416. hLsa,
  417. PolicyAccountDomainInformation,
  418. (PVOID*)ppAccountDomainInfo
  419. );
  420. if ( !NT_SUCCESS( ntStatus ) )
  421. {
  422. AFP_PRINT( ( "SFMSVC: Lsa..Policy for Acct dom failed %lx\n",ntStatus));
  423. break;
  424. }
  425. // Get the primary domain
  426. //
  427. ntStatus = LsaQueryInformationPolicy(
  428. hLsa,
  429. PolicyPrimaryDomainInformation,
  430. (PVOID*)ppPrimaryDomainInfo
  431. );
  432. if ( !NT_SUCCESS( ntStatus ) )
  433. {
  434. AFP_PRINT( ( "SFMSVC: Lsa..Policy for Primary dom failed %lx\n",ntStatus));
  435. break;
  436. }
  437. // If this machine is part of a domain (not standalone), then we need
  438. // to get a list of trusted domains. Note that a workstation and a
  439. // member server can both join a domain, but they don't have to.
  440. //
  441. if ( (*ppPrimaryDomainInfo)->Sid != NULL )
  442. {
  443. // To obtain a list of trusted domains, we need to first open
  444. // the LSA on a domain controller. If we are an PDC/BDC
  445. // (NtProductLanManNt) then the local LSA will do, otherwise we need
  446. // to search for domain controllers (NtProductServer, NtProductWinNt).
  447. //
  448. if ( AfpGlobals.NtProductType != NtProductLanManNt )
  449. {
  450. ULONG ulCount;
  451. ULONG ControllerCount = 0;
  452. PUNICODE_STRING ControllerNames = NULL;
  453. PUNICODE_STRING DomainController = NULL;
  454. DomainName = (LPWSTR)LocalAlloc(
  455. LPTR,
  456. (*ppPrimaryDomainInfo)->Name.Length+sizeof(WCHAR));
  457. if ( DomainName == NULL )
  458. {
  459. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  460. break;
  461. }
  462. CopyMemory( DomainName,
  463. (*ppPrimaryDomainInfo)->Name.Buffer,
  464. (*ppPrimaryDomainInfo)->Name.Length );
  465. DomainName[(*ppPrimaryDomainInfo)->Name.Length/sizeof(WCHAR)] = 0;
  466. dwRetCode = DsGetDcName(
  467. NULL,
  468. (LPWSTR)DomainName,
  469. NULL, // domain
  470. NULL, // site name
  471. DS_DIRECTORY_SERVICE_PREFERRED,
  472. &pDCInfo);
  473. if ( dwRetCode != NO_ERROR )
  474. {
  475. AFP_PRINT( ( "SFMSVC: DsGetDcName failed 0x%lx\n",dwRetCode));
  476. dwRetCode = ERROR_CANT_ACCESS_DOMAIN_INFO;
  477. break;
  478. }
  479. AFP_PRINT(("SFMSVC: AfpOpenLsa on DC %ws for domain %ws\n",
  480. pDCInfo->DomainControllerName,DomainName));
  481. RtlInitUnicodeString(&DCName, pDCInfo->DomainControllerName);
  482. dwRetCode = AfpOpenLsa(&DCName, phLsaController );
  483. //
  484. // it's possible that this DC is down: force discovery
  485. //
  486. if (dwRetCode != NO_ERROR)
  487. {
  488. AFP_PRINT(("SFMSVC: DC %ws unreachable, forcing discovery\n",
  489. pDCInfo->DomainControllerName));
  490. NetApiBufferFree(pDCInfo);
  491. pDCInfo = NULL;
  492. dwRetCode = DsGetDcName(
  493. NULL,
  494. (LPWSTR)DomainName,
  495. NULL,
  496. NULL,
  497. (DS_DIRECTORY_SERVICE_PREFERRED | DS_FORCE_REDISCOVERY),
  498. &pDCInfo);
  499. if ( dwRetCode != NO_ERROR )
  500. {
  501. AFP_PRINT(("SFMSVC: second DsGetDcName failed %lx\n",dwRetCode));
  502. dwRetCode = ERROR_CANT_ACCESS_DOMAIN_INFO;
  503. break;
  504. }
  505. RtlInitUnicodeString(&DCName, pDCInfo->DomainControllerName);
  506. dwRetCode = AfpOpenLsa(&DCName, phLsaController );
  507. }
  508. }
  509. else
  510. {
  511. *phLsaController = hLsa;
  512. // Since the local server is an PDC/BDC, it's account
  513. // domain is the same as it's primary domain so set the
  514. // account domain info to NULL
  515. //
  516. LsaFreeMemory( *ppAccountDomainInfo );
  517. *ppAccountDomainInfo = NULL;
  518. }
  519. }
  520. else
  521. {
  522. LsaFreeMemory( *ppPrimaryDomainInfo );
  523. *ppPrimaryDomainInfo = NULL;
  524. }
  525. } while( FALSE );
  526. if (DomainName)
  527. {
  528. LocalFree( DomainName );
  529. }
  530. if (pDCInfo)
  531. {
  532. NetApiBufferFree(pDCInfo);
  533. }
  534. if ( !NT_SUCCESS( ntStatus ) || ( dwRetCode != NO_ERROR ) )
  535. {
  536. if ( *ppAccountDomainInfo != NULL )
  537. {
  538. LsaFreeMemory( *ppAccountDomainInfo );
  539. }
  540. if ( *ppPrimaryDomainInfo != NULL )
  541. {
  542. LsaFreeMemory( *ppPrimaryDomainInfo );
  543. }
  544. if ( *phLsaController != NULL )
  545. {
  546. LsaClose( *phLsaController );
  547. }
  548. if ( dwRetCode == NO_ERROR )
  549. {
  550. dwRetCode = RtlNtStatusToDosError( ntStatus );
  551. }
  552. }
  553. return( dwRetCode );
  554. }
  555. //**
  556. //
  557. // Call: AfpOpenLsa
  558. //
  559. // Returns: Returns from LsaOpenPolicy.
  560. //
  561. // Description: The LSA will be opened.
  562. //
  563. DWORD
  564. AfpOpenLsa(
  565. IN PUNICODE_STRING pSystem OPTIONAL,
  566. IN OUT PLSA_HANDLE phLsa
  567. )
  568. {
  569. SECURITY_QUALITY_OF_SERVICE QOS;
  570. OBJECT_ATTRIBUTES ObjectAttributes;
  571. NTSTATUS ntStatus;
  572. // Open the LSA and obtain a handle to it.
  573. //
  574. QOS.Length = sizeof( QOS );
  575. QOS.ImpersonationLevel = SecurityImpersonation;
  576. QOS.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  577. QOS.EffectiveOnly = FALSE;
  578. InitializeObjectAttributes( &ObjectAttributes,
  579. NULL,
  580. 0L,
  581. NULL,
  582. NULL );
  583. ObjectAttributes.SecurityQualityOfService = &QOS;
  584. ntStatus = LsaOpenPolicy( pSystem,
  585. &ObjectAttributes,
  586. POLICY_VIEW_LOCAL_INFORMATION |
  587. POLICY_LOOKUP_NAMES,
  588. phLsa );
  589. if ( !NT_SUCCESS( ntStatus ))
  590. {
  591. AFP_PRINT(("SFMSVC: AfpOpenLsa: LsaOpenPolicy failed %lx\n",ntStatus));
  592. return( RtlNtStatusToDosError( ntStatus ) );
  593. }
  594. return( NO_ERROR );
  595. }
  596. //
  597. // Call: AfpNameToSid
  598. //
  599. // Returns: NT_SUCCESS
  600. // error return codes from LSA apis.
  601. //
  602. // Description: Will use LSA API's to translate a name to a SID. On a
  603. // successful return, the pSid should be freed using LocalFree.
  604. //
  605. NTSTATUS
  606. AfpNameToSid(
  607. IN LSA_HANDLE hLsa,
  608. IN PAFP_FSD_CMD_PKT pAfpFsdCmd,
  609. OUT PAFP_FSD_CMD_PKT *ppAfpFsdCmdResponse,
  610. OUT LPDWORD pcbResponse
  611. )
  612. {
  613. NTSTATUS ntStatus;
  614. UNICODE_STRING Name;
  615. PLSA_REFERENCED_DOMAIN_LIST pDomainList;
  616. PLSA_TRANSLATED_SID pSids;
  617. UCHAR AuthCount;
  618. PSID pDomainSid;
  619. PSID pSid;
  620. // This do - while(FALSE) loop facilitates a single exit and clean-up point.
  621. //
  622. do {
  623. *ppAfpFsdCmdResponse = NULL;
  624. pDomainList = NULL;
  625. pSids = NULL;
  626. RtlInitUnicodeString( &Name, (LPWSTR)(pAfpFsdCmd->Data.Name) );
  627. ntStatus = LsaLookupNames( hLsa, 1, &Name, &pDomainList, &pSids );
  628. if ( !NT_SUCCESS( ntStatus ) )
  629. return( ntStatus );
  630. if ( pSids->Use == SidTypeDeletedAccount ){
  631. ntStatus = STATUS_NO_SUCH_USER;
  632. break;
  633. }
  634. if ( ( pDomainList->Entries == 0 ) ||
  635. ( pSids->Use == SidTypeDomain ) ||
  636. ( pSids->Use == SidTypeInvalid ) ||
  637. ( pSids->Use == SidTypeUnknown ) ||
  638. ( pSids->DomainIndex == -1 )) {
  639. ntStatus = STATUS_NONE_MAPPED;
  640. break;
  641. }
  642. pDomainSid = pDomainList->Domains[pSids->DomainIndex].Sid;
  643. AuthCount = *RtlSubAuthorityCountSid( pDomainSid ) + 1;
  644. *pcbResponse = sizeof(AFP_FSD_CMD_PKT)+RtlLengthRequiredSid(AuthCount);
  645. *ppAfpFsdCmdResponse = (PAFP_FSD_CMD_PKT)LocalAlloc(LPTR,*pcbResponse);
  646. if ( *ppAfpFsdCmdResponse == NULL ) {
  647. ntStatus = STATUS_NO_MEMORY ;
  648. break;
  649. }
  650. pSid = (*ppAfpFsdCmdResponse)->Data.Sid;
  651. // Copy the Domain Sid.
  652. //
  653. RtlCopySid( RtlLengthRequiredSid(AuthCount), pSid, pDomainSid );
  654. // Append the Relative Id.
  655. //
  656. *RtlSubAuthorityCountSid( pSid ) += 1;
  657. *RtlSubAuthoritySid( pSid, AuthCount - 1) = pSids->RelativeId;
  658. } while( FALSE );
  659. if ( (!NT_SUCCESS( ntStatus )) && ( *ppAfpFsdCmdResponse != NULL ) )
  660. LocalFree( *ppAfpFsdCmdResponse );
  661. if ( pSids != NULL )
  662. LsaFreeMemory( pSids );
  663. if ( pDomainList != NULL )
  664. LsaFreeMemory( pDomainList );
  665. return( ntStatus );
  666. }
  667. //**
  668. //
  669. // Call: AfpSidToName
  670. //
  671. // Returns: NT_SUCCESS
  672. // error return codes from LSA apis.
  673. //
  674. // Description: Given a SID, this routine will find the corresponding
  675. // UNICODE name.
  676. //
  677. NTSTATUS
  678. AfpSidToName(
  679. IN LSA_HANDLE hLsa,
  680. IN PPOLICY_ACCOUNT_DOMAIN_INFO pAccountDomainInfo,
  681. IN PPOLICY_PRIMARY_DOMAIN_INFO pPrimaryDomainInfo,
  682. IN PAFP_FSD_CMD_PKT pAfpFsdCmd,
  683. OUT PAFP_FSD_CMD_PKT *ppAfpFsdCmdResponse,
  684. OUT LPDWORD pcbResponse
  685. )
  686. {
  687. NTSTATUS ntStatus;
  688. PLSA_REFERENCED_DOMAIN_LIST pDomainList = NULL;
  689. PLSA_TRANSLATED_NAME pNames = NULL;
  690. PSID pSid = (PSID)&(pAfpFsdCmd->Data.Sid);
  691. WCHAR * pWchar;
  692. BOOL fDoNotCopyDomainName = TRUE;
  693. DWORD cbResponse;
  694. DWORD dwUse;
  695. SID AfpBuiltInSid = { 1, 1, SECURITY_NT_AUTHORITY,
  696. SECURITY_BUILTIN_DOMAIN_RID };
  697. do {
  698. *ppAfpFsdCmdResponse = NULL;
  699. ntStatus = LsaLookupSids( hLsa, 1, &pSid, &pDomainList, &pNames );
  700. if ( !NT_SUCCESS( ntStatus ) ) {
  701. if ( ntStatus == STATUS_NONE_MAPPED ) {
  702. dwUse = SidTypeUnknown;
  703. ntStatus = STATUS_SUCCESS;
  704. }
  705. else
  706. break;
  707. }
  708. else
  709. dwUse = pNames->Use;
  710. cbResponse = sizeof( AFP_FSD_CMD_PKT );
  711. switch( dwUse ){
  712. case SidTypeInvalid:
  713. cbResponse += ((wcslen(AfpGlobals.wchInvalid)+1) * sizeof(WCHAR));
  714. break;
  715. case SidTypeDeletedAccount:
  716. cbResponse += ((wcslen(AfpGlobals.wchDeleted)+1) * sizeof(WCHAR));
  717. break;
  718. case SidTypeUnknown:
  719. cbResponse += ((wcslen(AfpGlobals.wchUnknown)+1) * sizeof(WCHAR));
  720. break;
  721. case SidTypeWellKnownGroup:
  722. cbResponse += ( pNames->Name.Length + sizeof(WCHAR) );
  723. break;
  724. case SidTypeDomain:
  725. cbResponse += ( pDomainList->Domains->Name.Length + sizeof(WCHAR) );
  726. break;
  727. default:
  728. if ((pNames->DomainIndex == -1) || (pNames->Name.Buffer == NULL)){
  729. ntStatus = STATUS_NONE_MAPPED;
  730. break;
  731. }
  732. // Do not copy the domain name if the name is either a well known
  733. // group or if the SID belongs to the ACCOUNT or BUILTIN domains.
  734. // Note, the pAccountDomainInfo is NULL is this is an advanced
  735. // server, in that case we check to see if the domain name is
  736. // the primary domain name.
  737. //
  738. if (( RtlEqualSid( &AfpBuiltInSid, pDomainList->Domains->Sid )) ||
  739. (( pAccountDomainInfo != NULL ) &&
  740. (RtlEqualUnicodeString( &(pAccountDomainInfo->DomainName),
  741. &(pDomainList->Domains->Name),
  742. TRUE ))) ||
  743. ((pAccountDomainInfo == NULL) && (pPrimaryDomainInfo != NULL) &&
  744. (RtlEqualUnicodeString( &(pPrimaryDomainInfo->Name),
  745. &(pDomainList->Domains->Name),
  746. TRUE )))){
  747. cbResponse += ( pNames->Name.Length + sizeof(WCHAR) );
  748. fDoNotCopyDomainName = TRUE;
  749. }
  750. else {
  751. fDoNotCopyDomainName = FALSE;
  752. cbResponse += ( pDomainList->Domains->Name.Length +
  753. sizeof(TEXT('\\')) +
  754. pNames->Name.Length +
  755. sizeof(WCHAR) );
  756. }
  757. }
  758. if ( !NT_SUCCESS( ntStatus ) )
  759. break;
  760. *pcbResponse = cbResponse;
  761. *ppAfpFsdCmdResponse = (PAFP_FSD_CMD_PKT)LocalAlloc(LPTR,cbResponse);
  762. if ( *ppAfpFsdCmdResponse == NULL ){
  763. ntStatus = STATUS_NO_MEMORY ;
  764. break;
  765. }
  766. pWchar = (WCHAR*)((*ppAfpFsdCmdResponse)->Data.Name);
  767. switch( dwUse ){
  768. case SidTypeInvalid:
  769. wcscpy( pWchar, AfpGlobals.wchInvalid );
  770. break;
  771. case SidTypeDeletedAccount:
  772. wcscpy( pWchar, AfpGlobals.wchDeleted );
  773. break;
  774. case SidTypeUnknown:
  775. wcscpy( pWchar, AfpGlobals.wchUnknown );
  776. break;
  777. case SidTypeWellKnownGroup:
  778. CopyMemory( pWchar, pNames->Name.Buffer, pNames->Name.Length );
  779. break;
  780. case SidTypeDomain:
  781. CopyMemory( pWchar,
  782. pDomainList->Domains->Name.Buffer,
  783. pDomainList->Domains->Name.Length );
  784. break;
  785. default:
  786. if ( !fDoNotCopyDomainName ) {
  787. CopyMemory( pWchar,
  788. pDomainList->Domains->Name.Buffer,
  789. pDomainList->Domains->Name.Length );
  790. pWchar += wcslen( pWchar );
  791. CopyMemory( pWchar, TEXT("\\"), sizeof(TEXT("\\")) );
  792. pWchar += wcslen( pWchar );
  793. }
  794. CopyMemory( pWchar, pNames->Name.Buffer, pNames->Name.Length );
  795. }
  796. } while( FALSE );
  797. if ( (!NT_SUCCESS( ntStatus )) && ( *ppAfpFsdCmdResponse != NULL ) )
  798. LocalFree( *ppAfpFsdCmdResponse );
  799. if ( pNames != NULL )
  800. LsaFreeMemory( pNames );
  801. if ( pDomainList != NULL )
  802. LsaFreeMemory( pDomainList );
  803. return( ntStatus );
  804. }
  805. //**
  806. //
  807. // Call: AfpChangePassword
  808. //
  809. // Returns: NT_SUCCESS
  810. // error return codes from LSA apis.
  811. //
  812. // Description: Given the AFP_PASSWORD_DESC data structure, this procedure
  813. // will change the password of a given user.
  814. // If the passwords are supplied in clear text, then it calculate
  815. // the OWF's (encrypt OWF = One Way Function) them.
  816. // If the domain name that the user
  817. // belongs to is not supplied then a list of domains are tried
  818. // in sequence. The sequence is 1) ACCOUNT domain
  819. // 2) PRIMARY domain
  820. // 3) All trusted domains.
  821. //
  822. NTSTATUS
  823. AfpChangePassword(
  824. IN LSA_HANDLE hLsa,
  825. IN PPOLICY_ACCOUNT_DOMAIN_INFO pAccountDomainInfo,
  826. IN PPOLICY_PRIMARY_DOMAIN_INFO pPrimaryDomainInfo,
  827. IN PAFP_FSD_CMD_PKT pAfpFsdCmd,
  828. OUT PAFP_FSD_CMD_PKT *ppAfpFsdCmdResponse,
  829. OUT LPDWORD pcbResponse
  830. )
  831. {
  832. PAFP_PASSWORD_DESC pPassword = &(pAfpFsdCmd->Data.Password);
  833. NTSTATUS ntStatus=STATUS_SUCCESS;
  834. PSID pDomainSid;
  835. UNICODE_STRING TargetDomainName;
  836. WCHAR RefDomainName[DNLEN+1];
  837. DWORD cbRefDomainNameLen;
  838. DWORD cbSidLen;
  839. PSID pUserSid=NULL;
  840. PLSA_TRANSLATED_SID pTransSids;
  841. SID_NAME_USE peUse;
  842. PLSA_REFERENCED_DOMAIN_LIST pDomainList=NULL;
  843. DWORD dwRetCode;
  844. AFP_PRINT(("SFMSVC: entered AfpChangePassword for user %ws\n",(LPWSTR)pPassword->UserName));
  845. do
  846. {
  847. //
  848. // Was the domain on which the account name exists specified ??
  849. //
  850. if ( pPassword->DomainName[0] != TEXT('\0') )
  851. {
  852. RtlInitUnicodeString(&TargetDomainName, (LPWSTR)pPassword->DomainName);
  853. }
  854. //
  855. // hmmm, no domain name. We must first find which domain this user belongs to
  856. //
  857. else
  858. {
  859. cbRefDomainNameLen = DNLEN+1;
  860. cbSidLen = 100;
  861. do
  862. {
  863. dwRetCode = ERROR_SUCCESS;
  864. if (pUserSid)
  865. {
  866. LocalFree(pUserSid);
  867. }
  868. pUserSid = (PSID)LocalAlloc(LPTR, cbSidLen);
  869. if (pUserSid == NULL)
  870. {
  871. dwRetCode = ERROR_NO_SYSTEM_RESOURCES;
  872. break;
  873. }
  874. if (!LookupAccountName(
  875. NULL,
  876. (LPWSTR)pPassword->UserName,
  877. pUserSid,
  878. &cbSidLen,
  879. RefDomainName,
  880. &cbRefDomainNameLen,
  881. &peUse))
  882. {
  883. ntStatus = (NTSTATUS)GetLastError();
  884. }
  885. AFP_PRINT(("SFMSVC: LookupAccountName in loop: %d\n",GetLastError()));
  886. } while ( dwRetCode == ERROR_INSUFFICIENT_BUFFER );
  887. if (dwRetCode != ERROR_SUCCESS)
  888. {
  889. AFP_PRINT(("SFMSVC: LookupAccountName on %ws failed with %ld\n",(LPWSTR)pPassword->UserName,dwRetCode));
  890. ntStatus = (NTSTATUS)dwRetCode;
  891. break;
  892. }
  893. LocalFree(pUserSid);
  894. RtlInitUnicodeString(&TargetDomainName, RefDomainName);
  895. }
  896. AFP_PRINT(("SFMSVC: changing pwd for user %ws, domain %ws\n",
  897. (LPWSTR)pPassword->UserName,TargetDomainName.Buffer));
  898. //
  899. // now, we must find the sid for this domain
  900. //
  901. ntStatus = LsaLookupNames(hLsa, 1, &TargetDomainName, &pDomainList, &pTransSids);
  902. if (!NT_SUCCESS(ntStatus))
  903. {
  904. AFP_PRINT(("SFMSVC: LsaLookupNames failed %lx\n",ntStatus));
  905. break;
  906. }
  907. if ((pDomainList->Entries == 0) ||
  908. (pTransSids->DomainIndex == -1) ||
  909. (pTransSids->Use != SidTypeDomain) ||
  910. (pTransSids->Use == SidTypeInvalid) ||
  911. (pTransSids->Use == SidTypeUnknown))
  912. {
  913. AFP_PRINT(("SFMSVC: invalide type? Entries = %d, DomIndex = %d, Use = %d\n",
  914. pDomainList->Entries,pTransSids->DomainIndex,pTransSids->Use));
  915. ntStatus = STATUS_NONE_MAPPED;
  916. break;
  917. }
  918. pDomainSid = pDomainList->Domains[pTransSids->DomainIndex].Sid;
  919. //
  920. // call our function to change the password
  921. //
  922. ntStatus = AfpChangePasswordOnDomain(
  923. pPassword,
  924. &TargetDomainName,
  925. pDomainSid );
  926. AFP_PRINT(("SFMSVC: AfpChangePasswordOnDomain returned %lx\n",ntStatus));
  927. } while ( FALSE );
  928. if (pDomainList)
  929. {
  930. LsaFreeMemory( pDomainList );
  931. }
  932. return( ntStatus );
  933. }
  934. //**
  935. //
  936. // Call: AfpChangePasswordOnDomain
  937. //
  938. // Returns: NT_SUCCESS
  939. // STATUS_NONE_MAPPED - If the user account does not
  940. // exist in the specified domain.
  941. // error return codes from LSA apis.
  942. //
  943. // Description: This procedure will try to change the user's password on a
  944. // specified domain. It is assumed that this procedure will be
  945. // called with either the pDomainName pointing to the domain, or
  946. // the pPassword->DomainName field containing the domain.
  947. //
  948. NTSTATUS
  949. AfpChangePasswordOnDomain(
  950. IN PAFP_PASSWORD_DESC pPassword,
  951. IN PUNICODE_STRING pDomainName,
  952. IN PSID pDomainSid
  953. )
  954. {
  955. LPWSTR DCName = (LPWSTR)NULL;
  956. SAM_HANDLE hServer = (SAM_HANDLE)NULL;
  957. SAM_HANDLE hDomain = (SAM_HANDLE)NULL;
  958. SAM_HANDLE hUser = (SAM_HANDLE)NULL;
  959. PULONG pUserId = (PULONG)NULL;
  960. PSID_NAME_USE pUse = (PSID_NAME_USE)NULL;
  961. OBJECT_ATTRIBUTES ObjectAttributes;
  962. UNICODE_STRING UserName;
  963. ANSI_STRING AOldPassword;
  964. UNICODE_STRING UOldPassword;
  965. ANSI_STRING ANewPassword;
  966. UNICODE_STRING UNewPassword;
  967. POEM_STRING pOemSrvName;
  968. OEM_STRING OemServerName;
  969. OEM_STRING OemUserName;
  970. SECURITY_QUALITY_OF_SERVICE QOS;
  971. PPOLICY_ACCOUNT_DOMAIN_INFO pDomainInfo = NULL;
  972. NTSTATUS ntStatus;
  973. UNICODE_STRING PDCServerName;
  974. PUNICODE_STRING pPDCServerName = &PDCServerName;
  975. PDOMAIN_PASSWORD_INFORMATION pPasswordInfo = NULL;
  976. BYTE EncryptedPassword[LM_OWF_PASSWORD_LENGTH];
  977. WCHAR wchDomain[DNLEN+1];
  978. PDOMAIN_CONTROLLER_INFO pDCInfo = NULL;
  979. PUSER_INFO_1 pUserInfo = NULL;
  980. DWORD dwRetCode;
  981. if ((pPassword->AuthentMode == RANDNUM_EXCHANGE) ||
  982. (pPassword->AuthentMode == TWOWAY_EXCHANGE))
  983. {
  984. AFP_PRINT(("SFMSVC: Entering AfpChangePwdArapStyle for RANDNUM_EXCHANGE || TWOWAY_EXCHANGE\n"));
  985. ntStatus = AfpChangePwdArapStyle(pPassword, pDomainName, pDomainSid);
  986. AFP_PRINT(("SFMSVC: Returned from AfpChangePwdArapStyle with error %lx\n", ntStatus));
  987. return(ntStatus);
  988. }
  989. OemServerName.Buffer = NULL;
  990. OemUserName.Buffer = NULL;
  991. InitializeObjectAttributes( &ObjectAttributes,
  992. NULL,
  993. 0L,
  994. NULL,
  995. NULL );
  996. QOS.Length = sizeof( QOS );
  997. QOS.ImpersonationLevel = SecurityImpersonation;
  998. QOS.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  999. QOS.EffectiveOnly = FALSE;
  1000. ObjectAttributes.SecurityQualityOfService = &QOS;
  1001. // If the domain was not the account domain then we try to get the
  1002. // primary domain controller for the domain.
  1003. //
  1004. if ((pDomainName != NULL) &&
  1005. (pAccountDomainInfo != NULL) &&
  1006. !(RtlEqualUnicodeString( &(pAccountDomainInfo->DomainName),pDomainName, TRUE)))
  1007. {
  1008. ZeroMemory( wchDomain, sizeof( wchDomain ) );
  1009. CopyMemory( wchDomain, pDomainName->Buffer, pDomainName->Length );
  1010. // Get the PDC for the domain if this is not the account domain
  1011. //
  1012. dwRetCode = DsGetDcName(
  1013. NULL,
  1014. wchDomain,
  1015. NULL,
  1016. NULL,
  1017. (DS_DIRECTORY_SERVICE_PREFERRED | DS_WRITABLE_REQUIRED),
  1018. &pDCInfo);
  1019. if ( dwRetCode != NO_ERROR )
  1020. {
  1021. AFP_PRINT (("SFMSVC: AfpChange... DsGetDcName failed %lx\n",dwRetCode));
  1022. return( STATUS_CANT_ACCESS_DOMAIN_INFO );
  1023. }
  1024. RtlInitUnicodeString(pPDCServerName, pDCInfo->DomainControllerName);
  1025. DCName = pDCInfo->DomainControllerName;
  1026. }
  1027. else
  1028. {
  1029. pPDCServerName = NULL;
  1030. DCName = NULL;
  1031. }
  1032. do
  1033. {
  1034. //
  1035. // first and foremost: make sure this user can actually change pwd
  1036. //
  1037. if ((ntStatus= NetUserGetInfo( (LPWSTR)DCName,
  1038. pPassword->UserName,
  1039. 1,
  1040. (LPBYTE*)&pUserInfo )) == NO_ERROR )
  1041. {
  1042. if ( ( pUserInfo->usri1_flags & UF_PASSWD_CANT_CHANGE ) ||
  1043. ( pUserInfo->usri1_flags & UF_LOCKOUT ) )
  1044. {
  1045. AFP_PRINT(("SFMSVC: can't change pwd: %s\n",
  1046. (pUserInfo->usri1_flags & UF_LOCKOUT) ?
  1047. "account is locked out" : "user not allowed to change pwd"));
  1048. ntStatus = STATUS_ACCESS_DENIED;
  1049. break;
  1050. }
  1051. else if ( pUserInfo->usri1_flags & UF_ACCOUNTDISABLE )
  1052. {
  1053. AFP_PRINT(("SFMSVC: can't change pwd: user account is disabled\n"));
  1054. ntStatus = STATUS_ACCOUNT_DISABLED;
  1055. break;
  1056. }
  1057. }
  1058. else
  1059. {
  1060. AFP_PRINT(("SFMSVC: can't change pwd: NetUserGetInfo failed\n"));
  1061. if (ntStatus == ERROR_ACCESS_DENIED)
  1062. {
  1063. ntStatus = STATUS_SUCCESS;
  1064. }
  1065. else
  1066. {
  1067. ntStatus = STATUS_PASSWORD_RESTRICTION;
  1068. break;
  1069. }
  1070. }
  1071. //
  1072. // if this is a password change request coming from MSUAM Version 2,
  1073. // then we are getting passwords (and not OWFs) encrypted. Use a
  1074. // different scheme of changing password
  1075. //
  1076. if (pPassword->AuthentMode == CUSTOM_UAM_V2)
  1077. {
  1078. OemServerName.MaximumLength = OemServerName.Length = 0;
  1079. OemUserName.MaximumLength = OemUserName.Length = 0;
  1080. RtlInitUnicodeString( &UserName, pPassword->UserName );
  1081. if (pPDCServerName)
  1082. {
  1083. ntStatus = RtlUnicodeStringToOemString(
  1084. &OemServerName,
  1085. pPDCServerName,
  1086. TRUE // allocate buffer
  1087. );
  1088. if (!NT_SUCCESS(ntStatus))
  1089. {
  1090. AFP_PRINT(("SFMSVC: 1st Rtl..OemString failed %lx\n",ntStatus));
  1091. break;
  1092. }
  1093. pOemSrvName = &OemServerName;
  1094. }
  1095. else
  1096. {
  1097. pOemSrvName = NULL;
  1098. }
  1099. ntStatus = RtlUnicodeStringToOemString(
  1100. &OemUserName,
  1101. &UserName,
  1102. TRUE // allocate buffer
  1103. );
  1104. if (!NT_SUCCESS(ntStatus))
  1105. {
  1106. AFP_PRINT(("SFMSVC: 2nd Rtl..OemString failed %lx\n",ntStatus));
  1107. break;
  1108. }
  1109. ntStatus = SamiOemChangePasswordUser2(
  1110. pOemSrvName,
  1111. &OemUserName,
  1112. (PSAMPR_ENCRYPTED_USER_PASSWORD)pPassword->NewPassword,
  1113. (PENCRYPTED_LM_OWF_PASSWORD)pPassword->OldPassword);
  1114. AFP_PRINT(("SFMSVC: change pwd for MSUAM V2.0 user done, status = %lx\n",ntStatus));
  1115. // done here
  1116. break;
  1117. }
  1118. AFP_PRINT(("SFMSVC: AuthMode != MSUAM\n"));
  1119. // Connect to the PDC of that domain
  1120. //
  1121. ntStatus = SamConnect(
  1122. pPDCServerName,
  1123. &hServer,
  1124. SAM_SERVER_EXECUTE,
  1125. &ObjectAttributes);
  1126. if ( !NT_SUCCESS( ntStatus ))
  1127. {
  1128. AFP_PRINT(("SFMSVC: SamConnect to %ws failed %lx\n",
  1129. (pPDCServerName)?pPDCServerName->Buffer:L"LOCAL",ntStatus));
  1130. break;
  1131. }
  1132. // Get Sid of Domain and open the domain
  1133. //
  1134. ntStatus = SamOpenDomain(
  1135. hServer,
  1136. DOMAIN_EXECUTE,
  1137. pDomainSid,
  1138. &hDomain
  1139. );
  1140. if ( !NT_SUCCESS( ntStatus ))
  1141. {
  1142. AFP_PRINT(("SFMSVC: SamOpenDomain failed %lx\n",ntStatus));
  1143. break;
  1144. }
  1145. // Get this user's ID
  1146. //
  1147. RtlInitUnicodeString( &UserName, pPassword->UserName );
  1148. ntStatus = SamLookupNamesInDomain(
  1149. hDomain,
  1150. 1,
  1151. &UserName,
  1152. &pUserId,
  1153. &pUse
  1154. );
  1155. if ( !NT_SUCCESS( ntStatus ))
  1156. {
  1157. AFP_PRINT(("SFMSVC: SamLookupNamesInDomain failed %lx\n",ntStatus));
  1158. break;
  1159. }
  1160. // Open the user account for this user
  1161. //
  1162. ntStatus = SamOpenUser( hDomain,
  1163. USER_CHANGE_PASSWORD,
  1164. *pUserId,
  1165. &hUser
  1166. );
  1167. if ( !NT_SUCCESS( ntStatus ))
  1168. {
  1169. AFP_PRINT(("SFMSVC: SamOpenUser failed %lx\n",ntStatus));
  1170. break;
  1171. }
  1172. // First get the minimum password length requred
  1173. //
  1174. ntStatus = SamQueryInformationDomain(
  1175. hDomain,
  1176. DomainPasswordInformation,
  1177. &pPasswordInfo
  1178. );
  1179. if ( !NT_SUCCESS( ntStatus ) )
  1180. {
  1181. AFP_PRINT(("SFMSVC: SamQueryInformationDomain failed %lx\n",ntStatus));
  1182. break;
  1183. }
  1184. // First we check to see if the passwords passed are in cleartext.
  1185. // If they are, we need to calculate the OWF's for them.
  1186. // (OWF = "One Way Function")
  1187. //
  1188. if ( pPassword->AuthentMode == CLEAR_TEXT_AUTHENT )
  1189. {
  1190. AFP_PRINT(("SFMSVC: AuthentMode == CLEAR_TEXT_AUTHENT\n"));
  1191. // First check to see if the new password is long enough
  1192. //
  1193. if ( strlen( pPassword->NewPassword )
  1194. < pPasswordInfo->MinPasswordLength ) {
  1195. ntStatus = STATUS_PWD_TOO_SHORT;
  1196. break;
  1197. }
  1198. RtlInitAnsiString( &AOldPassword, pPassword->OldPassword );
  1199. RtlInitAnsiString( &ANewPassword, pPassword->NewPassword );
  1200. RtlInitUnicodeString( &UserName, pPassword->UserName );
  1201. if ((ntStatus = RtlAnsiStringToUnicodeString( &UOldPassword, &AOldPassword, TRUE )) != STATUS_SUCCESS)
  1202. {
  1203. AFP_PRINT(("SFMSVC: RtlAnsiStringToUnicodeString: UOldPassword failed with error %lx]n", ntStatus));
  1204. break;
  1205. }
  1206. if ((ntStatus = RtlAnsiStringToUnicodeString( &UNewPassword, &ANewPassword, TRUE )) != STATUS_SUCCESS)
  1207. {
  1208. AFP_PRINT(("SFMSVC: RtlAnsiStringToUnicodeString: UNewPassword failed with error %lx]n", ntStatus));
  1209. RtlFreeUnicodeString (&UOldPassword);
  1210. break;
  1211. }
  1212. AFP_PRINT(("SFMSVC: Calling SamChangePasswordUser2 \n"));
  1213. // Change the password for this user
  1214. //
  1215. ntStatus = SamChangePasswordUser2 (
  1216. pPDCServerName,
  1217. &UserName,
  1218. &UOldPassword,
  1219. &UNewPassword
  1220. );
  1221. AFP_PRINT(("SFMSVC: SamChangePasswordUser2 returned %lx\n", ntStatus));
  1222. RtlFreeUnicodeString (&UOldPassword);
  1223. RtlFreeUnicodeString (&UNewPassword);
  1224. break;
  1225. }
  1226. else
  1227. {
  1228. if (pPassword->bPasswordLength < pPasswordInfo->MinPasswordLength)
  1229. {
  1230. AFP_PRINT(("SFMSVC: AfpChangePasswordOnDomain: pwd is too short\n"));
  1231. ntStatus = STATUS_PWD_TOO_SHORT;
  1232. break;
  1233. }
  1234. }
  1235. AFP_PRINT(("SFMSVC: Invalid UAM type\n"));
  1236. ntStatus = STATUS_INVALID_PARAMETER;
  1237. break;
  1238. } while( FALSE );
  1239. if ( pUserInfo != NULL )
  1240. {
  1241. NetApiBufferFree( pUserInfo );
  1242. }
  1243. if ( hServer != (SAM_HANDLE)NULL )
  1244. {
  1245. SamCloseHandle( hServer );
  1246. }
  1247. if ( hDomain != (SAM_HANDLE)NULL )
  1248. {
  1249. SamCloseHandle( hDomain );
  1250. }
  1251. if ( hUser != (SAM_HANDLE)NULL )
  1252. {
  1253. SamCloseHandle( hUser );
  1254. }
  1255. if ( pDomainInfo != NULL )
  1256. {
  1257. LsaFreeMemory( pDomainInfo );
  1258. }
  1259. if ( pUserId != (PULONG)NULL )
  1260. {
  1261. SamFreeMemory( pUserId );
  1262. }
  1263. if ( pUse != (PSID_NAME_USE)NULL )
  1264. {
  1265. SamFreeMemory( pUse );
  1266. }
  1267. if ( pPasswordInfo != (PDOMAIN_PASSWORD_INFORMATION)NULL )
  1268. {
  1269. SamFreeMemory( pPasswordInfo );
  1270. }
  1271. if (pDCInfo)
  1272. {
  1273. NetApiBufferFree(pDCInfo);
  1274. }
  1275. if (OemServerName.Buffer)
  1276. {
  1277. RtlFreeAnsiString(&OemServerName);
  1278. }
  1279. if (OemUserName.Buffer)
  1280. {
  1281. RtlFreeAnsiString(&OemUserName);
  1282. }
  1283. return( ntStatus );
  1284. }
  1285. //**
  1286. //
  1287. // Call: AfpIOCTLDomainOffsets
  1288. //
  1289. // Returns: NT_SUCCESS
  1290. // error return codes from LSA apis.
  1291. //
  1292. // Description: Will IOCTL a list of SIDs and corresponding POSIX offsets
  1293. // of all trusted domains and other well known domains.
  1294. //
  1295. //
  1296. DWORD
  1297. AfpIOCTLDomainOffsets(
  1298. IN LSA_HANDLE hLsa,
  1299. IN PPOLICY_ACCOUNT_DOMAIN_INFO pAccountDomainInfo,
  1300. IN PPOLICY_PRIMARY_DOMAIN_INFO pPrimaryDomainInfo
  1301. )
  1302. {
  1303. NTSTATUS ntStatus;
  1304. LSA_HANDLE hLsaDomain;
  1305. PTRUSTED_POSIX_OFFSET_INFO pPosixOffset;
  1306. PAFP_SID_OFFSET pSidOffset;
  1307. ULONG cbSids;
  1308. PBYTE pbVariableData;
  1309. AFP_SID_OFFSET pWellKnownSids[20];
  1310. DWORD dwIndex;
  1311. DWORD dwCount;
  1312. AFP_REQUEST_PACKET AfpRequestPkt;
  1313. PAFP_SID_OFFSET_DESC pAfpSidOffsets = NULL;
  1314. DWORD cbSidOffsets;
  1315. DWORD dwRetCode;
  1316. // Null this array out.
  1317. //
  1318. ZeroMemory( pWellKnownSids, sizeof(AFP_SID_OFFSET)*20 );
  1319. // This is a dummy loop used only so that the break statement may
  1320. // be used to localize all the clean up in one place.
  1321. //
  1322. do {
  1323. // Create all the well known SIDs
  1324. //
  1325. ntStatus = AfpCreateWellknownSids( pWellKnownSids );
  1326. if ( !NT_SUCCESS( ntStatus ) )
  1327. {
  1328. break;
  1329. }
  1330. // Add the size of the all the well known SIDS
  1331. //
  1332. for( dwCount = 0, cbSids = 0;
  1333. pWellKnownSids[dwCount].pSid != (PBYTE)NULL;
  1334. dwCount++ )
  1335. {
  1336. cbSids += RtlLengthSid( (PSID)(pWellKnownSids[dwCount].pSid) );
  1337. }
  1338. // Insert the SID of the Account domain if is is not an advanced server
  1339. //
  1340. if ( pAccountDomainInfo != NULL )
  1341. {
  1342. cbSids += RtlLengthSid( pAccountDomainInfo->DomainSid );
  1343. dwCount++;
  1344. }
  1345. // Add the primary domain Sids only if this machine
  1346. // is a member of a domain.
  1347. //
  1348. if ( pPrimaryDomainInfo != NULL )
  1349. {
  1350. cbSids += RtlLengthSid( pPrimaryDomainInfo->Sid );
  1351. dwCount++;
  1352. }
  1353. // OK, now allocate space for all these SIDS plus their offsets
  1354. //
  1355. cbSidOffsets = (dwCount * sizeof(AFP_SID_OFFSET)) + cbSids +
  1356. (sizeof(AFP_SID_OFFSET_DESC) - sizeof(AFP_SID_OFFSET));
  1357. pAfpSidOffsets = (PAFP_SID_OFFSET_DESC)LocalAlloc( LPTR, cbSidOffsets );
  1358. if ( pAfpSidOffsets == NULL )
  1359. {
  1360. ntStatus = STATUS_NO_MEMORY ;
  1361. break;
  1362. }
  1363. // First insert all the well known SIDS
  1364. //
  1365. for( dwIndex = 0,
  1366. pAfpSidOffsets->CountOfSidOffsets = dwCount,
  1367. pSidOffset = pAfpSidOffsets->SidOffsetPairs,
  1368. pbVariableData = (LPBYTE)pAfpSidOffsets + cbSidOffsets;
  1369. pWellKnownSids[dwIndex].pSid != (PBYTE)NULL;
  1370. dwIndex++ )
  1371. {
  1372. pbVariableData-=RtlLengthSid((PSID)(pWellKnownSids[dwIndex].pSid));
  1373. ntStatus = AfpInsertSidOffset(
  1374. pSidOffset++,
  1375. pbVariableData,
  1376. (PSID)(pWellKnownSids[dwIndex].pSid),
  1377. pWellKnownSids[dwIndex].Offset,
  1378. pWellKnownSids[dwIndex].SidType );
  1379. if ( !NT_SUCCESS( ntStatus ) )
  1380. {
  1381. break;
  1382. }
  1383. }
  1384. if ( !NT_SUCCESS( ntStatus ) )
  1385. {
  1386. break;
  1387. }
  1388. // Now insert the Account domain's SID/OFFSET pair if there is one
  1389. //
  1390. if ( pAccountDomainInfo != NULL )
  1391. {
  1392. pbVariableData -= RtlLengthSid( pAccountDomainInfo->DomainSid );
  1393. ntStatus = AfpInsertSidOffset(
  1394. pSidOffset++,
  1395. pbVariableData,
  1396. pAccountDomainInfo->DomainSid,
  1397. SE_ACCOUNT_DOMAIN_POSIX_OFFSET,
  1398. AFP_SID_TYPE_DOMAIN );
  1399. if ( !NT_SUCCESS( ntStatus ) )
  1400. {
  1401. break;
  1402. }
  1403. // Construct the "None" sid if we are a standalone server (i.e. not
  1404. // a PDC or BDC). This will be used when querying the group ID of
  1405. // a directory so the the UI will never show this group to the user.
  1406. //
  1407. if ( AfpGlobals.NtProductType != NtProductLanManNt )
  1408. {
  1409. ULONG SubAuthCount, SizeNoneSid = 0;
  1410. SubAuthCount = *RtlSubAuthorityCountSid(pAccountDomainInfo->DomainSid);
  1411. SizeNoneSid = RtlLengthRequiredSid(SubAuthCount + 1);
  1412. if ((AfpGlobals.pSidNone = (PSID)LocalAlloc(LPTR,SizeNoneSid)) == NULL)
  1413. {
  1414. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1415. break;
  1416. }
  1417. RtlCopySid(SizeNoneSid, AfpGlobals.pSidNone, pAccountDomainInfo->DomainSid);
  1418. // Add the relative ID
  1419. *RtlSubAuthorityCountSid(AfpGlobals.pSidNone) = (UCHAR)(SubAuthCount+1);
  1420. // Note that the "None" sid on standalone is the same as the
  1421. // "Domain Users" Sid on PDC/BDC. (On PDC/BDC the primary
  1422. // domain is the same as the account domain).
  1423. *RtlSubAuthoritySid(AfpGlobals.pSidNone, SubAuthCount) = DOMAIN_GROUP_RID_USERS;
  1424. }
  1425. }
  1426. // Now insert the primary domain if this machine is a member of a domain
  1427. //
  1428. if ( pPrimaryDomainInfo != NULL )
  1429. {
  1430. // Insert the primary domain's SID/OFFSET pair
  1431. //
  1432. pbVariableData -= RtlLengthSid( pPrimaryDomainInfo->Sid );
  1433. ntStatus = AfpInsertSidOffset(
  1434. pSidOffset++,
  1435. pbVariableData,
  1436. pPrimaryDomainInfo->Sid,
  1437. SE_PRIMARY_DOMAIN_POSIX_OFFSET,
  1438. AFP_SID_TYPE_PRIMARY_DOMAIN );
  1439. if ( !NT_SUCCESS( ntStatus ) )
  1440. {
  1441. break;
  1442. }
  1443. }
  1444. } while( FALSE );
  1445. // IOCTL down the information if all was OK
  1446. //
  1447. if ( NT_SUCCESS( ntStatus ) )
  1448. {
  1449. AfpRequestPkt.dwRequestCode = OP_SERVER_ADD_SID_OFFSETS;
  1450. AfpRequestPkt.dwApiType = AFP_API_TYPE_ADD;
  1451. AfpRequestPkt.Type.SetInfo.pInputBuf = pAfpSidOffsets;
  1452. AfpRequestPkt.Type.Add.cbInputBufSize = cbSidOffsets;
  1453. dwRetCode = AfpServerIOCtrl( &AfpRequestPkt );
  1454. }
  1455. else
  1456. {
  1457. dwRetCode = RtlNtStatusToDosError( ntStatus );
  1458. }
  1459. if ( pAfpSidOffsets != NULL )
  1460. {
  1461. LocalFree( pAfpSidOffsets );
  1462. }
  1463. // Free all the well known SIDS
  1464. //
  1465. for( dwIndex = 0;
  1466. pWellKnownSids[dwIndex].pSid != (PBYTE)NULL;
  1467. dwIndex++ )
  1468. {
  1469. RtlFreeSid( (PSID)(pWellKnownSids[dwIndex].pSid) );
  1470. }
  1471. return( dwRetCode );
  1472. }
  1473. //**
  1474. //
  1475. // Call: AfpInsertSidOffset
  1476. //
  1477. // Returns: NT_SUCCESS
  1478. // error return codes from RtlCopySid
  1479. //
  1480. // Description: Will insert a SID/OFFSET pair in the slot pointed to by
  1481. // pSidOffset. The pbVariableData will point to where the
  1482. // SID will be stored.
  1483. //
  1484. NTSTATUS
  1485. AfpInsertSidOffset(
  1486. IN PAFP_SID_OFFSET pSidOffset,
  1487. IN LPBYTE pbVariableData,
  1488. IN PSID pSid,
  1489. IN DWORD Offset,
  1490. IN AFP_SID_TYPE afpSidType
  1491. )
  1492. {
  1493. NTSTATUS ntStatus;
  1494. // Copy the offset
  1495. //
  1496. pSidOffset->Offset = Offset;
  1497. // Set the SID type
  1498. //
  1499. pSidOffset->SidType = afpSidType;
  1500. // Copy Sid at the end of the buffer and set the offset to it
  1501. //
  1502. ntStatus = RtlCopySid( RtlLengthSid( pSid ), pbVariableData, pSid );
  1503. if ( !NT_SUCCESS( ntStatus ) )
  1504. return( ntStatus );
  1505. pSidOffset->pSid = pbVariableData;
  1506. POINTER_TO_OFFSET( (pSidOffset->pSid), pSidOffset );
  1507. return( STATUS_SUCCESS );
  1508. }
  1509. //**
  1510. //
  1511. // Call: AfpCreateWellknownSids
  1512. //
  1513. // Returns: NT_SUCCESS
  1514. // STATUS_NO_MEMORY
  1515. // non-zero returns from RtlAllocateAndInitializeSid
  1516. //
  1517. // Description: Will allocate and initialize all well known SIDs.
  1518. // The array is terminated by a NULL pointer.
  1519. //
  1520. NTSTATUS
  1521. AfpCreateWellknownSids(
  1522. OUT AFP_SID_OFFSET pWellKnownSids[]
  1523. )
  1524. {
  1525. PSID pSid;
  1526. DWORD dwIndex = 0;
  1527. NTSTATUS ntStatus;
  1528. SID_IDENTIFIER_AUTHORITY NullSidAuthority = SECURITY_NULL_SID_AUTHORITY;
  1529. SID_IDENTIFIER_AUTHORITY WorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY;
  1530. SID_IDENTIFIER_AUTHORITY LocalSidAuthority = SECURITY_LOCAL_SID_AUTHORITY;
  1531. SID_IDENTIFIER_AUTHORITY CreatorSidAuthority= SECURITY_CREATOR_SID_AUTHORITY;
  1532. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  1533. do {
  1534. //
  1535. // OK, create all the well known SIDS
  1536. //
  1537. // Create NULL SID
  1538. //
  1539. ntStatus = RtlAllocateAndInitializeSid(
  1540. &NullSidAuthority,
  1541. 1,
  1542. SECURITY_NULL_RID,
  1543. 0,0,0,0,0,0,0,
  1544. &pSid );
  1545. if ( !NT_SUCCESS( ntStatus ) )
  1546. break;
  1547. pWellKnownSids[dwIndex].pSid = (PBYTE)pSid;
  1548. pWellKnownSids[dwIndex].Offset = SE_NULL_POSIX_ID;
  1549. pWellKnownSids[dwIndex].SidType = AFP_SID_TYPE_WELL_KNOWN;
  1550. dwIndex++;
  1551. // Create WORLD SID
  1552. //
  1553. ntStatus = RtlAllocateAndInitializeSid(
  1554. &WorldSidAuthority,
  1555. 1,
  1556. SECURITY_WORLD_RID,
  1557. 0,0,0,0,0,0,0,
  1558. &pSid );
  1559. if ( !NT_SUCCESS( ntStatus ) )
  1560. break;
  1561. pWellKnownSids[dwIndex].pSid = (PBYTE)pSid;
  1562. pWellKnownSids[dwIndex].Offset = SE_WORLD_POSIX_ID;
  1563. pWellKnownSids[dwIndex].SidType = AFP_SID_TYPE_WELL_KNOWN;
  1564. dwIndex++;
  1565. // Create LOCAL SID
  1566. //
  1567. ntStatus = RtlAllocateAndInitializeSid(
  1568. &LocalSidAuthority,
  1569. 1,
  1570. SECURITY_LOCAL_RID,
  1571. 0,0,0,0,0,0,0,
  1572. &pSid );
  1573. if ( !NT_SUCCESS( ntStatus ) )
  1574. break;
  1575. pWellKnownSids[dwIndex].pSid = (PBYTE)pSid;
  1576. pWellKnownSids[dwIndex].Offset = SE_LOCAL_POSIX_ID;
  1577. pWellKnownSids[dwIndex].SidType = AFP_SID_TYPE_WELL_KNOWN;
  1578. dwIndex++;
  1579. // Create CREATOR OWNER SID
  1580. //
  1581. ntStatus = RtlAllocateAndInitializeSid(
  1582. &CreatorSidAuthority,
  1583. 1,
  1584. SECURITY_CREATOR_OWNER_RID,
  1585. 0,0,0,0,0,0,0,
  1586. &pSid );
  1587. if ( !NT_SUCCESS( ntStatus ) )
  1588. break;
  1589. pWellKnownSids[dwIndex].pSid = (PBYTE)pSid;
  1590. pWellKnownSids[dwIndex].Offset = SE_CREATOR_OWNER_POSIX_ID;
  1591. pWellKnownSids[dwIndex].SidType = AFP_SID_TYPE_WELL_KNOWN;
  1592. dwIndex++;
  1593. // Create CREATOR GROUP SID
  1594. //
  1595. ntStatus = RtlAllocateAndInitializeSid(
  1596. &CreatorSidAuthority,
  1597. 1,
  1598. SECURITY_CREATOR_GROUP_RID,
  1599. 0,0,0,0,0,0,0,
  1600. &pSid );
  1601. if ( !NT_SUCCESS( ntStatus ) )
  1602. break;
  1603. pWellKnownSids[dwIndex].pSid = (PBYTE)pSid;
  1604. pWellKnownSids[dwIndex].Offset = SE_CREATOR_GROUP_POSIX_ID;
  1605. pWellKnownSids[dwIndex].SidType = AFP_SID_TYPE_WELL_KNOWN;
  1606. dwIndex++;
  1607. // Create SECURITY_NT_AUTHORITY Sid
  1608. //
  1609. ntStatus = RtlAllocateAndInitializeSid(
  1610. &NtAuthority,
  1611. 0,0,0,0,0,0,0,0,0,
  1612. &pSid );
  1613. if ( !NT_SUCCESS( ntStatus ) )
  1614. break;
  1615. pWellKnownSids[dwIndex].pSid = (PBYTE)pSid;
  1616. pWellKnownSids[dwIndex].Offset = SE_AUTHORITY_POSIX_ID;
  1617. pWellKnownSids[dwIndex].SidType = AFP_SID_TYPE_WELL_KNOWN;
  1618. dwIndex++;
  1619. // Create SECURITY_DIALUP Sid
  1620. //
  1621. ntStatus = RtlAllocateAndInitializeSid(
  1622. &NtAuthority,
  1623. 1,
  1624. SECURITY_DIALUP_RID,
  1625. 0,0,0,0,0,0,0,
  1626. &pSid );
  1627. if ( !NT_SUCCESS( ntStatus ) )
  1628. break;
  1629. pWellKnownSids[dwIndex].pSid = (PBYTE)pSid;
  1630. pWellKnownSids[dwIndex].Offset = SE_DIALUP_POSIX_ID;
  1631. pWellKnownSids[dwIndex].SidType = AFP_SID_TYPE_WELL_KNOWN;
  1632. dwIndex++;
  1633. // Create SECURITY_NETWORK Sid
  1634. //
  1635. ntStatus = RtlAllocateAndInitializeSid(
  1636. &NtAuthority,
  1637. 1,
  1638. SECURITY_NETWORK_RID,
  1639. 0,0,0,0,0,0,0,
  1640. &pSid );
  1641. if ( !NT_SUCCESS( ntStatus ) )
  1642. break;
  1643. pWellKnownSids[dwIndex].pSid = (PBYTE)pSid;
  1644. pWellKnownSids[dwIndex].Offset = SE_NETWORK_POSIX_ID;
  1645. pWellKnownSids[dwIndex].SidType = AFP_SID_TYPE_WELL_KNOWN;
  1646. dwIndex++;
  1647. // Create SECURITY_BATCH Sid
  1648. //
  1649. ntStatus = RtlAllocateAndInitializeSid(
  1650. &NtAuthority,
  1651. 1,
  1652. SECURITY_BATCH_RID,
  1653. 0,0,0,0,0,0,0,
  1654. &pSid );
  1655. if ( !NT_SUCCESS( ntStatus ) )
  1656. break;
  1657. pWellKnownSids[dwIndex].pSid = (PBYTE)pSid;
  1658. pWellKnownSids[dwIndex].Offset = SE_NETWORK_POSIX_ID;
  1659. pWellKnownSids[dwIndex].SidType = AFP_SID_TYPE_WELL_KNOWN;
  1660. dwIndex++;
  1661. // Create SECURITY_INTERACTIVE Sid
  1662. //
  1663. ntStatus = RtlAllocateAndInitializeSid(
  1664. &NtAuthority,
  1665. 1,
  1666. SECURITY_INTERACTIVE_RID,
  1667. 0,0,0,0,0,0,0,
  1668. &pSid );
  1669. if ( !NT_SUCCESS( ntStatus ) )
  1670. break;
  1671. pWellKnownSids[dwIndex].pSid = (PBYTE)pSid;
  1672. pWellKnownSids[dwIndex].Offset = SE_INTERACTIVE_POSIX_ID;
  1673. pWellKnownSids[dwIndex].SidType = AFP_SID_TYPE_WELL_KNOWN;
  1674. dwIndex++;
  1675. // Create SECURITY_SERVICE Sid
  1676. //
  1677. ntStatus = RtlAllocateAndInitializeSid(
  1678. &NtAuthority,
  1679. 1,
  1680. SECURITY_SERVICE_RID,
  1681. 0,0,0,0,0,0,0,
  1682. &pSid );
  1683. if ( !NT_SUCCESS( ntStatus ) )
  1684. break;
  1685. pWellKnownSids[dwIndex].pSid = (PBYTE)pSid;
  1686. pWellKnownSids[dwIndex].Offset = SE_SERVICE_POSIX_ID;
  1687. pWellKnownSids[dwIndex].SidType = AFP_SID_TYPE_WELL_KNOWN;
  1688. dwIndex++;
  1689. // Create the built in domain SID
  1690. //
  1691. ntStatus = RtlAllocateAndInitializeSid(
  1692. &NtAuthority,
  1693. 1,
  1694. SECURITY_BUILTIN_DOMAIN_RID,
  1695. 0,0,0,0,0,0,0,
  1696. &pSid );
  1697. if ( !NT_SUCCESS( ntStatus ) )
  1698. break;
  1699. pWellKnownSids[dwIndex].pSid = (PBYTE)pSid;
  1700. pWellKnownSids[dwIndex].Offset = SE_BUILT_IN_DOMAIN_POSIX_OFFSET;
  1701. pWellKnownSids[dwIndex].SidType = AFP_SID_TYPE_DOMAIN;
  1702. dwIndex++;
  1703. pWellKnownSids[dwIndex].pSid = (PBYTE)NULL;
  1704. } while( FALSE );
  1705. if ( !NT_SUCCESS( ntStatus ) ) {
  1706. while( dwIndex > 0 )
  1707. RtlFreeSid( pWellKnownSids[--dwIndex].pSid );
  1708. }
  1709. return( ntStatus );
  1710. }
  1711. //**
  1712. //
  1713. // Call: AfpChangePwdArapStyle
  1714. //
  1715. // Returns: return code
  1716. //
  1717. // Description: This procedure will try to change the user's password on a
  1718. // specified domain. This does it only for native Apple UAM clients
  1719. // i.e., the user's password is stored in the DS in a reversibly-encrypted
  1720. // form, and the client sends the old and the new password (not owf as in
  1721. // MS-UAM case). This is what ARAP does, that's why the name.
  1722. // This function is big time cut-n-paste from the ARAP code
  1723. //
  1724. NTSTATUS
  1725. AfpChangePwdArapStyle(
  1726. IN PAFP_PASSWORD_DESC pPassword,
  1727. IN PUNICODE_STRING pDomainName,
  1728. IN PSID pDomainSid
  1729. )
  1730. {
  1731. NTSTATUS status;
  1732. NTSTATUS PStatus;
  1733. PMSV1_0_PASSTHROUGH_REQUEST pPassThruReq;
  1734. PMSV1_0_SUBAUTH_REQUEST pSubAuthReq;
  1735. PMSV1_0_PASSTHROUGH_RESPONSE pPassThruResp;
  1736. PMSV1_0_SUBAUTH_RESPONSE pSubAuthResp;
  1737. DWORD dwSubmitBufLen;
  1738. DWORD dwSubmitBufOffset;
  1739. PRAS_SUBAUTH_INFO pRasSubAuthInfo;
  1740. PARAP_SUBAUTH_REQ pArapSubAuthInfo;
  1741. ARAP_SUBAUTH_RESP ArapResp;
  1742. PARAP_SUBAUTH_RESP pArapRespBuffer;
  1743. PVOID RetBuf;
  1744. DWORD dwRetBufLen;
  1745. // if our registeration with lsa process failed at init time, or if
  1746. // there is no domain name for this user, just fail the succer
  1747. // (if the user logged on successfully using native Apple UAM, then
  1748. // there had better be a domain!)
  1749. if ((SfmLsaHandle == NULL) ||(pDomainName == NULL))
  1750. {
  1751. return(STATUS_LOGON_FAILURE);
  1752. }
  1753. if (pDomainName != NULL)
  1754. {
  1755. if (pDomainName->Length == 0)
  1756. {
  1757. return(STATUS_LOGON_FAILURE);
  1758. }
  1759. }
  1760. dwSubmitBufLen = sizeof(MSV1_0_PASSTHROUGH_REQUEST) +
  1761. sizeof(WCHAR)*(MAX_ARAP_USER_NAMELEN+1) + // domain name
  1762. sizeof(TEXT(MSV1_0_PACKAGE_NAME)) + // package name
  1763. sizeof(MSV1_0_SUBAUTH_REQUEST) +
  1764. sizeof(RAS_SUBAUTH_INFO) +
  1765. sizeof(ARAP_SUBAUTH_REQ) +
  1766. ALIGN_WORST; // for alignment
  1767. pPassThruReq = (PMSV1_0_PASSTHROUGH_REQUEST)
  1768. GlobalAlloc(GMEM_FIXED, dwSubmitBufLen);
  1769. if (!pPassThruReq)
  1770. {
  1771. return (STATUS_INSUFFICIENT_RESOURCES);
  1772. }
  1773. RtlZeroMemory((PBYTE)pPassThruReq, dwSubmitBufLen);
  1774. //
  1775. // Set up the MSV1_0_PASSTHROUGH_REQUEST structure
  1776. //
  1777. // tell MSV that it needs to visit our subauth pkg (for change pwd)
  1778. pPassThruReq->MessageType = MsV1_0GenericPassthrough;
  1779. pPassThruReq->DomainName.Length = pDomainName->Length;
  1780. pPassThruReq->DomainName.MaximumLength =
  1781. (sizeof(WCHAR) * (MAX_ARAP_USER_NAMELEN+1));
  1782. pPassThruReq->DomainName.Buffer = (PWSTR) (pPassThruReq + 1);
  1783. RtlMoveMemory(pPassThruReq->DomainName.Buffer,
  1784. pDomainName->Buffer,
  1785. pPassThruReq->DomainName.Length);
  1786. pPassThruReq->PackageName.Length =
  1787. (sizeof(WCHAR) * wcslen(TEXT(MSV1_0_PACKAGE_NAME)));
  1788. pPassThruReq->PackageName.MaximumLength = sizeof(TEXT(MSV1_0_PACKAGE_NAME));
  1789. pPassThruReq->PackageName.Buffer =
  1790. (PWSTR)((PBYTE)(pPassThruReq->DomainName.Buffer) +
  1791. pPassThruReq->DomainName.MaximumLength);
  1792. RtlMoveMemory(pPassThruReq->PackageName.Buffer,
  1793. TEXT(MSV1_0_PACKAGE_NAME),
  1794. sizeof(TEXT(MSV1_0_PACKAGE_NAME)));
  1795. pPassThruReq->DataLength = sizeof(MSV1_0_SUBAUTH_REQUEST) +
  1796. sizeof(RAS_SUBAUTH_INFO) + sizeof(ARAP_SUBAUTH_REQ);
  1797. pPassThruReq->LogonData =
  1798. ROUND_UP_POINTER( ((PBYTE)pPassThruReq->PackageName.Buffer +
  1799. pPassThruReq->PackageName.MaximumLength),
  1800. ALIGN_WORST );
  1801. if (pPassThruReq->LogonData >= ((PCHAR)pPassThruReq + dwSubmitBufLen))
  1802. {
  1803. AFP_PRINT (("srvrhlpr.c: Error in ROUND_UP_POINTER\n"));
  1804. GlobalFree((HGLOBAL)pPassThruReq);
  1805. return STATUS_INVALID_BUFFER_SIZE;
  1806. }
  1807. pSubAuthReq = (PMSV1_0_SUBAUTH_REQUEST)pPassThruReq->LogonData;
  1808. pSubAuthReq->MessageType = MsV1_0SubAuth;
  1809. pSubAuthReq->SubAuthPackageId = MSV1_0_SUBAUTHENTICATION_DLL_RAS;
  1810. pSubAuthReq->SubAuthInfoLength =
  1811. sizeof(RAS_SUBAUTH_INFO) + sizeof(ARAP_SUBAUTH_REQ);
  1812. //
  1813. // this pointer is self-relative
  1814. //
  1815. pSubAuthReq->SubAuthSubmitBuffer = (PUCHAR)sizeof(MSV1_0_SUBAUTH_REQUEST);
  1816. //
  1817. // copy the structure our subauth pkg will use at the other end
  1818. //
  1819. pRasSubAuthInfo = (PRAS_SUBAUTH_INFO)(pSubAuthReq + 1);
  1820. pRasSubAuthInfo->ProtocolType = RAS_SUBAUTH_PROTO_ARAP;
  1821. pRasSubAuthInfo->DataSize = sizeof(ARAP_SUBAUTH_REQ);
  1822. pArapSubAuthInfo = (PARAP_SUBAUTH_REQ)&pRasSubAuthInfo->Data[0];
  1823. pArapSubAuthInfo->PacketType = SFM_SUBAUTH_CHGPWD_PKT;
  1824. wcscpy(pArapSubAuthInfo->ChgPwd.UserName, pPassword->UserName);
  1825. RtlCopyMemory(pArapSubAuthInfo->ChgPwd.OldMunge,
  1826. pPassword->OldPassword,
  1827. MAX_MAC_PWD_LEN);
  1828. pArapSubAuthInfo->ChgPwd.OldMunge[MAX_MAC_PWD_LEN] = 0;
  1829. RtlCopyMemory(pArapSubAuthInfo->ChgPwd.NewMunge,
  1830. pPassword->NewPassword,
  1831. MAX_MAC_PWD_LEN);
  1832. pArapSubAuthInfo->ChgPwd.NewMunge[MAX_MAC_PWD_LEN] = 0;
  1833. //
  1834. // whew! finally done setting up all the parms: now call that api
  1835. //
  1836. status = LsaCallAuthenticationPackage (
  1837. SfmLsaHandle,
  1838. SfmAuthPkgId,
  1839. pPassThruReq,
  1840. dwSubmitBufLen,
  1841. &RetBuf,
  1842. &dwRetBufLen,
  1843. &PStatus);
  1844. if (status != STATUS_SUCCESS || PStatus != STATUS_SUCCESS)
  1845. {
  1846. GlobalFree((HGLOBAL)pPassThruReq);
  1847. if (status == STATUS_SUCCESS)
  1848. {
  1849. status = PStatus;
  1850. }
  1851. return(status);
  1852. }
  1853. pPassThruResp = (PMSV1_0_PASSTHROUGH_RESPONSE)RetBuf;
  1854. pSubAuthResp = (PMSV1_0_SUBAUTH_RESPONSE)(pPassThruResp->ValidationData);
  1855. // our return buffer is in self-relative format
  1856. pArapRespBuffer = (PARAP_SUBAUTH_RESP)((PBYTE)pSubAuthResp +
  1857. (ULONG_PTR)(pSubAuthResp->SubAuthReturnBuffer));
  1858. RtlCopyMemory(&ArapResp,
  1859. (PUCHAR)pArapRespBuffer,
  1860. pSubAuthResp->SubAuthInfoLength);
  1861. GlobalFree((HGLOBAL)pPassThruReq);
  1862. LsaFreeReturnBuffer(RetBuf);
  1863. if(ArapResp.Result != 0)
  1864. {
  1865. return(STATUS_UNSUCCESSFUL);
  1866. }
  1867. return(STATUS_SUCCESS);
  1868. }