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.

550 lines
13 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. service.c
  5. Abstract:
  6. This file provides access to the service control
  7. manager for starting, stopping, adding, and removing
  8. services.
  9. Environment:
  10. WIN32 User Mode
  11. Author:
  12. Wesley Witt (wesw) 17-Feb-1996
  13. --*/
  14. #include <nt.h>
  15. #include <ntrtl.h>
  16. #include <nturtl.h>
  17. #include "wizard.h"
  18. #include <ntsecapi.h>
  19. #include <lm.h>
  20. NTSTATUS
  21. OpenPolicy(
  22. LPWSTR ServerName, // machine to open policy on (Unicode)
  23. DWORD DesiredAccess, // desired access to policy
  24. PLSA_HANDLE PolicyHandle // resultant policy handle
  25. );
  26. BOOL
  27. GetAccountSid(
  28. LPTSTR SystemName, // where to lookup account
  29. LPTSTR AccountName, // account of interest
  30. PSID *Sid // resultant buffer containing SID
  31. );
  32. NTSTATUS
  33. SetPrivilegeOnAccount(
  34. LSA_HANDLE PolicyHandle, // open policy handle
  35. PSID AccountSid, // SID to grant privilege to
  36. LPWSTR PrivilegeName, // privilege to grant (Unicode)
  37. BOOL bEnable // enable or disable
  38. );
  39. void
  40. InitLsaString(
  41. PLSA_UNICODE_STRING LsaString, // destination
  42. LPWSTR String // source (Unicode)
  43. );
  44. void
  45. DisplayNtStatus(
  46. LPSTR szAPI, // pointer to function name (ANSI)
  47. NTSTATUS Status // NTSTATUS error value
  48. );
  49. void
  50. DisplayWinError(
  51. LPSTR szAPI, // pointer to function name (ANSI)
  52. DWORD WinError // DWORD WinError
  53. );
  54. #define RTN_OK 0
  55. #define RTN_USAGE 1
  56. #define RTN_ERROR 13
  57. //
  58. // If you have the ddk, include ntstatus.h.
  59. //
  60. #ifndef STATUS_SUCCESS
  61. #define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
  62. #endif
  63. BOOL
  64. GetDefaultDomainName(
  65. LPWSTR DomainName
  66. )
  67. {
  68. OBJECT_ATTRIBUTES ObjectAttributes;
  69. NTSTATUS NtStatus;
  70. DWORD err = 0;
  71. LSA_HANDLE LsaPolicyHandle = NULL;
  72. PPOLICY_ACCOUNT_DOMAIN_INFO DomainInfo = NULL;
  73. //
  74. // Open a handle to the local machine's LSA policy object.
  75. //
  76. InitializeObjectAttributes( &ObjectAttributes, // object attributes
  77. NULL, // name
  78. 0L, // attributes
  79. NULL, // root directory
  80. NULL ); // security descriptor
  81. NtStatus = LsaOpenPolicy( NULL, // system name
  82. &ObjectAttributes, // object attributes
  83. POLICY_EXECUTE, // access mask
  84. &LsaPolicyHandle ); // policy handle
  85. if( !NT_SUCCESS( NtStatus ) )
  86. {
  87. return FALSE;
  88. }
  89. //
  90. // Query the domain information from the policy object.
  91. //
  92. NtStatus = LsaQueryInformationPolicy( LsaPolicyHandle,
  93. PolicyAccountDomainInformation,
  94. (PVOID *) &DomainInfo );
  95. if (!NT_SUCCESS(NtStatus))
  96. {
  97. LsaClose(LsaPolicyHandle);
  98. return FALSE;
  99. }
  100. (void) LsaClose(LsaPolicyHandle);
  101. //
  102. // Copy the domain name into our cache, and
  103. //
  104. CopyMemory( DomainName,
  105. DomainInfo->DomainName.Buffer,
  106. DomainInfo->DomainName.Length );
  107. //
  108. // Null terminate it appropriately
  109. //
  110. DomainName[DomainInfo->DomainName.Length / sizeof(WCHAR)] = L'\0';
  111. //
  112. // Clean up
  113. //
  114. LsaFreeMemory( (PVOID)DomainInfo );
  115. return TRUE;
  116. }
  117. LPWSTR
  118. GetMachineName(
  119. LPWSTR AccountName
  120. )
  121. {
  122. LSA_HANDLE PolicyHandle = NULL;
  123. WCHAR DomainName[128];
  124. WCHAR LocalComputerName[128];
  125. LPWSTR MachineName = NULL;
  126. LPWSTR p;
  127. LPWSTR DCName = NULL;
  128. NET_API_STATUS NetStatus;
  129. UNICODE_STRING NameStrings;
  130. PLSA_REFERENCED_DOMAIN_LIST ReferencedDomains = NULL;
  131. PLSA_TRANSLATED_SID LsaSids = NULL;
  132. PUSER_MODALS_INFO_1 Modals = NULL;
  133. DWORD Size;
  134. NTSTATUS Status;
  135. //
  136. // get the domain name
  137. //
  138. p = wcschr( AccountName, L'\\' );
  139. if (p) {
  140. *p = 0;
  141. wcscpy( DomainName, AccountName );
  142. *p = L'\\';
  143. } else {
  144. wcscpy( DomainName, AccountName );
  145. }
  146. //
  147. // Open the policy on the target machine.
  148. //
  149. Status = OpenPolicy(
  150. NULL,
  151. POLICY_CREATE_ACCOUNT | POLICY_LOOKUP_NAMES,
  152. &PolicyHandle
  153. );
  154. if (Status != STATUS_SUCCESS) {
  155. goto exit;
  156. }
  157. //
  158. // lookup the domain name for the account
  159. //
  160. InitLsaString( &NameStrings, AccountName );
  161. Status = LsaLookupNames(
  162. PolicyHandle,
  163. 1,
  164. &NameStrings,
  165. &ReferencedDomains,
  166. &LsaSids
  167. );
  168. if (Status != STATUS_SUCCESS) {
  169. goto exit;
  170. }
  171. //
  172. // get the local computer name
  173. //
  174. Size = sizeof(LocalComputerName);
  175. if (!GetComputerName( LocalComputerName, &Size )) {
  176. goto exit;
  177. }
  178. //
  179. // see if we are tring to set a local account
  180. //
  181. if (wcscmp( LocalComputerName, ReferencedDomains->Domains->Name.Buffer ) != 0) {
  182. //
  183. // see what part of the domain we are attempting to set
  184. //
  185. NetStatus = NetUserModalsGet( NULL, 1, (LPBYTE*) &Modals );
  186. if (NetStatus != NERR_Success) {
  187. goto exit;
  188. }
  189. if (Modals->usrmod1_role != UAS_ROLE_PRIMARY) {
  190. //
  191. // we know we are remote, so get the real dc name
  192. //
  193. NetStatus = NetGetDCName( NULL, DomainName, (LPBYTE*) &DCName );
  194. if (NetStatus != NERR_Success) {
  195. goto exit;
  196. }
  197. MachineName = StringDup( DCName );
  198. }
  199. }
  200. exit:
  201. if (Modals) {
  202. NetApiBufferFree( Modals );
  203. }
  204. if (DCName) {
  205. NetApiBufferFree( DCName );
  206. }
  207. if (ReferencedDomains) {
  208. LsaFreeMemory( ReferencedDomains );
  209. }
  210. if (LsaSids) {
  211. LsaFreeMemory( LsaSids );
  212. }
  213. if (PolicyHandle) {
  214. LsaClose( PolicyHandle );
  215. }
  216. return MachineName;
  217. }
  218. DWORD
  219. SetServiceSecurity(
  220. LPWSTR AccountName
  221. )
  222. {
  223. LSA_HANDLE PolicyHandle;
  224. PSID pSid;
  225. NTSTATUS Status;
  226. int iRetVal=RTN_ERROR;
  227. LPWSTR MachineName;
  228. WCHAR NewAccountName[512];
  229. if (AccountName[0] == L'.') {
  230. if (GetDefaultDomainName( NewAccountName )) {
  231. wcscat( NewAccountName, &AccountName[1] );
  232. AccountName = NewAccountName;
  233. }
  234. }
  235. //
  236. // try to get the correct machine name
  237. //
  238. MachineName = GetMachineName( AccountName );
  239. //
  240. // Open the policy on the target machine.
  241. //
  242. Status = OpenPolicy(
  243. MachineName,
  244. POLICY_CREATE_ACCOUNT | POLICY_LOOKUP_NAMES,
  245. &PolicyHandle
  246. );
  247. if (Status != STATUS_SUCCESS) {
  248. return RTN_ERROR;
  249. }
  250. //
  251. // Obtain the SID of the user/group.
  252. // Note that we could target a specific machine, but we don't.
  253. // Specifying NULL for target machine searches for the SID in the
  254. // following order: well-known, Built-in and local, primary domain,
  255. // trusted domains.
  256. //
  257. if(GetAccountSid(
  258. MachineName, // target machine
  259. AccountName,// account to obtain SID
  260. &pSid // buffer to allocate to contain resultant SID
  261. )) {
  262. //
  263. // We only grant the privilege if we succeeded in obtaining the
  264. // SID. We can actually add SIDs which cannot be looked up, but
  265. // looking up the SID is a good sanity check which is suitable for
  266. // most cases.
  267. //
  268. // Grant the SeServiceLogonRight to users represented by pSid.
  269. //
  270. if((Status=SetPrivilegeOnAccount(
  271. PolicyHandle, // policy handle
  272. pSid, // SID to grant privilege
  273. L"SeServiceLogonRight", // Unicode privilege
  274. TRUE // enable the privilege
  275. )) == STATUS_SUCCESS) {
  276. iRetVal=RTN_OK;
  277. }
  278. }
  279. //
  280. // Close the policy handle.
  281. //
  282. LsaClose(PolicyHandle);
  283. //
  284. // Free memory allocated for SID.
  285. //
  286. if(pSid != NULL) MemFree(pSid);
  287. return iRetVal;
  288. }
  289. void
  290. InitLsaString(
  291. PLSA_UNICODE_STRING LsaString,
  292. LPWSTR String
  293. )
  294. {
  295. DWORD StringLength;
  296. if (String == NULL) {
  297. LsaString->Buffer = NULL;
  298. LsaString->Length = 0;
  299. LsaString->MaximumLength = 0;
  300. return;
  301. }
  302. StringLength = wcslen(String);
  303. LsaString->Buffer = String;
  304. LsaString->Length = (USHORT) StringLength * sizeof(WCHAR);
  305. LsaString->MaximumLength=(USHORT)(StringLength+1) * sizeof(WCHAR);
  306. }
  307. NTSTATUS
  308. OpenPolicy(
  309. LPWSTR ServerName,
  310. DWORD DesiredAccess,
  311. PLSA_HANDLE PolicyHandle
  312. )
  313. {
  314. LSA_OBJECT_ATTRIBUTES ObjectAttributes;
  315. LSA_UNICODE_STRING ServerString;
  316. PLSA_UNICODE_STRING Server = NULL;
  317. //
  318. // Always initialize the object attributes to all zeroes.
  319. //
  320. ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
  321. if (ServerName != NULL) {
  322. //
  323. // Make a LSA_UNICODE_STRING out of the LPWSTR passed in
  324. //
  325. InitLsaString(&ServerString, ServerName);
  326. Server = &ServerString;
  327. }
  328. //
  329. // Attempt to open the policy.
  330. //
  331. return LsaOpenPolicy(
  332. Server,
  333. &ObjectAttributes,
  334. DesiredAccess,
  335. PolicyHandle
  336. );
  337. }
  338. /*++
  339. This function attempts to obtain a SID representing the supplied
  340. account on the supplied system.
  341. If the function succeeds, the return value is TRUE. A buffer is
  342. allocated which contains the SID representing the supplied account.
  343. This buffer should be freed when it is no longer needed by calling
  344. HeapFree(GetProcessHeap(), 0, buffer)
  345. If the function fails, the return value is FALSE. Call GetLastError()
  346. to obtain extended error information.
  347. --*/
  348. BOOL
  349. GetAccountSid(
  350. LPTSTR SystemName,
  351. LPTSTR AccountName,
  352. PSID *Sid
  353. )
  354. {
  355. LPTSTR ReferencedDomain=NULL;
  356. DWORD cbSid=128; // initial allocation attempt
  357. DWORD cbReferencedDomain=32; // initial allocation size
  358. SID_NAME_USE peUse;
  359. BOOL bSuccess=FALSE; // assume this function will fail
  360. __try {
  361. //
  362. // initial memory allocations
  363. //
  364. if((*Sid=MemAlloc(cbSid)) == NULL) __leave;
  365. if((ReferencedDomain=MemAlloc(cbReferencedDomain)) == NULL) __leave;
  366. //
  367. // Obtain the SID of the specified account on the specified system.
  368. //
  369. while(!LookupAccountName(
  370. SystemName, // machine to lookup account on
  371. AccountName, // account to lookup
  372. *Sid, // SID of interest
  373. &cbSid, // size of SID
  374. ReferencedDomain, // domain account was found on
  375. &cbReferencedDomain,
  376. &peUse
  377. )) {
  378. if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
  379. //
  380. // reallocate memory
  381. //
  382. if((*Sid=HeapReAlloc(
  383. GetProcessHeap(),
  384. 0,
  385. *Sid,
  386. cbSid
  387. )) == NULL) __leave;
  388. if((ReferencedDomain=HeapReAlloc(
  389. GetProcessHeap(),
  390. 0,
  391. ReferencedDomain,
  392. cbReferencedDomain
  393. )) == NULL) __leave;
  394. }
  395. else __leave;
  396. }
  397. //
  398. // Indicate success.
  399. //
  400. bSuccess=TRUE;
  401. } // finally
  402. __finally {
  403. //
  404. // Cleanup and indicate failure, if appropriate.
  405. //
  406. MemFree(ReferencedDomain);
  407. if(!bSuccess) {
  408. if(*Sid != NULL) {
  409. MemFree(*Sid);
  410. *Sid = NULL;
  411. }
  412. }
  413. } // finally
  414. return bSuccess;
  415. }
  416. NTSTATUS
  417. SetPrivilegeOnAccount(
  418. LSA_HANDLE PolicyHandle, // open policy handle
  419. PSID AccountSid, // SID to grant privilege to
  420. LPWSTR PrivilegeName, // privilege to grant (Unicode)
  421. BOOL bEnable // enable or disable
  422. )
  423. {
  424. LSA_UNICODE_STRING PrivilegeString;
  425. //
  426. // Create a LSA_UNICODE_STRING for the privilege name.
  427. //
  428. InitLsaString(&PrivilegeString, PrivilegeName);
  429. //
  430. // grant or revoke the privilege, accordingly
  431. //
  432. if(bEnable) {
  433. return LsaAddAccountRights(
  434. PolicyHandle, // open policy handle
  435. AccountSid, // target SID
  436. &PrivilegeString, // privileges
  437. 1 // privilege count
  438. );
  439. }
  440. else {
  441. return LsaRemoveAccountRights(
  442. PolicyHandle, // open policy handle
  443. AccountSid, // target SID
  444. FALSE, // do not disable all rights
  445. &PrivilegeString, // privileges
  446. 1 // privilege count
  447. );
  448. }
  449. }