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.

981 lines
24 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. LockAPI.cxx
  5. Abstract:
  6. This file contains the Service Controller's lock APIs:
  7. RLockServiceDatabase
  8. RQueryServiceLockStatusW
  9. RUnlockServiceDatabase
  10. SC_RPC_LOCK_rundown
  11. Author:
  12. John Rogers (JohnRo) 14-Apr-1992
  13. Environment:
  14. User Mode - Win32
  15. Revision History:
  16. 26-Mar-1992 danl
  17. Created the stubbed out version for RPC.
  18. 17-Apr-1992 JohnRo
  19. Split lock APIs out from config API stubs in CfgAPI.c.
  20. Did initial coding of all lock APIs.
  21. 22-Apr-1992 JohnRo
  22. Made changes suggested by PC-LINT.
  23. Use SC_LOG0(), etc.
  24. 06-Aug-1992 ritaw
  25. Completed the code.
  26. --*/
  27. //
  28. // INCLUDES
  29. //
  30. #include "precomp.hxx"
  31. extern "C" {
  32. #include <ntlsa.h> // LsaLookupSids
  33. }
  34. #include <stdlib.h> // wide character c runtimes.
  35. #include <tstr.h> // Unicode string macros
  36. #include <sclib.h> // ScCopyStringToBufferW().
  37. #include <time.h> // time().
  38. #include "account.h" // SCDOMAIN_USERNAME_SEPARATOR
  39. #include "lockapi.h" // ScLockDatabase
  40. #include "scsec.h" // ScGetClientSid
  41. #define SC_MANAGER_USERNAME L".\\NT Service Control Manager"
  42. #define ScDatabaseNamesMatch(a,b) (_wcsicmp( (a), (b) ) == 0)
  43. // Macros to lock and unlock the lock list:
  44. #define LOCK_API_LOCK_LIST_SHARED( comment ) \
  45. { \
  46. ScServiceRecordLock.GetShared(); \
  47. }
  48. #define LOCK_API_LOCK_LIST_EXCLUSIVE( comment ) \
  49. { \
  50. ScServiceRecordLock.GetExclusive(); \
  51. }
  52. #define UNLOCK_API_LOCK_LIST( comment ) \
  53. { \
  54. ScServiceRecordLock.Release(); \
  55. }
  56. typedef struct _API_LOCK {
  57. struct _API_LOCK *Prev;
  58. struct _API_LOCK *Next;
  59. DWORD Signature; // Must be API_LOCK_SIGNATURE.
  60. LPWSTR DatabaseName;
  61. time_t TimeWhenLocked; // seconds since 1970.
  62. PSID LockOwnerSid; // SID. It is NULL if SC
  63. // Manager grabbed the lock
  64. } API_LOCK, *PAPI_LOCK, *LPAPI_LOCK;
  65. #define API_LOCK_SIGNATURE 0x4C697041 // "ApiL" in ASCII.
  66. //
  67. // List of API_LOCK structures. This list is locked by the macros above.
  68. //
  69. LPAPI_LOCK ScGlobalApiLockList = NULL;
  70. DWORD
  71. ScCreateLock(
  72. IN BOOL IsServiceController,
  73. IN LPWSTR DatabaseName,
  74. IN PSID UserSid OPTIONAL,
  75. OUT LPSC_RPC_LOCK lpLock
  76. );
  77. #if DBG
  78. VOID
  79. ScDumpLockList(
  80. VOID
  81. );
  82. #endif
  83. LPAPI_LOCK
  84. ScFindApiLockForDatabase(
  85. IN LPWSTR DatabaseName
  86. )
  87. /*++
  88. Routine Description:
  89. Arguments:
  90. Return Value:
  91. Pointer to entry in the list (or NULL if not found).
  92. Note:
  93. The caller must have a lock (shared or exclusive) for the api lock list.
  94. --*/
  95. {
  96. LPAPI_LOCK apiLockEntry;
  97. apiLockEntry = ScGlobalApiLockList;
  98. while (apiLockEntry != NULL) {
  99. SC_ASSERT( apiLockEntry->Signature == API_LOCK_SIGNATURE );
  100. if (ScDatabaseNamesMatch( DatabaseName, apiLockEntry->DatabaseName) ) {
  101. return (apiLockEntry);
  102. }
  103. apiLockEntry = apiLockEntry->Next;
  104. }
  105. return (NULL);
  106. }
  107. DWORD
  108. RLockServiceDatabase(
  109. IN SC_RPC_HANDLE hSCManager,
  110. OUT LPSC_RPC_LOCK lpLock
  111. )
  112. /*++
  113. Routine Description:
  114. Arguments:
  115. Return Value:
  116. --*/
  117. {
  118. DWORD status;
  119. LPSC_HANDLE_STRUCT serviceHandleStruct = (LPSC_HANDLE_STRUCT) hSCManager;
  120. SC_ASSERT( lpLock != NULL );
  121. *lpLock = NULL;
  122. if ( !ScIsValidScManagerHandle( hSCManager ) ) {
  123. return (ERROR_INVALID_HANDLE);
  124. }
  125. //
  126. // Do we have permission to do this?
  127. //
  128. if ( !RtlAreAllAccessesGranted(
  129. serviceHandleStruct->AccessGranted,
  130. SC_MANAGER_LOCK
  131. )) {
  132. return (ERROR_ACCESS_DENIED);
  133. }
  134. status = ScLockDatabase(
  135. FALSE,
  136. serviceHandleStruct->Type.ScManagerObject.DatabaseName,
  137. lpLock
  138. );
  139. SC_LOG0( LOCK_API, "Database Lock is ON (from API)\n");
  140. return status;
  141. }
  142. DWORD
  143. RQueryServiceLockStatusW(
  144. IN SC_RPC_HANDLE hSCManager,
  145. OUT LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
  146. IN DWORD cbBufSize,
  147. OUT LPDWORD pcbBytesNeeded
  148. )
  149. /*++
  150. Routine Description:
  151. Arguments:
  152. Return Value:
  153. --*/
  154. {
  155. DWORD status;
  156. LPAPI_LOCK apiLockEntry;
  157. DWORD allocSize;
  158. LPWSTR databaseName;
  159. LPWSTR endOfVariableData;
  160. LPWSTR fixedDataEnd;
  161. LPWSTR lockOwner;
  162. DWORD lockOwnerSize;
  163. LPSC_HANDLE_STRUCT serviceHandleStruct = (LPSC_HANDLE_STRUCT) hSCManager;
  164. if ( !ScIsValidScManagerHandle( hSCManager ) ) {
  165. return (ERROR_INVALID_HANDLE);
  166. } else if (lpLockStatus == NULL) {
  167. return (ERROR_INVALID_PARAMETER);
  168. } else if (pcbBytesNeeded == NULL) {
  169. return (ERROR_INVALID_PARAMETER);
  170. }
  171. //
  172. // Do we have permission to do this?
  173. //
  174. if ( !RtlAreAllAccessesGranted(
  175. serviceHandleStruct->AccessGranted,
  176. SC_MANAGER_QUERY_LOCK_STATUS
  177. )) {
  178. return (ERROR_ACCESS_DENIED);
  179. }
  180. LOCK_API_LOCK_LIST_SHARED( "RQueryServiceLockStatusW start" );
  181. databaseName = serviceHandleStruct->Type.ScManagerObject.DatabaseName;
  182. SC_ASSERT( databaseName != NULL );
  183. apiLockEntry = ScFindApiLockForDatabase( databaseName );
  184. if (apiLockEntry == NULL) {
  185. allocSize = sizeof(QUERY_SERVICE_LOCK_STATUSW) + sizeof(WCHAR);
  186. *pcbBytesNeeded = allocSize;
  187. if (cbBufSize < allocSize) {
  188. UNLOCK_API_LOCK_LIST( "RQueryServiceLockStatusW too small" );
  189. return (ERROR_INSUFFICIENT_BUFFER);
  190. }
  191. lpLockStatus->fIsLocked = FALSE;
  192. fixedDataEnd = (LPWSTR) (lpLockStatus + 1);
  193. endOfVariableData = (LPWSTR) ((LPBYTE)lpLockStatus + allocSize);
  194. if (! ScCopyStringToBufferW (
  195. NULL,
  196. 0,
  197. fixedDataEnd,
  198. &endOfVariableData,
  199. &lpLockStatus->lpLockOwner,
  200. NULL
  201. )) {
  202. SC_ASSERT( FALSE );
  203. }
  204. lpLockStatus->dwLockDuration = 0;
  205. UNLOCK_API_LOCK_LIST( "RQueryServiceLockStatusW not found" );
  206. return (NO_ERROR);
  207. }
  208. SC_ASSERT( apiLockEntry->Signature == API_LOCK_SIGNATURE );
  209. status = ScGetLockOwner(
  210. apiLockEntry->LockOwnerSid,
  211. &lockOwner
  212. );
  213. if (status != NO_ERROR) {
  214. UNLOCK_API_LOCK_LIST( "RQueryServiceLockStatusW failed get owner" );
  215. return status;
  216. }
  217. lockOwnerSize = (DWORD) WCSSIZE(lockOwner);
  218. SC_ASSERT( lockOwnerSize > 2 ); // min is ".\x" (domain\user).
  219. allocSize = sizeof(QUERY_SERVICE_LOCK_STATUSW) + lockOwnerSize;
  220. *pcbBytesNeeded = allocSize;
  221. if (allocSize > cbBufSize) {
  222. LocalFree(lockOwner);
  223. UNLOCK_API_LOCK_LIST( "RQueryServiceLockStatusW too small" );
  224. return (ERROR_INSUFFICIENT_BUFFER);
  225. }
  226. //
  227. // Build the QUERY_SERVICE_LOCK_STATUS structure.
  228. //
  229. lpLockStatus->fIsLocked = TRUE;
  230. lpLockStatus->dwLockDuration =
  231. (DWORD)(time(NULL) - apiLockEntry->TimeWhenLocked);
  232. fixedDataEnd = (LPWSTR) (lpLockStatus + 1);
  233. endOfVariableData = (LPWSTR) ((LPBYTE)lpLockStatus + allocSize);
  234. if (! ScCopyStringToBufferW (
  235. lockOwner,
  236. (DWORD) wcslen(lockOwner),
  237. fixedDataEnd,
  238. &endOfVariableData,
  239. &lpLockStatus->lpLockOwner,
  240. NULL
  241. )) {
  242. SC_ASSERT( FALSE );
  243. }
  244. LocalFree(lockOwner);
  245. UNLOCK_API_LOCK_LIST( "RQueryServiceLockStatusW done" );
  246. return (NO_ERROR);
  247. }
  248. DWORD
  249. RUnlockServiceDatabase(
  250. IN OUT LPSC_RPC_LOCK lpLock
  251. )
  252. /*++
  253. Routine Description:
  254. Arguments:
  255. Return Value:
  256. --*/
  257. {
  258. LPAPI_LOCK apiLockEntry;
  259. if (lpLock == NULL) {
  260. return (ERROR_INVALID_SERVICE_LOCK);
  261. }
  262. apiLockEntry = * (LPAPI_LOCK *) (LPVOID) lpLock;
  263. if (apiLockEntry->Signature != API_LOCK_SIGNATURE) {
  264. SC_LOG1( ERROR, "RUnlockServiceDatabase: lock w/o signature at "
  265. FORMAT_LPVOID "\n", (LPVOID) lpLock );
  266. return (ERROR_INVALID_SERVICE_LOCK);
  267. }
  268. //
  269. // We're going to update the linked list, so keep other threads out.
  270. //
  271. LOCK_API_LOCK_LIST_EXCLUSIVE( "RUnlockServiceDatabase start" );
  272. //
  273. // Remove the entry from the lock list. This has the effect of
  274. // unlocking this database.
  275. //
  276. if (apiLockEntry->Prev != NULL) {
  277. apiLockEntry->Prev->Next = apiLockEntry->Next;
  278. }
  279. if (apiLockEntry->Next != NULL) {
  280. apiLockEntry->Next->Prev = apiLockEntry->Prev;
  281. }
  282. if ( (apiLockEntry->Next == NULL) && (apiLockEntry->Prev == NULL) ) {
  283. ScGlobalApiLockList = NULL;
  284. }
  285. //
  286. // Free the storage we allocated for this entry.
  287. //
  288. LocalFree( apiLockEntry );
  289. *lpLock = NULL;
  290. #if DBG
  291. ScDumpLockList();
  292. #endif
  293. //
  294. // OK, it's safe for other threads to muck with the lock list.
  295. //
  296. UNLOCK_API_LOCK_LIST( "RUnlockServiceDatabase done" );
  297. SC_LOG0( LOCK_API,"Database Lock is OFF (from API)\n");
  298. return(NO_ERROR);
  299. }
  300. VOID
  301. SC_RPC_LOCK_rundown(
  302. SC_RPC_LOCK lock
  303. )
  304. /*++
  305. Routine Description:
  306. This function is called by RPC when a connection is broken that had
  307. an outstanding context handle. The value of the context handle is
  308. passed in here so that we have an opportunity to clean up.
  309. Arguments:
  310. lock - This is the handle value of the context handle that is broken.
  311. Return Value:
  312. none.
  313. --*/
  314. {
  315. RUnlockServiceDatabase(&lock);
  316. }
  317. VOID
  318. ScUnlockDatabase(
  319. IN OUT LPSC_RPC_LOCK lpLock
  320. )
  321. /*++
  322. Routine Description:
  323. This function is called by internally by ScStartServiceAndDependencies
  324. to unlock the SC Manager database lock when it is done starting
  325. services.
  326. Arguments:
  327. lpLock - Supplies the address of the pointer to the lock structure.
  328. On output, the pointer is set to NULL.
  329. Return Value:
  330. None.
  331. --*/
  332. {
  333. RUnlockServiceDatabase(lpLock);
  334. }
  335. DWORD
  336. ScLockDatabase(
  337. IN BOOL IsServiceController,
  338. IN LPWSTR DatabaseName,
  339. OUT LPSC_RPC_LOCK lpLock
  340. )
  341. /*++
  342. Routine Description:
  343. This function grabs the external database lock which is used
  344. by setup programs to ensure serialization to the services'
  345. configuration.
  346. It is also called by the service controller itself from
  347. ScStartServiceAndDependencies. We need to grab the database lock
  348. internally when starting services so that setup programs know
  349. that when is an unsafe time to modify service configuration.
  350. When called by the service controller itself, the SID is not
  351. looked up.
  352. Arguments:
  353. IsServiceController - Supplies a flag which is TRUE if this routine
  354. is called by the service controller; FALSE all other times.
  355. DatabaseName - Supplies the name of the database which the lock
  356. is to be acquired.
  357. lpLock - Receives a pointer to the lock entry created.
  358. Return Value:
  359. NO_ERROR or reason for failure.
  360. --*/
  361. {
  362. DWORD status;
  363. LPAPI_LOCK apiLockEntry;
  364. PTOKEN_USER UserInfo = NULL;
  365. SC_ASSERT(DatabaseName != NULL);
  366. LOCK_API_LOCK_LIST_EXCLUSIVE( "ScLockDatabase start" );
  367. //
  368. // Check for another lock.
  369. //
  370. apiLockEntry = ScFindApiLockForDatabase(DatabaseName);
  371. if (apiLockEntry != NULL) {
  372. UNLOCK_API_LOCK_LIST( "ScLockDatabase already locked" );
  373. SC_LOG0(LOCK_API, "ScLockDatabase: Database is already locked\n");
  374. return ERROR_SERVICE_DATABASE_LOCKED;
  375. }
  376. if (! IsServiceController) {
  377. //
  378. // Get the caller's SID
  379. //
  380. if ((status = ScGetClientSid(
  381. &UserInfo
  382. )) != NO_ERROR) {
  383. UNLOCK_API_LOCK_LIST( "ScLockDatabase ScGetClientSid failed" );
  384. return status;
  385. }
  386. status = ScCreateLock(
  387. FALSE, // Non-ScManager caller to grab lock
  388. DatabaseName,
  389. UserInfo->User.Sid,
  390. lpLock
  391. );
  392. LocalFree(UserInfo);
  393. }
  394. else {
  395. status = ScCreateLock(
  396. TRUE, // ScManager caller to grab lock
  397. DatabaseName,
  398. NULL,
  399. lpLock
  400. );
  401. }
  402. #if DBG
  403. ScDumpLockList();
  404. #endif
  405. UNLOCK_API_LOCK_LIST("ScLockDatabase done");
  406. return status;
  407. }
  408. DWORD
  409. ScCreateLock(
  410. IN BOOL IsServiceController,
  411. IN LPWSTR DatabaseName,
  412. IN PSID UserSid OPTIONAL,
  413. OUT LPSC_RPC_LOCK lpLock
  414. )
  415. /*++
  416. Routine Description:
  417. This function is creates a lock entry, fills in the information about
  418. the nature of the lock and insert it into the lock list.
  419. Arguments:
  420. IsServiceController - Supplies a flag which is TRUE if this routine
  421. is called by the service controller; FALSE all other times.
  422. DatabaseName - Supplies the name of the database which the lock
  423. is to be acquired.
  424. UserSid - Supplies the SID of the caller to claim the lock. This
  425. is NULL if IsServiceController is TRUE.
  426. lpLock - Receives a pointer to the lock entry created.
  427. Return Value:
  428. NO_ERROR or reason for failure.
  429. --*/
  430. {
  431. NTSTATUS ntstatus;
  432. DWORD allocSize;
  433. LPAPI_LOCK newLockEntry;
  434. LPAPI_LOCK apiLockEntry;
  435. //
  436. // Build a structure to describe this lock.
  437. //
  438. if (IsServiceController) {
  439. allocSize = sizeof(API_LOCK) + (DWORD) WCSSIZE(DatabaseName);
  440. }
  441. else {
  442. if (! ARGUMENT_PRESENT(UserSid)) {
  443. SC_LOG0(ERROR, "ScCreateLock: UserSid is NULL!\n");
  444. SC_ASSERT(FALSE);
  445. return ERROR_GEN_FAILURE;
  446. }
  447. allocSize = sizeof(API_LOCK) + (DWORD) WCSSIZE(DatabaseName)
  448. + RtlLengthSid(UserSid);
  449. }
  450. newLockEntry = (LPAPI_LOCK) LocalAlloc( LMEM_ZEROINIT, (UINT) allocSize );
  451. if (newLockEntry == NULL) {
  452. SC_LOG1(ERROR,"ScCreateLock: Local Alloc FAILED "
  453. FORMAT_DWORD "\n", GetLastError());
  454. return (ERROR_NOT_ENOUGH_MEMORY);
  455. }
  456. SC_LOG3(LOCK_API,"ScCreateLock: alloc'ed " FORMAT_DWORD
  457. " bytes at " FORMAT_LPVOID " Sid-size " FORMAT_DWORD ".\n",
  458. allocSize, (LPVOID) newLockEntry,
  459. (UserSid) ? RtlLengthSid(UserSid) : 0);
  460. //
  461. // Fill in fields of new lock entry
  462. //
  463. newLockEntry->Signature = API_LOCK_SIGNATURE;
  464. newLockEntry->DatabaseName = (LPWSTR) (newLockEntry + 1);
  465. wcscpy(newLockEntry->DatabaseName, DatabaseName);
  466. if (ARGUMENT_PRESENT(UserSid)) {
  467. newLockEntry->LockOwnerSid = (PSID) ((DWORD_PTR) newLockEntry->DatabaseName +
  468. WCSSIZE(DatabaseName));
  469. SC_LOG1(LOCK_API, "ScCreateLock: Before RtlCopySid, bytes left "
  470. FORMAT_DWORD "\n", ((DWORD_PTR) newLockEntry + allocSize) -
  471. (DWORD_PTR) newLockEntry->LockOwnerSid);
  472. ntstatus = RtlCopySid(
  473. (ULONG)(((DWORD_PTR) newLockEntry + allocSize) - (DWORD_PTR) newLockEntry->LockOwnerSid),
  474. newLockEntry->LockOwnerSid,
  475. UserSid
  476. );
  477. if (! NT_SUCCESS(ntstatus)) {
  478. SC_LOG1(ERROR, "ScCreateLock: RtlCopySid failed " FORMAT_NTSTATUS
  479. "\n", ntstatus);
  480. LocalFree(newLockEntry);
  481. return RtlNtStatusToDosError(ntstatus);
  482. }
  483. }
  484. else {
  485. newLockEntry->LockOwnerSid = (PSID) NULL;
  486. }
  487. newLockEntry->TimeWhenLocked = (DWORD) time( NULL );
  488. //
  489. // Record this lock.
  490. //
  491. if (ScGlobalApiLockList != NULL) {
  492. //
  493. // List is not empty, so just add to end.
  494. //
  495. apiLockEntry = ScGlobalApiLockList;
  496. ADD_TO_LIST( apiLockEntry, newLockEntry );
  497. } else {
  498. //
  499. // List is empty, so start with this (new) entry.
  500. //
  501. ScGlobalApiLockList = newLockEntry;
  502. newLockEntry->Next = NULL;
  503. newLockEntry->Prev = NULL;
  504. }
  505. *lpLock = newLockEntry;
  506. return NO_ERROR;
  507. }
  508. DWORD
  509. ScGetLockOwner(
  510. IN PSID UserSid OPTIONAL,
  511. OUT LPWSTR *LockOwnerName
  512. )
  513. {
  514. DWORD status = NO_ERROR;
  515. NTSTATUS ntstatus;
  516. OBJECT_ATTRIBUTES ObjAttributes;
  517. LSA_HANDLE PolicyHandle;
  518. PLSA_REFERENCED_DOMAIN_LIST ReferencedDomain = NULL;
  519. PLSA_TRANSLATED_NAME Name = NULL;
  520. NT_PRODUCT_TYPE ProductType;
  521. if (! ARGUMENT_PRESENT(UserSid)) {
  522. *LockOwnerName = (LPWSTR)LocalAlloc(
  523. LMEM_ZEROINIT,
  524. WCSSIZE(SC_MANAGER_USERNAME)
  525. );
  526. if (*LockOwnerName == NULL) {
  527. SC_LOG1(ERROR, "ScGetLockOwner: LocalAlloc failed " FORMAT_DWORD
  528. "\n", GetLastError());
  529. return ERROR_NOT_ENOUGH_MEMORY;
  530. }
  531. wcscpy(*LockOwnerName, SC_MANAGER_USERNAME);
  532. return NO_ERROR;
  533. }
  534. //
  535. // Open a handle to the local security policy. Initialize the
  536. // objects attributes structure first.
  537. //
  538. InitializeObjectAttributes(
  539. &ObjAttributes,
  540. NULL,
  541. 0L,
  542. NULL,
  543. NULL
  544. );
  545. ntstatus = LsaOpenPolicy(
  546. NULL,
  547. &ObjAttributes,
  548. POLICY_LOOKUP_NAMES,
  549. &PolicyHandle
  550. );
  551. if (! NT_SUCCESS(ntstatus)) {
  552. SC_LOG(ERROR, "ScGetLockOwner: LsaOpenPolicy returned " FORMAT_NTSTATUS
  553. "\n", ntstatus);
  554. return RtlNtStatusToDosError(ntstatus);
  555. }
  556. //
  557. // Get the name of the specified SID
  558. //
  559. ntstatus = LsaLookupSids(
  560. PolicyHandle,
  561. 1,
  562. &UserSid,
  563. &ReferencedDomain,
  564. &Name
  565. );
  566. if (! NT_SUCCESS(ntstatus))
  567. {
  568. SC_LOG(ERROR, "ScGetLockOwner: LsaLookupNames returned " FORMAT_NTSTATUS
  569. "\n", ntstatus);
  570. status = RtlNtStatusToDosError(ntstatus);
  571. goto CleanExit;
  572. }
  573. if (ReferencedDomain == NULL || Name == NULL)
  574. {
  575. SC_LOG2(ERROR, "ScGetLockOwner: ReferencedDomain=%08lx, Name=%08lx\n",
  576. ReferencedDomain, Name);
  577. status = ERROR_GEN_FAILURE;
  578. goto CleanExit;
  579. }
  580. else
  581. {
  582. LPWSTR Ptr;
  583. if (Name->Use == SidTypeUnknown || Name->Use == SidTypeInvalid) {
  584. SC_LOG0(ERROR, "ScGetLockOwner: Sid is unknown or invalid\n");
  585. status = ERROR_GEN_FAILURE;
  586. goto CleanExit;
  587. }
  588. if (Name->DomainIndex < 0) {
  589. SC_LOG1(ERROR, "ScGetLockOwner: DomainIndex is negative %ld\n",
  590. Name->DomainIndex);
  591. status = ERROR_GEN_FAILURE;
  592. goto CleanExit;
  593. }
  594. if (ReferencedDomain->Entries == 0) {
  595. SC_LOG0(ERROR, "ScGetLockOwner: No ReferencedDomain entry\n");
  596. status = ERROR_GEN_FAILURE;
  597. goto CleanExit;
  598. }
  599. *LockOwnerName = (LPWSTR)LocalAlloc(
  600. LMEM_ZEROINIT,
  601. Name->Name.Length +
  602. ReferencedDomain->Domains[Name->DomainIndex].Name.Length +
  603. 2 * sizeof(WCHAR)
  604. );
  605. if (*LockOwnerName == NULL) {
  606. SC_LOG1(ERROR, "ScGetLockOwner: LocalAlloc failed " FORMAT_DWORD
  607. "\n", GetLastError());
  608. status = ERROR_NOT_ENOUGH_MEMORY;
  609. goto CleanExit;
  610. }
  611. if (! RtlGetNtProductType(&ProductType)) {
  612. status = GetLastError();
  613. SC_LOG1(ERROR, "ScGetLockOwner: RtlGetNtProductType failed "
  614. FORMAT_DWORD "\n", status);
  615. LocalFree(*LockOwnerName);
  616. goto CleanExit;
  617. }
  618. if (ProductType != NtProductLanManNt) {
  619. status = ScGetAccountDomainInfo();
  620. if (status != NO_ERROR) {
  621. LocalFree(*LockOwnerName);
  622. goto CleanExit;
  623. }
  624. if (RtlEqualUnicodeString(
  625. &(ReferencedDomain->Domains[Name->DomainIndex].Name),
  626. &ScAccountDomain,
  627. TRUE
  628. )
  629. ||
  630. RtlEqualUnicodeString(
  631. &(ReferencedDomain->Domains[Name->DomainIndex].Name),
  632. &ScComputerName,
  633. TRUE
  634. )
  635. ) {
  636. //
  637. // We are WinNT and the user who has the lock is logged on to
  638. // a local account. Convert the local domain name to "."
  639. //
  640. wcscpy(*LockOwnerName, SC_LOCAL_DOMAIN_NAME);
  641. }
  642. else {
  643. goto ReturnRefDomain;
  644. }
  645. }
  646. else {
  647. ReturnRefDomain:
  648. memcpy(
  649. *LockOwnerName,
  650. ReferencedDomain->Domains[Name->DomainIndex].Name.Buffer,
  651. ReferencedDomain->Domains[Name->DomainIndex].Name.Length
  652. );
  653. }
  654. Ptr = *LockOwnerName + wcslen(*LockOwnerName);
  655. *Ptr = SCDOMAIN_USERNAME_SEPARATOR;
  656. Ptr++;
  657. memcpy(
  658. Ptr,
  659. Name->Name.Buffer,
  660. Name->Name.Length
  661. );
  662. }
  663. CleanExit:
  664. if (ReferencedDomain != NULL) {
  665. LsaFreeMemory(ReferencedDomain);
  666. }
  667. if (Name != NULL) {
  668. LsaFreeMemory(Name);
  669. }
  670. LsaClose(PolicyHandle);
  671. return status;
  672. }
  673. #if DBG
  674. VOID
  675. ScDumpLockList(
  676. VOID
  677. )
  678. {
  679. LPAPI_LOCK LockEntry = ScGlobalApiLockList;
  680. LPWSTR LockOwner;
  681. if (LockEntry == NULL) {
  682. KdPrintEx((DPFLTR_SCSERVER_ID, DEBUG_LOCK_API, "\nLock list is NULL\n"));
  683. return;
  684. }
  685. KdPrintEx((DPFLTR_SCSERVER_ID, DEBUG_LOCK_API, "\nScDumpLockList:\n"));
  686. while (LockEntry != NULL) {
  687. if (ScGetLockOwner(LockEntry->LockOwnerSid, &LockOwner) == NO_ERROR) {
  688. KdPrintEx((DPFLTR_SCSERVER_ID,
  689. DEBUG_LOCK_API,
  690. "LockOwner: " FORMAT_LPWSTR "\n",
  691. LockOwner));
  692. KdPrintEx((DPFLTR_SCSERVER_ID,
  693. DEBUG_LOCK_API,
  694. "LockDuration: " FORMAT_DWORD "\n",
  695. ((DWORD)time(NULL)) - LockEntry->TimeWhenLocked));
  696. KdPrintEx((DPFLTR_SCSERVER_ID,
  697. DEBUG_LOCK_API,
  698. "LockDatabase: " FORMAT_LPWSTR "\n",
  699. LockEntry->DatabaseName));
  700. LocalFree(LockOwner);
  701. }
  702. LockEntry = LockEntry->Next;
  703. }
  704. }
  705. #endif