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.

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