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.

577 lines
14 KiB

  1. /*---------------------------------------------------------------------------
  2. File: LSAUtils.cpp
  3. Comments: Code to change the domain membership of a workstation.
  4. This file also contains some general helper functions, such as:
  5. GetDomainDCName
  6. EstablishNullSession
  7. EstablishSession
  8. EstablishShare // connects to a share
  9. InitLsaString
  10. GetDomainSid
  11. (c) Copyright 1999, Mission Critical Software, Inc., All Rights Reserved
  12. Proprietary and confidential to Mission Critical Software, Inc.
  13. REVISION LOG ENTRY
  14. Revision By: Christy Boles
  15. Revised on 02/03/99 12:37:51
  16. ---------------------------------------------------------------------------
  17. */
  18. //
  19. //#include "stdafx.h"
  20. #include <windows.h>
  21. #include <process.h>
  22. #ifndef UNICODE
  23. #define UNICODE
  24. #define _UNICODE
  25. #endif
  26. #include <lm.h> // for NetXxx API
  27. #include <stdio.h>
  28. #include "LSAUtils.h"
  29. #include "ErrDct.hpp"
  30. #include "ResStr.h"
  31. #define RTN_OK 0
  32. #define RTN_USAGE 1
  33. #define RTN_ERROR 13
  34. extern TErrorDct err;
  35. BOOL
  36. GetDomainDCName(
  37. LPWSTR Domain, // in - domain name
  38. LPWSTR * pPrimaryDC // out- PDC name (must be freed with NetApiBufferFree)
  39. )
  40. {
  41. NET_API_STATUS nas;
  42. //
  43. // get the name of the Primary Domain Controller
  44. //
  45. // we're using NetGetDCName instead of DsGetDCName so this can work on NT 3.51
  46. nas = NetGetDCName(NULL, Domain, (LPBYTE *)pPrimaryDC);
  47. if(nas != NERR_Success)
  48. {
  49. SetLastError(nas);
  50. return FALSE;
  51. }
  52. return TRUE;
  53. }
  54. BOOL
  55. EstablishNullSession(
  56. LPCWSTR Server, // in - server name
  57. BOOL bEstablish // in - TRUE=establish, FALSE=disconnect
  58. )
  59. {
  60. return EstablishSession(Server,L"",L"",L"",bEstablish);
  61. }
  62. BOOL
  63. EstablishSession(
  64. LPCWSTR Server, // in - server name
  65. LPWSTR Domain, // in - domain name for user credentials
  66. LPWSTR UserName, // in - username for credentials to use
  67. LPWSTR Password, // in - password for credentials
  68. BOOL bEstablish // in - TRUE=establish, FALSE=disconnect
  69. )
  70. {
  71. LPCWSTR szIpc = L"\\IPC$";
  72. WCHAR RemoteResource[UNCLEN + 5 + 1]; // UNC len + \IPC$ + NULL
  73. DWORD cchServer;
  74. NET_API_STATUS nas;
  75. //
  76. // do not allow NULL or empty server name
  77. //
  78. if(Server == NULL || *Server == L'\0')
  79. {
  80. SetLastError(ERROR_INVALID_COMPUTERNAME);
  81. return FALSE;
  82. }
  83. cchServer = lstrlenW( Server );
  84. if( Server[0] != L'\\' && Server[1] != L'\\')
  85. {
  86. //
  87. // prepend slashes and NULL terminate
  88. //
  89. RemoteResource[0] = L'\\';
  90. RemoteResource[1] = L'\\';
  91. RemoteResource[2] = L'\0';
  92. }
  93. else
  94. {
  95. cchServer -= 2; // drop slashes from count
  96. RemoteResource[0] = L'\0';
  97. }
  98. if(cchServer > CNLEN)
  99. {
  100. SetLastError(ERROR_INVALID_COMPUTERNAME);
  101. return FALSE;
  102. }
  103. if(lstrcatW(RemoteResource, Server) == NULL)
  104. {
  105. return FALSE;
  106. }
  107. if(lstrcatW(RemoteResource, szIpc) == NULL)
  108. {
  109. return FALSE;
  110. }
  111. //
  112. // disconnect or connect to the resource, based on bEstablish
  113. //
  114. if(bEstablish)
  115. {
  116. USE_INFO_2 ui2;
  117. DWORD errParm;
  118. ZeroMemory(&ui2, sizeof(ui2));
  119. ui2.ui2_local = NULL;
  120. ui2.ui2_remote = RemoteResource;
  121. ui2.ui2_asg_type = USE_IPC;
  122. ui2.ui2_domainname = Domain;
  123. ui2.ui2_username = UserName;
  124. ui2.ui2_password = Password;
  125. // try establishing session for one minute
  126. // if computer is not accepting any more connections
  127. for (int i = 0; i < (60000 / 5000); i++)
  128. {
  129. nas = NetUseAdd(NULL, 2, (LPBYTE)&ui2, &errParm);
  130. if (nas != ERROR_REQ_NOT_ACCEP)
  131. {
  132. break;
  133. }
  134. Sleep(5000);
  135. }
  136. }
  137. else
  138. {
  139. nas = NetUseDel(NULL, RemoteResource, 0);
  140. }
  141. if( nas == NERR_Success )
  142. {
  143. return TRUE; // indicate success
  144. }
  145. SetLastError(nas);
  146. return FALSE;
  147. }
  148. BOOL
  149. EstablishShare(
  150. LPCWSTR Server, // in - server name
  151. LPWSTR Share, // in - share name
  152. LPWSTR Domain, // in - domain name for credentials to connect with
  153. LPWSTR UserName, // in - user name to connect as
  154. LPWSTR Password, // in - password for username
  155. BOOL bEstablish // in - TRUE=connect, FALSE=disconnect
  156. )
  157. {
  158. WCHAR RemoteResource[MAX_PATH];
  159. DWORD cchServer;
  160. NET_API_STATUS nas;
  161. //
  162. // do not allow NULL or empty server name
  163. //
  164. if(Server == NULL || *Server == L'\0')
  165. {
  166. SetLastError(ERROR_INVALID_COMPUTERNAME);
  167. return FALSE;
  168. }
  169. cchServer = lstrlenW( Server );
  170. if( Server[0] != L'\\' && Server[1] != L'\\')
  171. {
  172. //
  173. // prepend slashes and NULL terminate
  174. //
  175. RemoteResource[0] = L'\\';
  176. RemoteResource[1] = L'\\';
  177. RemoteResource[2] = L'\0';
  178. }
  179. else
  180. {
  181. cchServer -= 2; // drop slashes from count
  182. RemoteResource[0] = L'\0';
  183. }
  184. if(cchServer > CNLEN)
  185. {
  186. SetLastError(ERROR_INVALID_COMPUTERNAME);
  187. return FALSE;
  188. }
  189. if(lstrcatW(RemoteResource, Server) == NULL)
  190. {
  191. return FALSE;
  192. }
  193. if(lstrcatW(RemoteResource, Share) == NULL)
  194. {
  195. return FALSE;
  196. }
  197. //
  198. // disconnect or connect to the resource, based on bEstablish
  199. //
  200. if(bEstablish)
  201. {
  202. USE_INFO_2 ui2;
  203. DWORD errParm;
  204. ZeroMemory(&ui2, sizeof(ui2));
  205. ui2.ui2_local = NULL;
  206. ui2.ui2_remote = RemoteResource;
  207. ui2.ui2_asg_type = USE_DISKDEV;
  208. ui2.ui2_domainname = Domain;
  209. ui2.ui2_username = UserName;
  210. ui2.ui2_password = Password;
  211. // try establishing session for one minute
  212. // if computer is not accepting any more connections
  213. for (int i = 0; i < (60000 / 5000); i++)
  214. {
  215. nas = NetUseAdd(NULL, 2, (LPBYTE)&ui2, &errParm);
  216. if (nas != ERROR_REQ_NOT_ACCEP)
  217. {
  218. break;
  219. }
  220. Sleep(5000);
  221. }
  222. }
  223. else
  224. {
  225. nas = NetUseDel(NULL, RemoteResource, 0);
  226. }
  227. if( nas == NERR_Success )
  228. {
  229. return TRUE; // indicate success
  230. }
  231. SetLastError(nas);
  232. return FALSE;
  233. }
  234. void
  235. InitLsaString(
  236. PLSA_UNICODE_STRING LsaString, // i/o- pointer to LSA string to initialize
  237. LPWSTR String // in - value to initialize LSA string to
  238. )
  239. {
  240. DWORD StringLength;
  241. if( String == NULL )
  242. {
  243. LsaString->Buffer = NULL;
  244. LsaString->Length = 0;
  245. LsaString->MaximumLength = 0;
  246. }
  247. else
  248. {
  249. StringLength = lstrlenW(String);
  250. LsaString->Buffer = String;
  251. LsaString->Length = (USHORT) StringLength * sizeof(WCHAR);
  252. LsaString->MaximumLength = (USHORT) (StringLength + 1) * sizeof(WCHAR);
  253. }
  254. }
  255. BOOL
  256. GetDomainSid(
  257. LPWSTR PrimaryDC, // in - domain controller of domain to acquire Sid
  258. PSID * pDomainSid // out- points to allocated Sid on success
  259. )
  260. {
  261. NET_API_STATUS nas;
  262. PUSER_MODALS_INFO_2 umi2 = NULL;
  263. DWORD dwSidSize;
  264. BOOL bSuccess = FALSE; // assume this function will fail
  265. *pDomainSid = NULL; // invalidate pointer
  266. __try {
  267. //
  268. // obtain the domain Sid from the PDC
  269. //
  270. nas = NetUserModalsGet(PrimaryDC, 2, (LPBYTE *)&umi2);
  271. if(nas != NERR_Success) __leave;
  272. //
  273. // if the Sid is valid, obtain the size of the Sid
  274. //
  275. if(!IsValidSid(umi2->usrmod2_domain_id)) __leave;
  276. dwSidSize = GetLengthSid(umi2->usrmod2_domain_id);
  277. //
  278. // allocate storage and copy the Sid
  279. //
  280. *pDomainSid = LocalAlloc(LPTR, dwSidSize);
  281. if(*pDomainSid == NULL) __leave;
  282. if(!CopySid(dwSidSize, *pDomainSid, umi2->usrmod2_domain_id)) __leave;
  283. bSuccess = TRUE; // indicate success
  284. } // try
  285. __finally
  286. {
  287. if(umi2 != NULL)
  288. {
  289. NetApiBufferFree(umi2);
  290. }
  291. if(!bSuccess)
  292. {
  293. //
  294. // if the function failed, free memory and indicate result code
  295. //
  296. if(*pDomainSid != NULL)
  297. {
  298. FreeSid(*pDomainSid);
  299. *pDomainSid = NULL;
  300. }
  301. if( nas != NERR_Success )
  302. {
  303. SetLastError(nas);
  304. }
  305. }
  306. } // finally
  307. return bSuccess;
  308. }
  309. NTSTATUS
  310. OpenPolicy(
  311. LPWSTR ComputerName, // in - computer name
  312. DWORD DesiredAccess, // in - access rights needed for policy
  313. PLSA_HANDLE PolicyHandle // out- LSA handle
  314. )
  315. {
  316. LSA_OBJECT_ATTRIBUTES ObjectAttributes;
  317. LSA_UNICODE_STRING ComputerString;
  318. PLSA_UNICODE_STRING Computer = NULL;
  319. LPWSTR NewComputerName;
  320. NewComputerName = (WCHAR*)LocalAlloc(LPTR,
  321. (MAX_COMPUTERNAME_LENGTH+3)*sizeof(WCHAR));
  322. if (!NewComputerName)
  323. return STATUS_NO_MEMORY;
  324. //
  325. // Prepend some backslashes to the computer name so that
  326. // this will work on NT 3.51
  327. //
  328. lstrcpy(NewComputerName,L"\\\\");
  329. lstrcat(NewComputerName,ComputerName);
  330. lstrcpy(NewComputerName,ComputerName);
  331. //
  332. // Always initialize the object attributes to all zeroes
  333. //
  334. ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
  335. if(ComputerName != NULL)
  336. {
  337. //
  338. // Make a LSA_UNICODE_STRING out of the LPWSTR passed in
  339. //
  340. InitLsaString(&ComputerString, NewComputerName);
  341. Computer = &ComputerString;
  342. }
  343. //
  344. // Attempt to open the policy
  345. //
  346. return LsaOpenPolicy(Computer,&ObjectAttributes,DesiredAccess,PolicyHandle);
  347. }
  348. /*++
  349. This function sets the Primary Domain for the workstation.
  350. To join the workstation to a Workgroup, ppdi.Name should be the name of
  351. the Workgroup and ppdi.Sid should be NULL.
  352. --*/
  353. NTSTATUS
  354. SetPrimaryDomain(
  355. LSA_HANDLE PolicyHandle, // in -policy handle for computer
  356. PSID DomainSid, // in - sid for new domain
  357. LPWSTR TrustedDomainName // in - name of new domain
  358. )
  359. {
  360. POLICY_PRIMARY_DOMAIN_INFO ppdi;
  361. InitLsaString(&ppdi.Name, TrustedDomainName);
  362. ppdi.Sid = DomainSid;
  363. return LsaSetInformationPolicy(PolicyHandle,PolicyPrimaryDomainInformation,&ppdi);
  364. }
  365. // This function removes the information from the domain the computer used to
  366. // be a member of
  367. void
  368. QueryWorkstationTrustedDomainInfo(
  369. LSA_HANDLE PolicyHandle, // in - policy handle for computer
  370. PSID DomainSid, // in - SID for new domain the computer is member of
  371. BOOL bNoChange // in - flag indicating whether to write changes
  372. )
  373. {
  374. // This function is not currently used.
  375. NTSTATUS Status;
  376. LSA_ENUMERATION_HANDLE h = 0;
  377. LSA_TRUST_INFORMATION * ti = NULL;
  378. ULONG count;
  379. Status = LsaEnumerateTrustedDomains(PolicyHandle,&h,(void**)&ti,50000,&count);
  380. if ( Status == STATUS_SUCCESS )
  381. {
  382. for ( UINT i = 0 ; i < count ; i++ )
  383. {
  384. if ( !bNoChange && !EqualSid(DomainSid,ti[i].Sid) )
  385. {
  386. // Remove the old trust
  387. Status = LsaDeleteTrustedDomain(PolicyHandle,ti[i].Sid);
  388. if ( Status != STATUS_SUCCESS )
  389. {
  390. }
  391. }
  392. }
  393. LsaFreeMemory(ti);
  394. }
  395. else
  396. {
  397. }
  398. }
  399. /*++
  400. This function manipulates the trust associated with the supplied
  401. DomainSid.
  402. If the domain trust does not exist, it is created with the
  403. specified password. In this case, the supplied PolicyHandle must
  404. have been opened with POLICY_TRUST_ADMIN and POLICY_CREATE_SECRET
  405. access to the policy object.
  406. --*/
  407. NTSTATUS
  408. SetWorkstationTrustedDomainInfo(
  409. LSA_HANDLE PolicyHandle, // in - policy handle
  410. PSID DomainSid, // in - Sid of domain to manipulate
  411. LPWSTR TrustedDomainName, // in - trusted domain name to add/update
  412. LPWSTR Password, // in - new trust password for trusted domain
  413. LPWSTR errOut // out- error text if function fails
  414. )
  415. {
  416. LSA_UNICODE_STRING LsaPassword;
  417. LSA_UNICODE_STRING KeyName;
  418. LSA_UNICODE_STRING LsaDomainName;
  419. DWORD cchDomainName; // number of chars in TrustedDomainName
  420. NTSTATUS Status;
  421. InitLsaString(&LsaDomainName, TrustedDomainName);
  422. //
  423. // ...convert TrustedDomainName to uppercase...
  424. //
  425. cchDomainName = LsaDomainName.Length / sizeof(WCHAR);
  426. while(cchDomainName--)
  427. {
  428. LsaDomainName.Buffer[cchDomainName] = towupper(LsaDomainName.Buffer[cchDomainName]);
  429. }
  430. //
  431. // ...create the trusted domain object
  432. //
  433. Status = LsaSetTrustedDomainInformation(
  434. PolicyHandle,
  435. DomainSid,
  436. TrustedDomainNameInformation,
  437. &LsaDomainName
  438. );
  439. if(Status == STATUS_OBJECT_NAME_COLLISION)
  440. {
  441. //printf("LsaSetTrustedDomainInformation: Name Collision (ok)\n");
  442. }
  443. else if (Status != STATUS_SUCCESS)
  444. {
  445. err.SysMsgWrite(ErrE,LsaNtStatusToWinError(Status),DCT_MSG_LSA_OPERATION_FAILED_SD,L"LsaSetTrustedDomainInformation", Status);
  446. return RTN_ERROR;
  447. }
  448. InitLsaString(&KeyName, L"$MACHINE.ACC");
  449. InitLsaString(&LsaPassword, Password);
  450. //
  451. // Set the machine password
  452. //
  453. Status = LsaStorePrivateData(
  454. PolicyHandle,
  455. &KeyName,
  456. &LsaPassword
  457. );
  458. if(Status != STATUS_SUCCESS)
  459. {
  460. err.SysMsgWrite(ErrE,LsaNtStatusToWinError(Status),DCT_MSG_LSA_OPERATION_FAILED_SD,L"LsaStorePrivateData", Status);
  461. return RTN_ERROR;
  462. }
  463. return STATUS_SUCCESS;
  464. }