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.

704 lines
18 KiB

  1. #include <nt.h>
  2. #include <ntrtl.h>
  3. #include <nturtl.h>
  4. #include <ntsam.h>
  5. #include <ntlsa.h>
  6. #include <windows.h>
  7. #include <lmcons.h>
  8. #include <stdlib.h>
  9. #include <stdio.h>
  10. #include <crypt.h> // logonmsv.h needs this
  11. #include <logonmsv.h> // SSI_SECRET_NAME defined here.
  12. #define TRUST_ENUM_PERF_BUF_SIZE sizeof(LSA_TRUST_INFORMATION) * 1000
  13. // process max. 1000 trusted account records at atime !!
  14. #define NETLOGON_SECRET_NAME L"NETLOGON$"
  15. NTSTATUS
  16. OpenAndVerifyLSA(
  17. IN OUT PLSA_HANDLE LsaHandle,
  18. IN ACCESS_MASK DesiredMask,
  19. IN LPWSTR DomainName,
  20. OUT PPOLICY_PRIMARY_DOMAIN_INFO * ReturnPrimaryDomainInfo OPTIONAL
  21. );
  22. NTSTATUS
  23. AddATrustedDomain(
  24. IN LSA_HANDLE PolicyHandle,
  25. IN PLSA_TRUST_INFORMATION TrustedDomainAccountInfo,
  26. IN LPWSTR TrustedAccountSecret
  27. );
  28. NTSTATUS
  29. DeleteATrustedDomain(
  30. IN LSA_HANDLE PolicyHandle,
  31. IN PLSA_TRUST_INFORMATION TrustedDomainAccountInfo
  32. );
  33. NTSTATUS
  34. MakeNetlogonSecretName(
  35. IN OUT PUNICODE_STRING SecretName
  36. );
  37. VOID
  38. FailureMessage(
  39. IN char *ProcName,
  40. IN NTSTATUS NtStatus
  41. );
  42. VOID
  43. FailureMessage(
  44. IN char *ProcName,
  45. IN NTSTATUS NtStatus
  46. )
  47. {
  48. fprintf( stderr, "NETJOIN: %s failed - Status == %x\n", ProcName, NtStatus );
  49. }
  50. int
  51. _cdecl
  52. main(
  53. int argc,
  54. char *argv[]
  55. )
  56. {
  57. NTSTATUS NtStatus;
  58. HKEY hKey;
  59. WCHAR UnicodeDomainName[ 32 ];
  60. WCHAR UnicodePassword[ 32 ];
  61. DWORD cbUnicodePassword = sizeof( UnicodePassword );
  62. DWORD cbUnicodeDomainName = sizeof( UnicodeDomainName );
  63. DWORD dwType;
  64. DWORD rc;
  65. ACCESS_MASK DesiredAccess;
  66. LSA_HANDLE PolicyHandle = NULL;
  67. PPOLICY_PRIMARY_DOMAIN_INFO PrimaryDomainInfo = NULL;
  68. LSA_ENUMERATION_HANDLE TrustEnumContext = 0;
  69. PLSA_TRUST_INFORMATION TrustEnumBuffer = NULL;
  70. DWORD TrustEnumCount = 0;
  71. //
  72. // Get computer name as the password to use.
  73. //
  74. if (!GetComputerNameW( UnicodePassword, &cbUnicodePassword )) {
  75. fprintf( stderr, "NETJOIN: Unable to read computer name from registry - %u\n", GetLastError() );
  76. exit( 1 );
  77. }
  78. if ((rc = RegOpenKeyW( HKEY_LOCAL_MACHINE,
  79. L"System\\CurrentControlSet\\Services\\LanmanWorkstation\\Parameters",
  80. &hKey
  81. )
  82. ) ||
  83. (rc = RegQueryValueExW( hKey,
  84. L"Domain",
  85. NULL,
  86. &dwType,
  87. (LPBYTE)UnicodeDomainName,
  88. &cbUnicodeDomainName
  89. )
  90. )
  91. ) {
  92. fprintf( stderr, "NETJOIN: Unable to read domain name from registry - %u\n", rc );
  93. exit( 1 );
  94. }
  95. DesiredAccess = POLICY_VIEW_LOCAL_INFORMATION |
  96. // needed to read domain info and trusted account info
  97. POLICY_TRUST_ADMIN |
  98. // needed to add and delete trust accounts
  99. POLICY_CREATE_SECRET ;
  100. // needed to add and delete secret
  101. NtStatus = OpenAndVerifyLSA( &PolicyHandle,
  102. DesiredAccess,
  103. UnicodeDomainName,
  104. &PrimaryDomainInfo
  105. );
  106. if (!NT_SUCCESS( NtStatus )) {
  107. fprintf( stderr, "NETJOIN: Unable to read domain name from registry - %u\n", GetLastError() );
  108. exit( 1 );
  109. }
  110. //
  111. // now the domain names match and the PrimaryDomainInfo has the SID of the
  112. // domain, we can add trust entry and secret in LSA for this domain.
  113. // Before adding this, clean up old entries.
  114. //
  115. for(;;) {
  116. DWORD i;
  117. PLSA_TRUST_INFORMATION TrustedDomainAccount;
  118. NtStatus = LsaEnumerateTrustedDomains( PolicyHandle,
  119. &TrustEnumContext,
  120. (PVOID *)&TrustEnumBuffer,
  121. TRUST_ENUM_PERF_BUF_SIZE,
  122. &TrustEnumCount
  123. );
  124. if (NtStatus == STATUS_NO_MORE_ENTRIES) {
  125. //
  126. // we are done
  127. //
  128. break;
  129. }
  130. if (NtStatus != STATUS_MORE_ENTRIES) {
  131. if (!NT_SUCCESS( NtStatus )) {
  132. FailureMessage( "LsaEnumerateTrustedDomains", NtStatus );
  133. goto Cleanup;
  134. }
  135. }
  136. //
  137. // delete trusted accounts and the corresponding secrets
  138. //
  139. for( i = 0, TrustedDomainAccount = TrustEnumBuffer;
  140. i < TrustEnumCount;
  141. TrustedDomainAccount++, i++ ) {
  142. NtStatus = DeleteATrustedDomain( PolicyHandle,
  143. TrustedDomainAccount
  144. );
  145. if (!NT_SUCCESS( NtStatus )) {
  146. FailureMessage( "DeleteATrustedDomain", NtStatus );
  147. goto Cleanup;
  148. }
  149. }
  150. if (NtStatus != STATUS_MORE_ENTRIES) {
  151. //
  152. // we have cleaned up all old entries.
  153. //
  154. break;
  155. }
  156. //
  157. // free up used enum buffer
  158. //
  159. if (TrustEnumBuffer != NULL) {
  160. LsaFreeMemory( TrustEnumBuffer );
  161. TrustEnumBuffer = NULL;
  162. }
  163. }
  164. //
  165. // add a new trust for the specified domain
  166. //
  167. NtStatus = AddATrustedDomain( PolicyHandle,
  168. (PLSA_TRUST_INFORMATION) PrimaryDomainInfo,
  169. UnicodePassword
  170. );
  171. if (!NT_SUCCESS( NtStatus )) {
  172. FailureMessage( "AddATrustedDomain", NtStatus );
  173. }
  174. else {
  175. //
  176. // Give LSA a chance to do its thing.
  177. //
  178. Sleep( 10000 );
  179. }
  180. Cleanup:
  181. if (PrimaryDomainInfo != NULL) {
  182. LsaFreeMemory( PrimaryDomainInfo );
  183. }
  184. if (TrustEnumBuffer != NULL) {
  185. LsaFreeMemory( TrustEnumBuffer );
  186. }
  187. if (PolicyHandle != NULL) {
  188. LsaClose( PolicyHandle );
  189. }
  190. if (NT_SUCCESS( NtStatus )) {
  191. fprintf( stderr,
  192. "NETJOIN: Computer == '%ws' joined the '%ws' domain.\n",
  193. UnicodePassword,
  194. UnicodeDomainName
  195. );
  196. return 0;
  197. }
  198. else {
  199. fprintf( stderr,
  200. "NETJOIN: Computer == '%ws' unable to join the '%ws' domain - Status == %08x\n",
  201. UnicodePassword,
  202. UnicodeDomainName,
  203. NtStatus
  204. );
  205. return 1;
  206. }
  207. }
  208. NTSTATUS
  209. OpenAndVerifyLSA(
  210. IN OUT PLSA_HANDLE PolicyHandle,
  211. IN ACCESS_MASK DesiredAccess,
  212. IN LPWSTR DomainName,
  213. OUT PPOLICY_PRIMARY_DOMAIN_INFO * ReturnPrimaryDomainInfo OPTIONAL
  214. )
  215. /*++
  216. Routine Description:
  217. This function opens the local LSA policy and verifies that the LSA is
  218. configured for the workstation. Optionally it returns the primary
  219. domain information that is read form the LSA.
  220. Arguments:
  221. LsaHandle - Pointer to location where the LSA handle will be retured.
  222. DesiredMask - Access mask used to open the LSA.
  223. DomainName - Name of the trusted domain.
  224. ReturnPrimaryDomainInfo - Primary domain info is returned here.
  225. Return Value:
  226. Error code of the operation.
  227. --*/
  228. {
  229. NTSTATUS NtStatus;
  230. PPOLICY_PRIMARY_DOMAIN_INFO PrimaryDomainInfo = NULL;
  231. OBJECT_ATTRIBUTES ObjectAttributes;
  232. DWORD PrimaryDomainNameLength;
  233. LPWSTR PrimaryDomainName = NULL;
  234. //
  235. // open LSA
  236. *PolicyHandle = NULL;
  237. InitializeObjectAttributes( &ObjectAttributes,
  238. NULL,
  239. 0,
  240. NULL,
  241. NULL
  242. );
  243. NtStatus = LsaOpenPolicy( NULL,
  244. &ObjectAttributes,
  245. DesiredAccess,
  246. PolicyHandle
  247. );
  248. if (!NT_SUCCESS( NtStatus )) {
  249. FailureMessage( "OpenAndVerifyLSA: LsaOpenPolicy", NtStatus );
  250. return NtStatus;
  251. }
  252. //
  253. // now read primary domain info from LSA.
  254. //
  255. NtStatus = LsaQueryInformationPolicy( *PolicyHandle,
  256. PolicyPrimaryDomainInformation,
  257. (PVOID *) &PrimaryDomainInfo
  258. );
  259. if (!NT_SUCCESS( NtStatus )) {
  260. FailureMessage( "OpenAndVerifyLSA: LsaQueryInformationPolicy", NtStatus );
  261. return NtStatus;
  262. }
  263. //
  264. // compare domain names
  265. //
  266. PrimaryDomainNameLength = PrimaryDomainInfo->Name.Length + sizeof( WCHAR );
  267. PrimaryDomainName = malloc( PrimaryDomainNameLength );
  268. if (PrimaryDomainName == NULL) {
  269. NtStatus = STATUS_NO_MEMORY;
  270. FailureMessage( "OpenAndVerifyLSA: malloc", NtStatus );
  271. goto Cleanup;
  272. }
  273. RtlMoveMemory( PrimaryDomainName,
  274. PrimaryDomainInfo->Name.Buffer,
  275. PrimaryDomainInfo->Name.Length
  276. );
  277. PrimaryDomainName[ PrimaryDomainInfo->Name.Length / sizeof(WCHAR) ] = UNICODE_NULL;
  278. if (_wcsicmp( DomainName, PrimaryDomainName )) {
  279. //
  280. // domain names don't match
  281. //
  282. NtStatus = STATUS_OBJECT_NAME_NOT_FOUND;
  283. FailureMessage( "OpenAndVerifyLSA: wcsicmp", NtStatus );
  284. goto Cleanup;
  285. }
  286. NtStatus = STATUS_SUCCESS;
  287. Cleanup:
  288. if (PrimaryDomainName != NULL) {
  289. free( PrimaryDomainName );
  290. }
  291. if (PrimaryDomainInfo != NULL) {
  292. if (ARGUMENT_PRESENT( ReturnPrimaryDomainInfo ) ) {
  293. if (NT_SUCCESS( NtStatus )) {
  294. *ReturnPrimaryDomainInfo = PrimaryDomainInfo;
  295. }
  296. else {
  297. LsaFreeMemory( PrimaryDomainInfo );
  298. *ReturnPrimaryDomainInfo = NULL;
  299. }
  300. }
  301. else {
  302. LsaFreeMemory( PrimaryDomainInfo );
  303. }
  304. }
  305. if (!NT_SUCCESS( NtStatus ) && *PolicyHandle != NULL) {
  306. //
  307. // close LSA if an error occurred.
  308. //
  309. LsaClose( *PolicyHandle );
  310. *PolicyHandle = NULL;
  311. }
  312. return NtStatus;
  313. }
  314. #if 0
  315. NET_API_STATUS NET_API_FUNCTION
  316. I_NetGetDCList(
  317. IN LPWSTR ServerName OPTIONAL,
  318. IN LPWSTR TrustedDomainName,
  319. OUT PULONG DCCount,
  320. OUT PUNICODE_STRING * DCNames
  321. );
  322. #endif
  323. NTSTATUS
  324. AddATrustedDomain(
  325. IN LSA_HANDLE PolicyHandle,
  326. IN PLSA_TRUST_INFORMATION TrustedDomainAccountInfo,
  327. IN LPWSTR TrustedAccountSecret
  328. )
  329. /*++
  330. Routine Description:
  331. This function adds trusted domain account and a secret for the
  332. corresponding account in LSA. This function does not do any check
  333. before adding this account in LSA.
  334. Arguments:
  335. PolicyHandle - LSA policy handle
  336. TrustedDomainAccountInfo - Pointer to the LSA_TRUST_INFORMATION structure.
  337. TrustedAccountSecret - Pointer to the secret for the trusted domain
  338. account.
  339. Return Value:
  340. Error code of the operation.
  341. --*/
  342. {
  343. NTSTATUS NtStatus;
  344. LSA_HANDLE TrustedDomainHandle = NULL;
  345. DWORD DCCount;
  346. PUNICODE_STRING DCNames = NULL;
  347. TRUSTED_CONTROLLERS_INFO TrustedControllersInfo;
  348. UNICODE_STRING SecretName = {0, 0, NULL};
  349. LSA_HANDLE SecretHandle = NULL;
  350. UNICODE_STRING CurrentSecretValue;
  351. DWORD UnicodeDomainNameLength;
  352. LPWSTR UnicodeDomainName = NULL;
  353. NtStatus = LsaCreateTrustedDomain( PolicyHandle,
  354. TrustedDomainAccountInfo,
  355. TRUSTED_SET_CONTROLLERS | DELETE,
  356. &TrustedDomainHandle
  357. );
  358. if (!NT_SUCCESS( NtStatus )) {
  359. FailureMessage( "AddATrustedDomain: LsaCreateTrustedDomain", NtStatus );
  360. return NtStatus;
  361. }
  362. //
  363. // Determine the DC List. This list will be stored in trusted domain
  364. // account.
  365. //
  366. // Specify the server name NULL, the domain name is the primary domain
  367. // of this workstation and so it must be listening DC announcements.
  368. //
  369. UnicodeDomainNameLength = TrustedDomainAccountInfo->Name.Length +
  370. sizeof(WCHAR);
  371. UnicodeDomainName = malloc( UnicodeDomainNameLength );
  372. if (UnicodeDomainName == NULL) {
  373. NtStatus = STATUS_NO_MEMORY;
  374. FailureMessage( "AddATrustedDomain: malloc", NtStatus );
  375. goto Cleanup;
  376. }
  377. RtlMoveMemory( UnicodeDomainName,
  378. TrustedDomainAccountInfo->Name.Buffer,
  379. TrustedDomainAccountInfo->Name.Length
  380. );
  381. UnicodeDomainName[ (UnicodeDomainNameLength / sizeof(WCHAR)) - 1 ] = '\0';
  382. #if 0
  383. if (I_NetGetDCList( NULL,
  384. UnicodeDomainName,
  385. &DCCount,
  386. &DCNames
  387. )
  388. ) {
  389. //
  390. // if unable to find the DC list for the specified domain, set
  391. // the Dc list to null and proceed.
  392. //
  393. DCCount = 0;
  394. DCNames = NULL;
  395. }
  396. #else
  397. DCCount = 0;
  398. DCNames = NULL;
  399. #endif
  400. TrustedControllersInfo.Entries = DCCount;
  401. TrustedControllersInfo.Names = DCNames;
  402. //
  403. // set controller info in trusted domain object.
  404. //
  405. NtStatus = LsaSetInformationTrustedDomain( TrustedDomainHandle,
  406. TrustedControllersInformation,
  407. &TrustedControllersInfo
  408. );
  409. if (!NT_SUCCESS( NtStatus )) {
  410. FailureMessage( "AddATrustedDomain: LsaSetInformationTrustedDomain", NtStatus );
  411. goto Cleanup;
  412. }
  413. //
  414. // Add a secret for this trusted account
  415. //
  416. MakeNetlogonSecretName( &SecretName );
  417. NtStatus = LsaCreateSecret( PolicyHandle,
  418. &SecretName,
  419. SECRET_SET_VALUE,
  420. &SecretHandle
  421. );
  422. if (!NT_SUCCESS( NtStatus )) {
  423. FailureMessage( "AddATrustedDomain: LsaCreateSecret", NtStatus );
  424. goto Cleanup;
  425. }
  426. RtlInitUnicodeString( &CurrentSecretValue, TrustedAccountSecret );
  427. NtStatus = LsaSetSecret( SecretHandle,
  428. &CurrentSecretValue,
  429. &CurrentSecretValue
  430. );
  431. Cleanup:
  432. if (DCNames != NULL) {
  433. free( DCNames );
  434. }
  435. if (UnicodeDomainName != NULL) {
  436. free( UnicodeDomainName );
  437. }
  438. if (SecretHandle != NULL) {
  439. if (!NT_SUCCESS( NtStatus)) {
  440. //
  441. // since we are not successful completely to create the trusted
  442. // account, delete it.
  443. //
  444. LsaDelete( SecretHandle );
  445. }
  446. else {
  447. LsaClose( SecretHandle );
  448. }
  449. }
  450. if (TrustedDomainHandle != NULL) {
  451. if (!NT_SUCCESS( NtStatus)) {
  452. //
  453. // since we are not successful completely to create the trusted
  454. // account, delete it.
  455. //
  456. LsaDelete( TrustedDomainHandle );
  457. }
  458. else {
  459. LsaClose( TrustedDomainHandle );
  460. }
  461. }
  462. return NtStatus;
  463. }
  464. NTSTATUS
  465. DeleteATrustedDomain(
  466. IN LSA_HANDLE PolicyHandle,
  467. IN PLSA_TRUST_INFORMATION TrustedDomainAccountInfo
  468. )
  469. /*++
  470. Routine Description:
  471. This function deletes a trusted domain account and the corresponding
  472. secret from LSA. This function however does not check any conditions
  473. before deleting this account.
  474. Arguments:
  475. PolicyHandle - LSA policy handle
  476. TurstedDoaminAccountInfo - Pointer to the LSA_TRUST_INFORMATION structure.
  477. Return Value:
  478. Error code of the operation.
  479. --*/
  480. {
  481. NTSTATUS NtStatus;
  482. LSA_HANDLE TrustedDomainHandle = NULL;
  483. LSA_HANDLE SecretHandle = NULL;
  484. UNICODE_STRING SecretName = { 0, 0, NULL };
  485. MakeNetlogonSecretName( &SecretName );
  486. //
  487. // open trusted domain account secret
  488. //
  489. NtStatus = LsaOpenSecret(
  490. PolicyHandle,
  491. &SecretName,
  492. DELETE,
  493. &SecretHandle );
  494. if (NtStatus != STATUS_OBJECT_NAME_NOT_FOUND) {
  495. if (!NT_SUCCESS( NtStatus )) {
  496. FailureMessage( "DeleteATrustedDomain: LsaOpenSecret", NtStatus );
  497. goto Cleanup;
  498. }
  499. LsaDelete( SecretHandle );
  500. }
  501. //
  502. // open trusted domain account
  503. //
  504. NtStatus = LsaOpenTrustedDomain(
  505. PolicyHandle,
  506. TrustedDomainAccountInfo->Sid,
  507. DELETE,
  508. &TrustedDomainHandle );
  509. if (!NT_SUCCESS( NtStatus )) {
  510. FailureMessage( "DeleteATrustedDomain: LsaOpenTrustedDomain", NtStatus );
  511. goto Cleanup;
  512. }
  513. LsaDelete( TrustedDomainHandle );
  514. Cleanup:
  515. return NtStatus;
  516. }
  517. NTSTATUS
  518. MakeNetlogonSecretName(
  519. IN OUT PUNICODE_STRING SecretName
  520. )
  521. /*++
  522. Routine Description:
  523. This function makes a secret name that is used for the netlogon.
  524. Arguments:
  525. SecretName - Pointer to a unicode structure in which the netlogon
  526. secret name will be returned.
  527. Return Value:
  528. NERR_Success;
  529. --*/
  530. {
  531. SecretName->Length = wcslen(SSI_SECRET_NAME) * sizeof(WCHAR);
  532. SecretName->MaximumLength = SecretName->Length + 2;
  533. SecretName->Buffer = SSI_SECRET_NAME;
  534. return STATUS_SUCCESS;
  535. }