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.

2397 lines
72 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: %#x\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. BOOLEAN fNeedToResolveDCName = FALSE;
  981. DWORD dwRetCode;
  982. if ((pPassword->AuthentMode == RANDNUM_EXCHANGE) ||
  983. (pPassword->AuthentMode == TWOWAY_EXCHANGE))
  984. {
  985. AFP_PRINT(("SFMSVC: Entering AfpChangePwdArapStyle for RANDNUM_EXCHANGE || TWOWAY_EXCHANGE\n"));
  986. ntStatus = AfpChangePwdArapStyle(pPassword, pDomainName, pDomainSid);
  987. AFP_PRINT(("SFMSVC: Returned from AfpChangePwdArapStyle with error %lx\n", ntStatus));
  988. return(ntStatus);
  989. }
  990. OemServerName.Buffer = NULL;
  991. OemUserName.Buffer = NULL;
  992. InitializeObjectAttributes( &ObjectAttributes,
  993. NULL,
  994. 0L,
  995. NULL,
  996. NULL );
  997. QOS.Length = sizeof( QOS );
  998. QOS.ImpersonationLevel = SecurityImpersonation;
  999. QOS.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  1000. QOS.EffectiveOnly = FALSE;
  1001. ObjectAttributes.SecurityQualityOfService = &QOS;
  1002. // If the domain was not the account domain then we try to get the
  1003. // primary domain controller for the domain.
  1004. //
  1005. if ((pDomainName != NULL) &&
  1006. (pAccountDomainInfo != NULL) &&
  1007. !(RtlEqualUnicodeString( &(pAccountDomainInfo->DomainName),pDomainName, TRUE)))
  1008. {
  1009. fNeedToResolveDCName = TRUE;
  1010. }
  1011. if ((pAccountDomainInfo == NULL) && (pDomainName != NULL))
  1012. {
  1013. fNeedToResolveDCName = TRUE;
  1014. }
  1015. if (fNeedToResolveDCName)
  1016. {
  1017. ZeroMemory( wchDomain, sizeof( wchDomain ) );
  1018. CopyMemory( wchDomain, pDomainName->Buffer, pDomainName->Length );
  1019. // Get the PDC for the domain if this is not the account domain
  1020. //
  1021. dwRetCode = DsGetDcName(
  1022. NULL,
  1023. wchDomain,
  1024. NULL,
  1025. NULL,
  1026. (DS_DIRECTORY_SERVICE_PREFERRED | DS_WRITABLE_REQUIRED),
  1027. &pDCInfo);
  1028. if ( dwRetCode != NO_ERROR )
  1029. {
  1030. AFP_PRINT (("SFMSVC: AfpChange... DsGetDcName failed %lx\n",dwRetCode));
  1031. return( STATUS_CANT_ACCESS_DOMAIN_INFO );
  1032. }
  1033. else
  1034. {
  1035. AFP_PRINT (("SFMSVC: AfpChange... DsGetDcName succeeded\n"));
  1036. }
  1037. AFP_PRINT (("SFMSVC: AfpChange... DsGetDcName: Got DC Name (%ws)\n",
  1038. pDCInfo->DomainControllerName));
  1039. RtlInitUnicodeString(pPDCServerName, pDCInfo->DomainControllerName);
  1040. DCName = pDCInfo->DomainControllerName;
  1041. }
  1042. else
  1043. {
  1044. AFP_PRINT (("SFMSVC: AfpChange... Do *not* require to call DsGetDcName\n"));
  1045. pPDCServerName = NULL;
  1046. DCName = NULL;
  1047. }
  1048. do
  1049. {
  1050. //
  1051. // first and foremost: make sure this user can actually change pwd
  1052. //
  1053. if ((ntStatus= NetUserGetInfo( (LPWSTR)DCName,
  1054. pPassword->UserName,
  1055. 1,
  1056. (LPBYTE*)&pUserInfo )) == NO_ERROR )
  1057. {
  1058. if ( ( pUserInfo->usri1_flags & UF_PASSWD_CANT_CHANGE ) ||
  1059. ( pUserInfo->usri1_flags & UF_LOCKOUT ) )
  1060. {
  1061. AFP_PRINT(("SFMSVC: can't change pwd: %s\n",
  1062. (pUserInfo->usri1_flags & UF_LOCKOUT) ?
  1063. "account is locked out" : "user not allowed to change pwd"));
  1064. ntStatus = STATUS_ACCESS_DENIED;
  1065. break;
  1066. }
  1067. else if ( pUserInfo->usri1_flags & UF_ACCOUNTDISABLE )
  1068. {
  1069. AFP_PRINT(("SFMSVC: can't change pwd: user account is disabled\n"));
  1070. ntStatus = STATUS_ACCOUNT_DISABLED;
  1071. break;
  1072. }
  1073. }
  1074. else
  1075. {
  1076. AFP_PRINT(("SFMSVC: can't change pwd: NetUserGetInfo failed with error %ld\n", ntStatus));
  1077. if (ntStatus == ERROR_ACCESS_DENIED)
  1078. {
  1079. ntStatus = STATUS_SUCCESS;
  1080. }
  1081. else
  1082. {
  1083. ntStatus = STATUS_PASSWORD_RESTRICTION;
  1084. break;
  1085. }
  1086. }
  1087. //
  1088. // if this is a password change request coming from MSUAM Version 2 or 3
  1089. // then we are getting passwords (and not OWFs) encrypted. Use a
  1090. // different scheme of changing password
  1091. //
  1092. if (pPassword->AuthentMode == CUSTOM_UAM_V2)
  1093. {
  1094. OemServerName.MaximumLength = OemServerName.Length = 0;
  1095. OemUserName.MaximumLength = OemUserName.Length = 0;
  1096. RtlInitUnicodeString( &UserName, pPassword->UserName );
  1097. if (pPDCServerName)
  1098. {
  1099. ntStatus = RtlUnicodeStringToOemString(
  1100. &OemServerName,
  1101. pPDCServerName,
  1102. TRUE // allocate buffer
  1103. );
  1104. if (!NT_SUCCESS(ntStatus))
  1105. {
  1106. AFP_PRINT(("SFMSVC: 1st Rtl..OemString failed %lx\n",ntStatus));
  1107. break;
  1108. }
  1109. pOemSrvName = &OemServerName;
  1110. }
  1111. else
  1112. {
  1113. pOemSrvName = NULL;
  1114. }
  1115. ntStatus = RtlUnicodeStringToOemString(
  1116. &OemUserName,
  1117. &UserName,
  1118. TRUE // allocate buffer
  1119. );
  1120. if (!NT_SUCCESS(ntStatus))
  1121. {
  1122. AFP_PRINT(("SFMSVC: 2nd Rtl..OemString failed %lx\n",ntStatus));
  1123. break;
  1124. }
  1125. ntStatus = SamiOemChangePasswordUser2(
  1126. pOemSrvName,
  1127. &OemUserName,
  1128. (PSAMPR_ENCRYPTED_USER_PASSWORD)pPassword->NewPassword,
  1129. (PENCRYPTED_LM_OWF_PASSWORD)pPassword->OldPassword);
  1130. AFP_PRINT(("SFMSVC: change pwd for MSUAM V2.0 user done, status = %lx\n",ntStatus));
  1131. // done here
  1132. break;
  1133. }
  1134. else if (pPassword->AuthentMode == CUSTOM_UAM_V3)
  1135. {
  1136. BOOLEAN LmPresent;
  1137. RtlInitUnicodeString( &UserName, pPassword->UserName );
  1138. if (pPassword->NtEncryptedBuff.Ciphers.h.Version != 1 && pPassword->NtEncryptedBuff.Ciphers.h.Version != 2)
  1139. {
  1140. ntStatus = STATUS_INVALID_PARAMETER;
  1141. break;
  1142. }
  1143. LmPresent = pPassword->NtEncryptedBuff.Ciphers.h.Version == 2 ? TRUE : FALSE;
  1144. ntStatus = SamiChangePasswordUser2(
  1145. pPDCServerName,
  1146. &UserName,
  1147. &pPassword->NtEncryptedBuff.Ciphers.m1.NewPasswordEncryptedWithOldNt,
  1148. &pPassword->NtEncryptedBuff.Ciphers.m1.OldNtOwfPasswordEncryptedWithNewNt,
  1149. LmPresent,
  1150. LmPresent ? &pPassword->NtEncryptedBuff.Ciphers.m2.NewPasswordEncryptedWithOldLm : NULL,
  1151. LmPresent ? &pPassword->NtEncryptedBuff.Ciphers.m2.OldLmOwfPasswordEncryptedWithNewLmOrNt : NULL
  1152. );
  1153. AFP_PRINT(("SFMSVC: change pwd for MSUAM V3.0 user done, status = %#x\n", ntStatus));
  1154. // done here
  1155. break;
  1156. }
  1157. AFP_PRINT(("SFMSVC: AuthMode != MSUAM\n"));
  1158. // Connect to the PDC of that domain
  1159. //
  1160. ntStatus = SamConnect(
  1161. pPDCServerName,
  1162. &hServer,
  1163. SAM_SERVER_EXECUTE,
  1164. &ObjectAttributes);
  1165. if ( !NT_SUCCESS( ntStatus ))
  1166. {
  1167. AFP_PRINT(("SFMSVC: SamConnect to %ws failed %lx\n",
  1168. (pPDCServerName)?pPDCServerName->Buffer:L"LOCAL",ntStatus));
  1169. break;
  1170. }
  1171. // Get Sid of Domain and open the domain
  1172. //
  1173. ntStatus = SamOpenDomain(
  1174. hServer,
  1175. DOMAIN_EXECUTE,
  1176. pDomainSid,
  1177. &hDomain
  1178. );
  1179. if ( !NT_SUCCESS( ntStatus ))
  1180. {
  1181. AFP_PRINT(("SFMSVC: SamOpenDomain failed %lx\n",ntStatus));
  1182. break;
  1183. }
  1184. // Get this user's ID
  1185. //
  1186. RtlInitUnicodeString( &UserName, pPassword->UserName );
  1187. ntStatus = SamLookupNamesInDomain(
  1188. hDomain,
  1189. 1,
  1190. &UserName,
  1191. &pUserId,
  1192. &pUse
  1193. );
  1194. if ( !NT_SUCCESS( ntStatus ))
  1195. {
  1196. AFP_PRINT(("SFMSVC: SamLookupNamesInDomain failed %lx\n",ntStatus));
  1197. break;
  1198. }
  1199. // Open the user account for this user
  1200. //
  1201. ntStatus = SamOpenUser( hDomain,
  1202. USER_CHANGE_PASSWORD,
  1203. *pUserId,
  1204. &hUser
  1205. );
  1206. if ( !NT_SUCCESS( ntStatus ))
  1207. {
  1208. AFP_PRINT(("SFMSVC: SamOpenUser failed %lx\n",ntStatus));
  1209. break;
  1210. }
  1211. // First get the minimum password length requred
  1212. //
  1213. ntStatus = SamQueryInformationDomain(
  1214. hDomain,
  1215. DomainPasswordInformation,
  1216. &pPasswordInfo
  1217. );
  1218. if ( !NT_SUCCESS( ntStatus ) )
  1219. {
  1220. AFP_PRINT(("SFMSVC: SamQueryInformationDomain failed %lx\n",ntStatus));
  1221. break;
  1222. }
  1223. // First we check to see if the passwords passed are in cleartext.
  1224. // If they are, we need to calculate the OWF's for them.
  1225. // (OWF = "One Way Function")
  1226. //
  1227. if ( pPassword->AuthentMode == CLEAR_TEXT_AUTHENT )
  1228. {
  1229. AFP_PRINT(("SFMSVC: AuthentMode == CLEAR_TEXT_AUTHENT\n"));
  1230. // First check to see if the new password is long enough
  1231. //
  1232. if ( wcslen ( (PWCHAR)pPassword->NewPassword )
  1233. < pPasswordInfo->MinPasswordLength ) {
  1234. AFP_PRINT (("SFMSVC: NewPwdLen (%ld) < MinPwdLen (%ld)\n",
  1235. wcslen ( (PWCHAR)pPassword->NewPassword ),
  1236. pPasswordInfo->MinPasswordLength));
  1237. ntStatus = STATUS_PWD_TOO_SHORT;
  1238. break;
  1239. }
  1240. UOldPassword.Buffer = (PWCHAR)pPassword->OldPassword;
  1241. UOldPassword.Length = UOldPassword.MaximumLength =
  1242. (USHORT)pPassword->OldPasswordLen;
  1243. UNewPassword.Buffer = (PWCHAR)pPassword->NewPassword;
  1244. UNewPassword.Length = UNewPassword.MaximumLength =
  1245. (USHORT)pPassword->NewPasswordLen;
  1246. #if 0
  1247. AFP_PRINT (("SFMSVC: OldPwd = %Z, OldLen = (%ld), NewPwd = %Z, NewLen = (%ld)\n",
  1248. &UOldPassword,
  1249. UOldPassword.Length,
  1250. &UNewPassword,
  1251. UNewPassword.Length));
  1252. #endif
  1253. AFP_PRINT(("SFMSVC: Calling SamChangePasswordUser2\n"));
  1254. // Change the password for this user
  1255. //
  1256. ntStatus = SamChangePasswordUser2 (
  1257. pPDCServerName,
  1258. &UserName,
  1259. &UOldPassword,
  1260. &UNewPassword
  1261. );
  1262. AFP_PRINT(("SFMSVC: SamChangePasswordUser2 returned %lx\n", ntStatus));
  1263. break;
  1264. }
  1265. else
  1266. {
  1267. if (pPassword->bPasswordLength < pPasswordInfo->MinPasswordLength)
  1268. {
  1269. AFP_PRINT(("SFMSVC: AfpChangePasswordOnDomain: pwd is too short\n"));
  1270. ntStatus = STATUS_PWD_TOO_SHORT;
  1271. break;
  1272. }
  1273. }
  1274. AFP_PRINT(("SFMSVC: Invalid UAM type\n"));
  1275. ntStatus = STATUS_INVALID_PARAMETER;
  1276. break;
  1277. } while( FALSE );
  1278. if ( pUserInfo != NULL )
  1279. {
  1280. NetApiBufferFree( pUserInfo );
  1281. }
  1282. if ( hServer != (SAM_HANDLE)NULL )
  1283. {
  1284. SamCloseHandle( hServer );
  1285. }
  1286. if ( hDomain != (SAM_HANDLE)NULL )
  1287. {
  1288. SamCloseHandle( hDomain );
  1289. }
  1290. if ( hUser != (SAM_HANDLE)NULL )
  1291. {
  1292. SamCloseHandle( hUser );
  1293. }
  1294. if ( pDomainInfo != NULL )
  1295. {
  1296. LsaFreeMemory( pDomainInfo );
  1297. }
  1298. if ( pUserId != (PULONG)NULL )
  1299. {
  1300. SamFreeMemory( pUserId );
  1301. }
  1302. if ( pUse != (PSID_NAME_USE)NULL )
  1303. {
  1304. SamFreeMemory( pUse );
  1305. }
  1306. if ( pPasswordInfo != (PDOMAIN_PASSWORD_INFORMATION)NULL )
  1307. {
  1308. SamFreeMemory( pPasswordInfo );
  1309. }
  1310. if (pDCInfo)
  1311. {
  1312. NetApiBufferFree(pDCInfo);
  1313. }
  1314. if (OemServerName.Buffer)
  1315. {
  1316. RtlFreeAnsiString(&OemServerName);
  1317. }
  1318. if (OemUserName.Buffer)
  1319. {
  1320. RtlFreeAnsiString(&OemUserName);
  1321. }
  1322. return( ntStatus );
  1323. }
  1324. //**
  1325. //
  1326. // Call: AfpIOCTLDomainOffsets
  1327. //
  1328. // Returns: NT_SUCCESS
  1329. // error return codes from LSA apis.
  1330. //
  1331. // Description: Will IOCTL a list of SIDs and corresponding POSIX offsets
  1332. // of all trusted domains and other well known domains.
  1333. //
  1334. //
  1335. DWORD
  1336. AfpIOCTLDomainOffsets(
  1337. IN LSA_HANDLE hLsa,
  1338. IN PPOLICY_ACCOUNT_DOMAIN_INFO pAccountDomainInfo,
  1339. IN PPOLICY_PRIMARY_DOMAIN_INFO pPrimaryDomainInfo
  1340. )
  1341. {
  1342. NTSTATUS ntStatus;
  1343. LSA_HANDLE hLsaDomain;
  1344. PTRUSTED_POSIX_OFFSET_INFO pPosixOffset;
  1345. PAFP_SID_OFFSET pSidOffset;
  1346. ULONG cbSids;
  1347. PBYTE pbVariableData;
  1348. AFP_SID_OFFSET pWellKnownSids[20];
  1349. DWORD dwIndex;
  1350. DWORD dwCount;
  1351. AFP_REQUEST_PACKET AfpRequestPkt;
  1352. PAFP_SID_OFFSET_DESC pAfpSidOffsets = NULL;
  1353. DWORD cbSidOffsets;
  1354. DWORD dwRetCode;
  1355. // Null this array out.
  1356. //
  1357. ZeroMemory( pWellKnownSids, sizeof(AFP_SID_OFFSET)*20 );
  1358. // This is a dummy loop used only so that the break statement may
  1359. // be used to localize all the clean up in one place.
  1360. //
  1361. do {
  1362. // Create all the well known SIDs
  1363. //
  1364. ntStatus = AfpCreateWellknownSids( pWellKnownSids );
  1365. if ( !NT_SUCCESS( ntStatus ) )
  1366. {
  1367. break;
  1368. }
  1369. // Add the size of the all the well known SIDS
  1370. //
  1371. for( dwCount = 0, cbSids = 0;
  1372. pWellKnownSids[dwCount].pSid != (PBYTE)NULL;
  1373. dwCount++ )
  1374. {
  1375. cbSids += RtlLengthSid( (PSID)(pWellKnownSids[dwCount].pSid) );
  1376. }
  1377. // Insert the SID of the Account domain if is is not an advanced server
  1378. //
  1379. if ( pAccountDomainInfo != NULL )
  1380. {
  1381. cbSids += RtlLengthSid( pAccountDomainInfo->DomainSid );
  1382. dwCount++;
  1383. }
  1384. // Add the primary domain Sids only if this machine
  1385. // is a member of a domain.
  1386. //
  1387. if ( pPrimaryDomainInfo != NULL )
  1388. {
  1389. cbSids += RtlLengthSid( pPrimaryDomainInfo->Sid );
  1390. dwCount++;
  1391. }
  1392. // OK, now allocate space for all these SIDS plus their offsets
  1393. //
  1394. cbSidOffsets = (dwCount * sizeof(AFP_SID_OFFSET)) + cbSids +
  1395. (sizeof(AFP_SID_OFFSET_DESC) - sizeof(AFP_SID_OFFSET));
  1396. pAfpSidOffsets = (PAFP_SID_OFFSET_DESC)LocalAlloc( LPTR, cbSidOffsets );
  1397. if ( pAfpSidOffsets == NULL )
  1398. {
  1399. ntStatus = STATUS_NO_MEMORY ;
  1400. break;
  1401. }
  1402. // First insert all the well known SIDS
  1403. //
  1404. for( dwIndex = 0,
  1405. pAfpSidOffsets->CountOfSidOffsets = dwCount,
  1406. pSidOffset = pAfpSidOffsets->SidOffsetPairs,
  1407. pbVariableData = (LPBYTE)pAfpSidOffsets + cbSidOffsets;
  1408. pWellKnownSids[dwIndex].pSid != (PBYTE)NULL;
  1409. dwIndex++ )
  1410. {
  1411. pbVariableData-=RtlLengthSid((PSID)(pWellKnownSids[dwIndex].pSid));
  1412. ntStatus = AfpInsertSidOffset(
  1413. pSidOffset++,
  1414. pbVariableData,
  1415. (PSID)(pWellKnownSids[dwIndex].pSid),
  1416. pWellKnownSids[dwIndex].Offset,
  1417. pWellKnownSids[dwIndex].SidType );
  1418. if ( !NT_SUCCESS( ntStatus ) )
  1419. {
  1420. break;
  1421. }
  1422. }
  1423. if ( !NT_SUCCESS( ntStatus ) )
  1424. {
  1425. break;
  1426. }
  1427. // Now insert the Account domain's SID/OFFSET pair if there is one
  1428. //
  1429. if ( pAccountDomainInfo != NULL )
  1430. {
  1431. pbVariableData -= RtlLengthSid( pAccountDomainInfo->DomainSid );
  1432. ntStatus = AfpInsertSidOffset(
  1433. pSidOffset++,
  1434. pbVariableData,
  1435. pAccountDomainInfo->DomainSid,
  1436. SE_ACCOUNT_DOMAIN_POSIX_OFFSET,
  1437. AFP_SID_TYPE_DOMAIN );
  1438. if ( !NT_SUCCESS( ntStatus ) )
  1439. {
  1440. break;
  1441. }
  1442. // Construct the "None" sid if we are a standalone server (i.e. not
  1443. // a PDC or BDC). This will be used when querying the group ID of
  1444. // a directory so the the UI will never show this group to the user.
  1445. //
  1446. if ( AfpGlobals.NtProductType != NtProductLanManNt )
  1447. {
  1448. ULONG SubAuthCount, SizeNoneSid = 0;
  1449. SubAuthCount = *RtlSubAuthorityCountSid(pAccountDomainInfo->DomainSid);
  1450. SizeNoneSid = RtlLengthRequiredSid(SubAuthCount + 1);
  1451. if ((AfpGlobals.pSidNone = (PSID)LocalAlloc(LPTR,SizeNoneSid)) == NULL)
  1452. {
  1453. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1454. break;
  1455. }
  1456. RtlCopySid(SizeNoneSid, AfpGlobals.pSidNone, pAccountDomainInfo->DomainSid);
  1457. // Add the relative ID
  1458. *RtlSubAuthorityCountSid(AfpGlobals.pSidNone) = (UCHAR)(SubAuthCount+1);
  1459. // Note that the "None" sid on standalone is the same as the
  1460. // "Domain Users" Sid on PDC/BDC. (On PDC/BDC the primary
  1461. // domain is the same as the account domain).
  1462. *RtlSubAuthoritySid(AfpGlobals.pSidNone, SubAuthCount) = DOMAIN_GROUP_RID_USERS;
  1463. }
  1464. }
  1465. // Now insert the primary domain if this machine is a member of a domain
  1466. //
  1467. if ( pPrimaryDomainInfo != NULL )
  1468. {
  1469. // Insert the primary domain's SID/OFFSET pair
  1470. //
  1471. pbVariableData -= RtlLengthSid( pPrimaryDomainInfo->Sid );
  1472. ntStatus = AfpInsertSidOffset(
  1473. pSidOffset++,
  1474. pbVariableData,
  1475. pPrimaryDomainInfo->Sid,
  1476. SE_PRIMARY_DOMAIN_POSIX_OFFSET,
  1477. AFP_SID_TYPE_PRIMARY_DOMAIN );
  1478. if ( !NT_SUCCESS( ntStatus ) )
  1479. {
  1480. break;
  1481. }
  1482. }
  1483. } while( FALSE );
  1484. // IOCTL down the information if all was OK
  1485. //
  1486. if ( NT_SUCCESS( ntStatus ) )
  1487. {
  1488. AfpRequestPkt.dwRequestCode = OP_SERVER_ADD_SID_OFFSETS;
  1489. AfpRequestPkt.dwApiType = AFP_API_TYPE_ADD;
  1490. AfpRequestPkt.Type.SetInfo.pInputBuf = pAfpSidOffsets;
  1491. AfpRequestPkt.Type.Add.cbInputBufSize = cbSidOffsets;
  1492. dwRetCode = AfpServerIOCtrl( &AfpRequestPkt );
  1493. }
  1494. else
  1495. {
  1496. dwRetCode = RtlNtStatusToDosError( ntStatus );
  1497. }
  1498. if ( pAfpSidOffsets != NULL )
  1499. {
  1500. LocalFree( pAfpSidOffsets );
  1501. }
  1502. // Free all the well known SIDS
  1503. //
  1504. for( dwIndex = 0;
  1505. pWellKnownSids[dwIndex].pSid != (PBYTE)NULL;
  1506. dwIndex++ )
  1507. {
  1508. RtlFreeSid( (PSID)(pWellKnownSids[dwIndex].pSid) );
  1509. }
  1510. return( dwRetCode );
  1511. }
  1512. //**
  1513. //
  1514. // Call: AfpInsertSidOffset
  1515. //
  1516. // Returns: NT_SUCCESS
  1517. // error return codes from RtlCopySid
  1518. //
  1519. // Description: Will insert a SID/OFFSET pair in the slot pointed to by
  1520. // pSidOffset. The pbVariableData will point to where the
  1521. // SID will be stored.
  1522. //
  1523. NTSTATUS
  1524. AfpInsertSidOffset(
  1525. IN PAFP_SID_OFFSET pSidOffset,
  1526. IN LPBYTE pbVariableData,
  1527. IN PSID pSid,
  1528. IN DWORD Offset,
  1529. IN AFP_SID_TYPE afpSidType
  1530. )
  1531. {
  1532. NTSTATUS ntStatus;
  1533. // Copy the offset
  1534. //
  1535. pSidOffset->Offset = Offset;
  1536. // Set the SID type
  1537. //
  1538. pSidOffset->SidType = afpSidType;
  1539. // Copy Sid at the end of the buffer and set the offset to it
  1540. //
  1541. ntStatus = RtlCopySid( RtlLengthSid( pSid ), pbVariableData, pSid );
  1542. if ( !NT_SUCCESS( ntStatus ) )
  1543. return( ntStatus );
  1544. pSidOffset->pSid = pbVariableData;
  1545. POINTER_TO_OFFSET( (pSidOffset->pSid), pSidOffset );
  1546. return( STATUS_SUCCESS );
  1547. }
  1548. //**
  1549. //
  1550. // Call: AfpCreateWellknownSids
  1551. //
  1552. // Returns: NT_SUCCESS
  1553. // STATUS_NO_MEMORY
  1554. // non-zero returns from RtlAllocateAndInitializeSid
  1555. //
  1556. // Description: Will allocate and initialize all well known SIDs.
  1557. // The array is terminated by a NULL pointer.
  1558. //
  1559. NTSTATUS
  1560. AfpCreateWellknownSids(
  1561. OUT AFP_SID_OFFSET pWellKnownSids[]
  1562. )
  1563. {
  1564. PSID pSid;
  1565. DWORD dwIndex = 0;
  1566. NTSTATUS ntStatus;
  1567. SID_IDENTIFIER_AUTHORITY NullSidAuthority = SECURITY_NULL_SID_AUTHORITY;
  1568. SID_IDENTIFIER_AUTHORITY WorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY;
  1569. SID_IDENTIFIER_AUTHORITY LocalSidAuthority = SECURITY_LOCAL_SID_AUTHORITY;
  1570. SID_IDENTIFIER_AUTHORITY CreatorSidAuthority= SECURITY_CREATOR_SID_AUTHORITY;
  1571. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  1572. do {
  1573. //
  1574. // OK, create all the well known SIDS
  1575. //
  1576. // Create NULL SID
  1577. //
  1578. ntStatus = RtlAllocateAndInitializeSid(
  1579. &NullSidAuthority,
  1580. 1,
  1581. SECURITY_NULL_RID,
  1582. 0,0,0,0,0,0,0,
  1583. &pSid );
  1584. if ( !NT_SUCCESS( ntStatus ) )
  1585. break;
  1586. pWellKnownSids[dwIndex].pSid = (PBYTE)pSid;
  1587. pWellKnownSids[dwIndex].Offset = SE_NULL_POSIX_ID;
  1588. pWellKnownSids[dwIndex].SidType = AFP_SID_TYPE_WELL_KNOWN;
  1589. dwIndex++;
  1590. // Create WORLD SID
  1591. //
  1592. ntStatus = RtlAllocateAndInitializeSid(
  1593. &WorldSidAuthority,
  1594. 1,
  1595. SECURITY_WORLD_RID,
  1596. 0,0,0,0,0,0,0,
  1597. &pSid );
  1598. if ( !NT_SUCCESS( ntStatus ) )
  1599. break;
  1600. pWellKnownSids[dwIndex].pSid = (PBYTE)pSid;
  1601. pWellKnownSids[dwIndex].Offset = SE_WORLD_POSIX_ID;
  1602. pWellKnownSids[dwIndex].SidType = AFP_SID_TYPE_WELL_KNOWN;
  1603. dwIndex++;
  1604. // Create LOCAL SID
  1605. //
  1606. ntStatus = RtlAllocateAndInitializeSid(
  1607. &LocalSidAuthority,
  1608. 1,
  1609. SECURITY_LOCAL_RID,
  1610. 0,0,0,0,0,0,0,
  1611. &pSid );
  1612. if ( !NT_SUCCESS( ntStatus ) )
  1613. break;
  1614. pWellKnownSids[dwIndex].pSid = (PBYTE)pSid;
  1615. pWellKnownSids[dwIndex].Offset = SE_LOCAL_POSIX_ID;
  1616. pWellKnownSids[dwIndex].SidType = AFP_SID_TYPE_WELL_KNOWN;
  1617. dwIndex++;
  1618. // Create CREATOR OWNER SID
  1619. //
  1620. ntStatus = RtlAllocateAndInitializeSid(
  1621. &CreatorSidAuthority,
  1622. 1,
  1623. SECURITY_CREATOR_OWNER_RID,
  1624. 0,0,0,0,0,0,0,
  1625. &pSid );
  1626. if ( !NT_SUCCESS( ntStatus ) )
  1627. break;
  1628. pWellKnownSids[dwIndex].pSid = (PBYTE)pSid;
  1629. pWellKnownSids[dwIndex].Offset = SE_CREATOR_OWNER_POSIX_ID;
  1630. pWellKnownSids[dwIndex].SidType = AFP_SID_TYPE_WELL_KNOWN;
  1631. dwIndex++;
  1632. // Create CREATOR GROUP SID
  1633. //
  1634. ntStatus = RtlAllocateAndInitializeSid(
  1635. &CreatorSidAuthority,
  1636. 1,
  1637. SECURITY_CREATOR_GROUP_RID,
  1638. 0,0,0,0,0,0,0,
  1639. &pSid );
  1640. if ( !NT_SUCCESS( ntStatus ) )
  1641. break;
  1642. pWellKnownSids[dwIndex].pSid = (PBYTE)pSid;
  1643. pWellKnownSids[dwIndex].Offset = SE_CREATOR_GROUP_POSIX_ID;
  1644. pWellKnownSids[dwIndex].SidType = AFP_SID_TYPE_WELL_KNOWN;
  1645. dwIndex++;
  1646. // Create SECURITY_NT_AUTHORITY Sid
  1647. //
  1648. ntStatus = RtlAllocateAndInitializeSid(
  1649. &NtAuthority,
  1650. 0,0,0,0,0,0,0,0,0,
  1651. &pSid );
  1652. if ( !NT_SUCCESS( ntStatus ) )
  1653. break;
  1654. pWellKnownSids[dwIndex].pSid = (PBYTE)pSid;
  1655. pWellKnownSids[dwIndex].Offset = SE_AUTHORITY_POSIX_ID;
  1656. pWellKnownSids[dwIndex].SidType = AFP_SID_TYPE_WELL_KNOWN;
  1657. dwIndex++;
  1658. // Create SECURITY_DIALUP Sid
  1659. //
  1660. ntStatus = RtlAllocateAndInitializeSid(
  1661. &NtAuthority,
  1662. 1,
  1663. SECURITY_DIALUP_RID,
  1664. 0,0,0,0,0,0,0,
  1665. &pSid );
  1666. if ( !NT_SUCCESS( ntStatus ) )
  1667. break;
  1668. pWellKnownSids[dwIndex].pSid = (PBYTE)pSid;
  1669. pWellKnownSids[dwIndex].Offset = SE_DIALUP_POSIX_ID;
  1670. pWellKnownSids[dwIndex].SidType = AFP_SID_TYPE_WELL_KNOWN;
  1671. dwIndex++;
  1672. // Create SECURITY_NETWORK Sid
  1673. //
  1674. ntStatus = RtlAllocateAndInitializeSid(
  1675. &NtAuthority,
  1676. 1,
  1677. SECURITY_NETWORK_RID,
  1678. 0,0,0,0,0,0,0,
  1679. &pSid );
  1680. if ( !NT_SUCCESS( ntStatus ) )
  1681. break;
  1682. pWellKnownSids[dwIndex].pSid = (PBYTE)pSid;
  1683. pWellKnownSids[dwIndex].Offset = SE_NETWORK_POSIX_ID;
  1684. pWellKnownSids[dwIndex].SidType = AFP_SID_TYPE_WELL_KNOWN;
  1685. dwIndex++;
  1686. // Create SECURITY_BATCH Sid
  1687. //
  1688. ntStatus = RtlAllocateAndInitializeSid(
  1689. &NtAuthority,
  1690. 1,
  1691. SECURITY_BATCH_RID,
  1692. 0,0,0,0,0,0,0,
  1693. &pSid );
  1694. if ( !NT_SUCCESS( ntStatus ) )
  1695. break;
  1696. pWellKnownSids[dwIndex].pSid = (PBYTE)pSid;
  1697. pWellKnownSids[dwIndex].Offset = SE_NETWORK_POSIX_ID;
  1698. pWellKnownSids[dwIndex].SidType = AFP_SID_TYPE_WELL_KNOWN;
  1699. dwIndex++;
  1700. // Create SECURITY_INTERACTIVE Sid
  1701. //
  1702. ntStatus = RtlAllocateAndInitializeSid(
  1703. &NtAuthority,
  1704. 1,
  1705. SECURITY_INTERACTIVE_RID,
  1706. 0,0,0,0,0,0,0,
  1707. &pSid );
  1708. if ( !NT_SUCCESS( ntStatus ) )
  1709. break;
  1710. pWellKnownSids[dwIndex].pSid = (PBYTE)pSid;
  1711. pWellKnownSids[dwIndex].Offset = SE_INTERACTIVE_POSIX_ID;
  1712. pWellKnownSids[dwIndex].SidType = AFP_SID_TYPE_WELL_KNOWN;
  1713. dwIndex++;
  1714. // Create SECURITY_SERVICE Sid
  1715. //
  1716. ntStatus = RtlAllocateAndInitializeSid(
  1717. &NtAuthority,
  1718. 1,
  1719. SECURITY_SERVICE_RID,
  1720. 0,0,0,0,0,0,0,
  1721. &pSid );
  1722. if ( !NT_SUCCESS( ntStatus ) )
  1723. break;
  1724. pWellKnownSids[dwIndex].pSid = (PBYTE)pSid;
  1725. pWellKnownSids[dwIndex].Offset = SE_SERVICE_POSIX_ID;
  1726. pWellKnownSids[dwIndex].SidType = AFP_SID_TYPE_WELL_KNOWN;
  1727. dwIndex++;
  1728. // Create the built in domain SID
  1729. //
  1730. ntStatus = RtlAllocateAndInitializeSid(
  1731. &NtAuthority,
  1732. 1,
  1733. SECURITY_BUILTIN_DOMAIN_RID,
  1734. 0,0,0,0,0,0,0,
  1735. &pSid );
  1736. if ( !NT_SUCCESS( ntStatus ) )
  1737. break;
  1738. pWellKnownSids[dwIndex].pSid = (PBYTE)pSid;
  1739. pWellKnownSids[dwIndex].Offset = SE_BUILT_IN_DOMAIN_POSIX_OFFSET;
  1740. pWellKnownSids[dwIndex].SidType = AFP_SID_TYPE_DOMAIN;
  1741. dwIndex++;
  1742. pWellKnownSids[dwIndex].pSid = (PBYTE)NULL;
  1743. } while( FALSE );
  1744. if ( !NT_SUCCESS( ntStatus ) ) {
  1745. while( dwIndex > 0 )
  1746. RtlFreeSid( pWellKnownSids[--dwIndex].pSid );
  1747. }
  1748. return( ntStatus );
  1749. }
  1750. //**
  1751. //
  1752. // Call: AfpChangePwdArapStyle
  1753. //
  1754. // Returns: return code
  1755. //
  1756. // Description: This procedure will try to change the user's password on a
  1757. // specified domain. This does it only for native Apple UAM clients
  1758. // i.e., the user's password is stored in the DS in a reversibly-encrypted
  1759. // form, and the client sends the old and the new password (not owf as in
  1760. // MS-UAM case). This is what ARAP does, that's why the name.
  1761. // This function is big time cut-n-paste from the ARAP code
  1762. //
  1763. NTSTATUS
  1764. AfpChangePwdArapStyle(
  1765. IN PAFP_PASSWORD_DESC pPassword,
  1766. IN PUNICODE_STRING pDomainName,
  1767. IN PSID pDomainSid
  1768. )
  1769. {
  1770. NTSTATUS status;
  1771. NTSTATUS PStatus;
  1772. PMSV1_0_PASSTHROUGH_REQUEST pPassThruReq;
  1773. PMSV1_0_SUBAUTH_REQUEST pSubAuthReq;
  1774. PMSV1_0_PASSTHROUGH_RESPONSE pPassThruResp;
  1775. PMSV1_0_SUBAUTH_RESPONSE pSubAuthResp;
  1776. DWORD dwSubmitBufLen;
  1777. DWORD dwSubmitBufOffset;
  1778. PRAS_SUBAUTH_INFO pRasSubAuthInfo;
  1779. PARAP_SUBAUTH_REQ pArapSubAuthInfo;
  1780. ARAP_SUBAUTH_RESP ArapResp;
  1781. PARAP_SUBAUTH_RESP pArapRespBuffer;
  1782. PVOID RetBuf;
  1783. DWORD dwRetBufLen;
  1784. // if our registeration with lsa process failed at init time, or if
  1785. // there is no domain name for this user, just fail the succer
  1786. // (if the user logged on successfully using native Apple UAM, then
  1787. // there had better be a domain!)
  1788. if ((SfmLsaHandle == NULL) ||(pDomainName == NULL))
  1789. {
  1790. return(STATUS_LOGON_FAILURE);
  1791. }
  1792. if (pDomainName != NULL)
  1793. {
  1794. if (pDomainName->Length == 0)
  1795. {
  1796. return(STATUS_LOGON_FAILURE);
  1797. }
  1798. }
  1799. dwSubmitBufLen = sizeof(MSV1_0_PASSTHROUGH_REQUEST) +
  1800. sizeof(WCHAR)*(MAX_ARAP_USER_NAMELEN+1) + // domain name
  1801. sizeof(TEXT(MSV1_0_PACKAGE_NAME)) + // package name
  1802. sizeof(MSV1_0_SUBAUTH_REQUEST) +
  1803. sizeof(RAS_SUBAUTH_INFO) +
  1804. sizeof(ARAP_SUBAUTH_REQ) +
  1805. ALIGN_WORST; // for alignment
  1806. pPassThruReq = (PMSV1_0_PASSTHROUGH_REQUEST)
  1807. GlobalAlloc(GMEM_FIXED, dwSubmitBufLen);
  1808. if (!pPassThruReq)
  1809. {
  1810. return (STATUS_INSUFFICIENT_RESOURCES);
  1811. }
  1812. RtlZeroMemory((PBYTE)pPassThruReq, dwSubmitBufLen);
  1813. //
  1814. // Set up the MSV1_0_PASSTHROUGH_REQUEST structure
  1815. //
  1816. // tell MSV that it needs to visit our subauth pkg (for change pwd)
  1817. pPassThruReq->MessageType = MsV1_0GenericPassthrough;
  1818. pPassThruReq->DomainName.Length = pDomainName->Length;
  1819. pPassThruReq->DomainName.MaximumLength =
  1820. (sizeof(WCHAR) * (MAX_ARAP_USER_NAMELEN+1));
  1821. pPassThruReq->DomainName.Buffer = (PWSTR) (pPassThruReq + 1);
  1822. RtlMoveMemory(pPassThruReq->DomainName.Buffer,
  1823. pDomainName->Buffer,
  1824. pPassThruReq->DomainName.Length);
  1825. pPassThruReq->PackageName.Length =
  1826. (sizeof(WCHAR) * wcslen(TEXT(MSV1_0_PACKAGE_NAME)));
  1827. pPassThruReq->PackageName.MaximumLength = sizeof(TEXT(MSV1_0_PACKAGE_NAME));
  1828. pPassThruReq->PackageName.Buffer =
  1829. (PWSTR)((PBYTE)(pPassThruReq->DomainName.Buffer) +
  1830. pPassThruReq->DomainName.MaximumLength);
  1831. RtlMoveMemory(pPassThruReq->PackageName.Buffer,
  1832. TEXT(MSV1_0_PACKAGE_NAME),
  1833. sizeof(TEXT(MSV1_0_PACKAGE_NAME)));
  1834. pPassThruReq->DataLength = sizeof(MSV1_0_SUBAUTH_REQUEST) +
  1835. sizeof(RAS_SUBAUTH_INFO) + sizeof(ARAP_SUBAUTH_REQ);
  1836. pPassThruReq->LogonData =
  1837. ROUND_UP_POINTER( ((PBYTE)pPassThruReq->PackageName.Buffer +
  1838. pPassThruReq->PackageName.MaximumLength),
  1839. ALIGN_WORST );
  1840. if (pPassThruReq->LogonData >= ((PCHAR)pPassThruReq + dwSubmitBufLen))
  1841. {
  1842. AFP_PRINT (("srvrhlpr.c: Error in ROUND_UP_POINTER\n"));
  1843. GlobalFree((HGLOBAL)pPassThruReq);
  1844. return STATUS_INVALID_BUFFER_SIZE;
  1845. }
  1846. pSubAuthReq = (PMSV1_0_SUBAUTH_REQUEST)pPassThruReq->LogonData;
  1847. pSubAuthReq->MessageType = MsV1_0SubAuth;
  1848. pSubAuthReq->SubAuthPackageId = MSV1_0_SUBAUTHENTICATION_DLL_RAS;
  1849. pSubAuthReq->SubAuthInfoLength =
  1850. sizeof(RAS_SUBAUTH_INFO) + sizeof(ARAP_SUBAUTH_REQ);
  1851. //
  1852. // this pointer is self-relative
  1853. //
  1854. pSubAuthReq->SubAuthSubmitBuffer = (PUCHAR)sizeof(MSV1_0_SUBAUTH_REQUEST);
  1855. //
  1856. // copy the structure our subauth pkg will use at the other end
  1857. //
  1858. pRasSubAuthInfo = (PRAS_SUBAUTH_INFO)(pSubAuthReq + 1);
  1859. pRasSubAuthInfo->ProtocolType = RAS_SUBAUTH_PROTO_ARAP;
  1860. pRasSubAuthInfo->DataSize = sizeof(ARAP_SUBAUTH_REQ);
  1861. pArapSubAuthInfo = (PARAP_SUBAUTH_REQ)&pRasSubAuthInfo->Data[0];
  1862. pArapSubAuthInfo->PacketType = SFM_SUBAUTH_CHGPWD_PKT;
  1863. if (wcslen(pPassword->UserName) > MAX_ARAP_USER_NAMELEN)
  1864. {
  1865. AFP_PRINT (("srvrhlpr.c: Username greater than 32 characters\n"));
  1866. GlobalFree((HGLOBAL)pPassThruReq);
  1867. return STATUS_INVALID_PARAMETER;
  1868. }
  1869. wcsncpy(pArapSubAuthInfo->ChgPwd.UserName, pPassword->UserName, MAX_ARAP_USER_NAMELEN);
  1870. pArapSubAuthInfo->ChgPwd.UserName[wcslen(pPassword->UserName)] = L'\0';
  1871. RtlCopyMemory(pArapSubAuthInfo->ChgPwd.OldMunge,
  1872. pPassword->OldPassword,
  1873. MAX_MAC_PWD_LEN);
  1874. pArapSubAuthInfo->ChgPwd.OldMunge[MAX_MAC_PWD_LEN] = 0;
  1875. RtlCopyMemory(pArapSubAuthInfo->ChgPwd.NewMunge,
  1876. pPassword->NewPassword,
  1877. MAX_MAC_PWD_LEN);
  1878. pArapSubAuthInfo->ChgPwd.NewMunge[MAX_MAC_PWD_LEN] = 0;
  1879. //
  1880. // whew! finally done setting up all the parms: now call that api
  1881. //
  1882. status = LsaCallAuthenticationPackage (
  1883. SfmLsaHandle,
  1884. SfmAuthPkgId,
  1885. pPassThruReq,
  1886. dwSubmitBufLen,
  1887. &RetBuf,
  1888. &dwRetBufLen,
  1889. &PStatus);
  1890. if (status != STATUS_SUCCESS || PStatus != STATUS_SUCCESS)
  1891. {
  1892. GlobalFree((HGLOBAL)pPassThruReq);
  1893. if (status == STATUS_SUCCESS)
  1894. {
  1895. status = PStatus;
  1896. }
  1897. return(status);
  1898. }
  1899. pPassThruResp = (PMSV1_0_PASSTHROUGH_RESPONSE)RetBuf;
  1900. pSubAuthResp = (PMSV1_0_SUBAUTH_RESPONSE)(pPassThruResp->ValidationData);
  1901. // our return buffer is in self-relative format
  1902. pArapRespBuffer = (PARAP_SUBAUTH_RESP)((PBYTE)pSubAuthResp +
  1903. (ULONG_PTR)(pSubAuthResp->SubAuthReturnBuffer));
  1904. RtlCopyMemory(&ArapResp,
  1905. (PUCHAR)pArapRespBuffer,
  1906. pSubAuthResp->SubAuthInfoLength);
  1907. GlobalFree((HGLOBAL)pPassThruReq);
  1908. LsaFreeReturnBuffer(RetBuf);
  1909. if(ArapResp.Result != 0)
  1910. {
  1911. return(STATUS_UNSUCCESSFUL);
  1912. }
  1913. return(STATUS_SUCCESS);
  1914. }