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.

2327 lines
58 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. groupman.cxx
  5. Abstract:
  6. Contains code for the Group List Database manager. This includes
  7. all the linked list routines. This file contains the following
  8. functions:
  9. ScGetOrderGroupList
  10. ScGetStandaloneGroupList
  11. ScGetUnresolvedDependList
  12. ScGetNamedGroupRecord
  13. ScCreateOrderGroupEntry
  14. ScAllocateGroupEntry
  15. ScCreateGroupMembership
  16. ScDeleteGroupMembership
  17. ScCreateRegistryGroupPointer
  18. ScDeleteRegistryGroupPointer
  19. ScCreateStandaloneGroup
  20. ScDeleteStandaloneGroup
  21. ScGenerateDependencies
  22. ScSetDependencyPointers
  23. ScResolveDependencyToService
  24. ScCreateDependencies
  25. ScCreateUnresolvedDepend
  26. ScDeleteUnresolvedDepend
  27. ScCreateDependRecord
  28. ScDeleteStartDependencies
  29. ScDeleteStopDependencies
  30. ScSetServiceDependList
  31. ScGetUniqueTag
  32. ScCompareVector
  33. ScGetDependencySize
  34. ScGetDependencyString
  35. ScDumpGroups
  36. ScDumpServiceDependencies
  37. Author:
  38. Dan Lafferty (danl) 04-Feb-1992
  39. Environment:
  40. User Mode -Win32
  41. Revision History:
  42. 22-Oct-1993 danl
  43. Created by splitting these functions out of dataman.c because it was
  44. getting too large.
  45. --*/
  46. //
  47. // INCLUDES
  48. //
  49. #include "precomp.hxx"
  50. #include <stdlib.h> // wide character c runtimes.
  51. #include <tstr.h> // Unicode string macros
  52. #include <ntrpcp.h> // MIDL_user_allocate
  53. #include <control.h> // SendControl
  54. #include "scconfig.h" // ScGenerateServiceDB,ScInitSecurityProcess
  55. #include "scsec.h" // ScCreateScServiceObject
  56. #include "account.h" // ScRemoveAccount
  57. #include <sclib.h> // ScImagePathsMatch().
  58. #include "bootcfg.h" // ScDeleteRegTree().
  59. #include <strarray.h> // ScWStrArraySize
  60. //
  61. // Defines
  62. //
  63. // Names of specially treated groups
  64. #define SC_GROUPNAME_TDI L"TDI"
  65. #define SC_GROUPNAME_PNP_TDI L"PNP_TDI"
  66. // A value that will not match any real pointer to a load order group
  67. #define SC_INVALID_GROUP ((LPLOAD_ORDER_GROUP)(DWORD_PTR) 0xFFFFFFFF)
  68. //
  69. // External Globals
  70. //
  71. //
  72. // TDI GROUP SPECIAL: The groups named TDI and PNP_TDI are treated
  73. // specially during dependency handling. This is done by remembering a
  74. // pointer to each of those groups, if it occurs in the group order list,
  75. // and checking against the remembered pointers during dependency
  76. // handling.
  77. //
  78. LPLOAD_ORDER_GROUP ScGlobalTDIGroup = SC_INVALID_GROUP;
  79. LPLOAD_ORDER_GROUP ScGlobalPNP_TDIGroup = SC_INVALID_GROUP;
  80. //
  81. // Static Globals
  82. //
  83. //
  84. // These are the linked list heads for each of the databases
  85. // that are maintained.
  86. //
  87. LOAD_ORDER_GROUP OrderGroupList; // empty header for doubly linked
  88. LOAD_ORDER_GROUP StandaloneGroupList; // empty header for doubly linked
  89. UNRESOLVED_DEPEND UnresolvedDependList; // empty header for doubly linked
  90. //
  91. // Local Function Prototypes
  92. //
  93. DWORD
  94. ScAllocateOrderGroupEntry(
  95. OUT LPLOAD_ORDER_GROUP *NewGroup,
  96. IN LPWSTR GroupName
  97. );
  98. DWORD
  99. ScCreateStandaloneGroup(
  100. IN LPWSTR GroupName,
  101. OUT LPLOAD_ORDER_GROUP *GroupPointer
  102. );
  103. VOID
  104. ScDeleteStandaloneGroup(
  105. IN LPLOAD_ORDER_GROUP Group
  106. );
  107. VOID
  108. ScRememberSpecialGroup(
  109. IN LPLOAD_ORDER_GROUP Group
  110. );
  111. VOID
  112. ScForgetSpecialGroup(
  113. IN LPLOAD_ORDER_GROUP Group
  114. );
  115. DWORD
  116. ScCreateUnresolvedDepend(
  117. IN LPWSTR Name,
  118. OUT LPUNRESOLVED_DEPEND *Unresolved
  119. );
  120. VOID
  121. ScDeleteUnresolvedDepend(
  122. IN OUT LPUNRESOLVED_DEPEND *Unresolved
  123. );
  124. DWORD
  125. ScSetServiceDependList(
  126. LPDEPEND_RECORD Start,
  127. LPSERVICE_RECORD ServiceRecord,
  128. PVOID DependOnRecord,
  129. DEPEND_TYPE DependOnType
  130. );
  131. VOID
  132. ScCompareVector(
  133. IN LPDWORD TagArray,
  134. IN DWORD TagArrayLength,
  135. IN OUT LPDWORD ReturnTagPtr
  136. );
  137. //****************************************************************************/
  138. // Miscellaneous Short Functions
  139. //****************************************************************************/
  140. LPLOAD_ORDER_GROUP
  141. ScGetOrderGroupList(
  142. VOID
  143. )
  144. {
  145. SC_ASSERT(ScGroupListLock.Have());
  146. return OrderGroupList.Next;
  147. }
  148. LPLOAD_ORDER_GROUP
  149. ScGetStandaloneGroupList(
  150. VOID
  151. )
  152. {
  153. SC_ASSERT(ScGroupListLock.Have());
  154. return StandaloneGroupList.Next;
  155. }
  156. LPUNRESOLVED_DEPEND
  157. ScGetUnresolvedDependList(
  158. VOID
  159. )
  160. {
  161. SC_ASSERT(ScGroupListLock.Have());
  162. return UnresolvedDependList.Next;
  163. }
  164. VOID
  165. ScInitGroupDatabase(VOID)
  166. /*++
  167. Routine Description:
  168. Arguments:
  169. Return Value:
  170. --*/
  171. {
  172. OrderGroupList.Next = NULL;
  173. OrderGroupList.Prev = NULL;
  174. StandaloneGroupList.Next = NULL;
  175. StandaloneGroupList.Prev = NULL;
  176. UnresolvedDependList.Next = NULL;
  177. UnresolvedDependList.Prev = NULL;
  178. }
  179. VOID
  180. ScEndGroupDatabase(VOID)
  181. /*++
  182. Routine Description:
  183. Arguments:
  184. Return Value:
  185. --*/
  186. {
  187. LPLOAD_ORDER_GROUP Group;
  188. LPLOAD_ORDER_GROUP Grp;
  189. SC_ASSERT(ScGroupListLock.HaveExclusive());
  190. Group = OrderGroupList.Next;
  191. while (Group != NULL) {
  192. Grp = Group;
  193. Group = Group->Next;
  194. REMOVE_FROM_LIST(Grp);
  195. LocalFree(Grp);
  196. }
  197. }
  198. DWORD
  199. ScCreateOrderGroupEntry(
  200. IN LPWSTR GroupName
  201. )
  202. /*++
  203. Routine Description:
  204. This function adds a group entry into the end of the load order group
  205. list.
  206. Arguments:
  207. GroupName - Supplies the name of the load group.
  208. Return Value:
  209. NO_ERROR - The operation was successful.
  210. ERROR_NOT_ENOUGH_MEMORY - The call to allocate memory for a new
  211. group entry failed.
  212. Note:
  213. The GroupListLock must be held exclusively prior to calling this function.
  214. --*/
  215. {
  216. DWORD status;
  217. LPLOAD_ORDER_GROUP NewGroup;
  218. LPLOAD_ORDER_GROUP GroupListPointer;
  219. SC_ASSERT(ScGroupListLock.HaveExclusive());
  220. if ((status = ScAllocateOrderGroupEntry(
  221. &NewGroup,
  222. GroupName
  223. )) != NO_ERROR) {
  224. return status;
  225. }
  226. GroupListPointer = &OrderGroupList;
  227. //
  228. // Add the group entry to the group list at the end.
  229. //
  230. ADD_TO_LIST(GroupListPointer, NewGroup);
  231. SC_LOG(CONFIG, "ScCreateOrderGroupEntry: Added %ws to GroupList\n", GroupName);
  232. return NO_ERROR;
  233. }
  234. DWORD
  235. ScAllocateOrderGroupEntry(
  236. OUT LPLOAD_ORDER_GROUP *NewGroup,
  237. IN LPWSTR GroupName
  238. )
  239. {
  240. //
  241. // Allocate memory for the new group.
  242. //
  243. *NewGroup = (LPLOAD_ORDER_GROUP)LocalAlloc(
  244. LMEM_ZEROINIT,
  245. WCSSIZE(GroupName) + sizeof(LOAD_ORDER_GROUP)
  246. );
  247. if (*NewGroup == NULL) {
  248. SC_LOG(ERROR,"ScAllocateOrderGroupEntry: LocalAlloc failure %ld\n",
  249. GetLastError());
  250. return ERROR_NOT_ENOUGH_MEMORY;
  251. }
  252. //
  253. // Save away the GroupName
  254. //
  255. (*NewGroup)->GroupName = (LPWSTR) ((LPBYTE) (*NewGroup) + sizeof(LOAD_ORDER_GROUP));
  256. wcscpy((*NewGroup)->GroupName, GroupName);
  257. ScRememberSpecialGroup(*NewGroup);
  258. //
  259. // Set the RefCount field to 0xffffffff so that we can differentiate an
  260. // order group from a standalone group. This field actually indicates
  261. // the number of members in a group and dependency references to it if
  262. // the group is standalone so that we can delete the standalone group
  263. // when it goes to 0.
  264. //
  265. (*NewGroup)->RefCount = MAXULONG;
  266. return NO_ERROR;
  267. }
  268. DWORD
  269. ScCreateGroupMembership(
  270. OUT PSERVICE_RECORD ServiceRecord,
  271. IN LPWSTR Group OPTIONAL
  272. )
  273. /*++
  274. Routine Description:
  275. This function assigns the load order group membership information
  276. of the service to its specified service record. If the service
  277. belongs to a group in OrderGroupList, a pointer to the group in the load
  278. order group list is saved. If the service belongs to a group which
  279. is not in the load order group list, the name of the group is saved
  280. in the service record in case the group gets added to the load order
  281. group list later. If Group is not specified, no group membership
  282. information is saved.
  283. Arguments:
  284. ServiceRecord - Receives the group membership information in this service
  285. record.
  286. Group - Supplies the string which contains the name of the group. This
  287. is the raw string read from the registry which may contain blank,
  288. tab or newline characters which we should ignore.
  289. Return Value:
  290. NO_ERROR - The operation was successful.
  291. ERROR_NOT_ENOUGH_MEMORY - The call to allocate memory for a group name
  292. failed.
  293. Note:
  294. This routine assumes that the database lock is already held. It is
  295. called by ScAddConfigInfoServiceRecord.
  296. It also assumes that the caller has exclusive access to the group
  297. list lock.
  298. --*/
  299. {
  300. DWORD status;
  301. LPWSTR GroupPtr = Group;
  302. LPWSTR GroupName;
  303. PLOAD_ORDER_GROUP GroupEntry = ScGetOrderGroupList();
  304. SC_ASSERT(ScGroupListLock.HaveExclusive());
  305. SC_ASSERT(ScServiceRecordLock.HaveExclusive());
  306. //
  307. // Extract the group name from the string read in from the registry.
  308. //
  309. if ((! ARGUMENT_PRESENT(GroupPtr)) || (! ScGetToken(&GroupPtr, &GroupName))) {
  310. ServiceRecord->MemberOfGroup = (PLOAD_ORDER_GROUP) NULL;
  311. return NO_ERROR;
  312. }
  313. //
  314. // Search for matching group name in load order list
  315. //
  316. while (GroupEntry != NULL) {
  317. if (_wcsicmp(GroupEntry->GroupName, GroupName) == 0) {
  318. ServiceRecord->MemberOfGroup = GroupEntry;
  319. return NO_ERROR;
  320. }
  321. GroupEntry = GroupEntry->Next;
  322. }
  323. //
  324. // Group name not NULL, and not found in load order group list.
  325. // Group is a standalone group.
  326. //
  327. status = ScCreateStandaloneGroup(
  328. GroupName,
  329. &(ServiceRecord->MemberOfGroup)
  330. );
  331. if (status != NO_ERROR) {
  332. return status;
  333. }
  334. return NO_ERROR;
  335. }
  336. VOID
  337. ScDeleteGroupMembership(
  338. IN OUT PSERVICE_RECORD ServiceRecord
  339. )
  340. /*++
  341. Routine Description:
  342. This function deletes any memory allocated for group membership
  343. association.
  344. Arguments:
  345. ServiceRecord - Supplies the group membership information in this
  346. service record.
  347. Return Value:
  348. None.
  349. Note:
  350. This routine assumes that the database lock is already held. It is
  351. called by ScAddConfigInfoServiceRecord and ScDecrementUseCountAndDelete.
  352. It also assumes that the group list lock is held exclusively.
  353. --*/
  354. {
  355. SC_ASSERT(ScGroupListLock.HaveExclusive());
  356. SC_ASSERT(ScServiceRecordLock.HaveExclusive());
  357. if (ServiceRecord->MemberOfGroup != NULL &&
  358. ServiceRecord->MemberOfGroup->RefCount != MAXULONG) {
  359. ScDeleteStandaloneGroup(ServiceRecord->MemberOfGroup);
  360. }
  361. ServiceRecord->MemberOfGroup = NULL;
  362. }
  363. DWORD
  364. ScCreateRegistryGroupPointer(
  365. OUT PSERVICE_RECORD ServiceRecord,
  366. IN LPWSTR Group OPTIONAL
  367. )
  368. /*++
  369. Routine Description:
  370. This function assigns the load order group RegistryGroup
  371. information in the service record to match the load order group
  372. stored in the registry, which is not the same as MemberOfGroup
  373. information if the load order group of the service is changed
  374. while the service is running. However, we need to know what the
  375. resultant load order group of the service is when it stops so
  376. that when we can guarantee uniqueness of a tag based on all
  377. members the group.
  378. This function does exactly the same thing as the
  379. ScCreateGroupMembership function but alters the RegistryGroup
  380. pointer instead of the MemberOfGroup pointer in the service
  381. record.
  382. Arguments:
  383. ServiceRecord - Receives the group membership information in this service
  384. record.
  385. Group - Supplies the string which contains the name of the group. This
  386. is the raw string read from the registry which may contain blank,
  387. tab or newline characters which we should ignore.
  388. Return Value:
  389. NO_ERROR - The operation was successful.
  390. ERROR_NOT_ENOUGH_MEMORY - The call to allocate memory for a group name
  391. failed.
  392. Note:
  393. This routine assumes that the database lock is already held. It is
  394. called by ScAddConfigInfoServiceRecord.
  395. It also assumes that the caller has exclusive access to the group
  396. list lock.
  397. --*/
  398. {
  399. DWORD status;
  400. LPWSTR GroupPtr = Group;
  401. LPWSTR GroupName;
  402. PLOAD_ORDER_GROUP GroupEntry = ScGetOrderGroupList();
  403. SC_ASSERT(ScGroupListLock.HaveExclusive());
  404. SC_ASSERT(ScServiceRecordLock.HaveExclusive());
  405. //
  406. // Extract the group name from the string read in from the registry.
  407. //
  408. if ((! ARGUMENT_PRESENT(GroupPtr)) || (! ScGetToken(&GroupPtr, &GroupName))) {
  409. ServiceRecord->RegistryGroup = (PLOAD_ORDER_GROUP) NULL;
  410. return NO_ERROR;
  411. }
  412. //
  413. // Search for matching group name in load order list
  414. //
  415. while (GroupEntry != NULL) {
  416. if (_wcsicmp(GroupEntry->GroupName, GroupName) == 0) {
  417. ServiceRecord->RegistryGroup = GroupEntry;
  418. return NO_ERROR;
  419. }
  420. GroupEntry = GroupEntry->Next;
  421. }
  422. //
  423. // Group name not NULL, and not found in load order group list.
  424. // Group is a standalone group.
  425. //
  426. status = ScCreateStandaloneGroup(
  427. GroupName,
  428. &(ServiceRecord->RegistryGroup)
  429. );
  430. if (status != NO_ERROR) {
  431. return status;
  432. }
  433. return NO_ERROR;
  434. }
  435. VOID
  436. ScDeleteRegistryGroupPointer(
  437. IN OUT PSERVICE_RECORD ServiceRecord
  438. )
  439. /*++
  440. Routine Description:
  441. This function deletes any memory allocated for registry group
  442. association.
  443. Arguments:
  444. ServiceRecord - Supplies the registry group information in this
  445. service record.
  446. Return Value:
  447. None.
  448. Note:
  449. This routine assumes that the database lock is already held. It is
  450. called by ScAddConfigInfoServiceRecord and ScDecrementUseCountAndDelete.
  451. It also assumes that the group list lock is held exclusively.
  452. --*/
  453. {
  454. SC_ASSERT(ScGroupListLock.HaveExclusive());
  455. SC_ASSERT(ScServiceRecordLock.HaveExclusive());
  456. if (ServiceRecord->RegistryGroup != NULL &&
  457. ServiceRecord->RegistryGroup->RefCount != MAXULONG) {
  458. ScDeleteStandaloneGroup(ServiceRecord->RegistryGroup);
  459. }
  460. ServiceRecord->RegistryGroup = NULL;
  461. }
  462. DWORD
  463. ScCreateStandaloneGroup(
  464. IN LPWSTR GroupName,
  465. OUT LPLOAD_ORDER_GROUP *GroupPointer
  466. )
  467. /*++
  468. Routine Description:
  469. This function looks for a matching standalone group entry in the
  470. standalone group list. If a match is found, the reference count is
  471. incremented and the pointer to the matching entry is returned.
  472. If no matching entry is found, this function creates a new standalone
  473. group entry, insert it into the end of the standalone group list, and
  474. return a pointer to the new entry.
  475. Arguments:
  476. Name - Supplies the name of the group which is not in the
  477. ServiceOrderList.
  478. GroupPointer - Receives a pointer to the unresolved entry.
  479. Return Value:
  480. NO_ERROR - The operation was successful.
  481. ERROR_NOT_ENOUGH_MEMORY - Allocation of memory failed.
  482. Note:
  483. This routine assumes that the caller has exclusively acquired the
  484. group list lock. It is called by ScCreateGroupMembership.
  485. --*/
  486. {
  487. SC_ASSERT(ScGroupListLock.HaveExclusive());
  488. LPLOAD_ORDER_GROUP Group = ScGetStandaloneGroupList();
  489. BOOL Found = FALSE;
  490. //
  491. // Search the existing standalone group list for the matching
  492. // standalone group entry.
  493. //
  494. while (Group != NULL) {
  495. if (_wcsicmp(Group->GroupName, GroupName) == 0) {
  496. Found = TRUE;
  497. break;
  498. }
  499. Group = Group->Next;
  500. }
  501. if (Found) {
  502. Group->RefCount++;
  503. SC_LOG2(DEPEND_DUMP,
  504. "Found existing group entry for " FORMAT_LPWSTR
  505. ", just increment refcount to %lu\n", Group->GroupName,
  506. Group->RefCount);
  507. *GroupPointer = Group;
  508. return NO_ERROR;
  509. }
  510. //
  511. // Not found. Allocate a new group entry.
  512. //
  513. if ((*GroupPointer = (LPLOAD_ORDER_GROUP)LocalAlloc(
  514. LMEM_ZEROINIT,
  515. sizeof(LOAD_ORDER_GROUP) + WCSSIZE(GroupName)
  516. )) == NULL) {
  517. SC_LOG(ERROR,"ScCreateStandaloneGroup: LocalAlloc failure %lu\n",
  518. GetLastError());
  519. return ERROR_NOT_ENOUGH_MEMORY;
  520. }
  521. (*GroupPointer)->GroupName = (LPWSTR) ((DWORD_PTR) *GroupPointer +
  522. sizeof(LOAD_ORDER_GROUP));
  523. wcscpy((*GroupPointer)->GroupName, GroupName);
  524. (*GroupPointer)->RefCount = 1;
  525. SC_LOG1(DEPEND_DUMP, "Created new standalone group entry "
  526. FORMAT_LPWSTR "\n", (*GroupPointer)->GroupName);
  527. ScRememberSpecialGroup(*GroupPointer);
  528. Group = &StandaloneGroupList;
  529. //
  530. // Add the new group entry to the standalone group list at the end.
  531. //
  532. ADD_TO_LIST(Group, *GroupPointer);
  533. return NO_ERROR;
  534. }
  535. VOID
  536. ScDeleteStandaloneGroup(
  537. IN LPLOAD_ORDER_GROUP Group
  538. )
  539. {
  540. if (Group->RefCount) {
  541. Group->RefCount--;
  542. SC_LOG1(DEPEND, "DeleteStandaloneGroup: Subtracted RefCount is "
  543. FORMAT_DWORD "\n", Group->RefCount);
  544. }
  545. else {
  546. SC_LOG0(ERROR, "ScDeleteStandaloneGroup: Before delete, refcount is 0!\n");
  547. SC_ASSERT(FALSE);
  548. }
  549. if (Group->RefCount == 0) {
  550. SC_LOG1(DEPEND, "Deleting standalone group " FORMAT_LPWSTR "\n",
  551. Group->GroupName);
  552. REMOVE_FROM_LIST(Group);
  553. ScForgetSpecialGroup(Group);
  554. LocalFree(Group);
  555. }
  556. }
  557. VOID
  558. ScRememberSpecialGroup(
  559. IN LPLOAD_ORDER_GROUP Group
  560. )
  561. /*++
  562. Routine Description:
  563. Compares the group name against a set of known group names to see if it
  564. is a group that requires special handling, and if so, saves the pointer
  565. to the group in a global variable.
  566. Arguments:
  567. Return Value:
  568. --*/
  569. {
  570. SC_ASSERT(ScGroupListLock.HaveExclusive());
  571. // CODEWORK: If the number of special groups keeps growing, do this
  572. // in a table-driven way!
  573. if (_wcsicmp(Group->GroupName, SC_GROUPNAME_TDI) == 0)
  574. {
  575. if (ScGlobalTDIGroup != SC_INVALID_GROUP)
  576. {
  577. SC_LOG0(ERROR, "Warning: TDI group occurs more than once in load order group list\n");
  578. }
  579. ScGlobalTDIGroup = Group;
  580. }
  581. else if (_wcsicmp(Group->GroupName, SC_GROUPNAME_PNP_TDI) == 0)
  582. {
  583. if (ScGlobalPNP_TDIGroup != SC_INVALID_GROUP)
  584. {
  585. SC_LOG0(ERROR, "Warning: PNP_TDI group occurs more than once in load order group list\n");
  586. }
  587. ScGlobalPNP_TDIGroup = Group;
  588. }
  589. }
  590. VOID
  591. ScForgetSpecialGroup(
  592. IN LPLOAD_ORDER_GROUP Group
  593. )
  594. /*++
  595. Routine Description:
  596. Arguments:
  597. Return Value:
  598. --*/
  599. {
  600. SC_ASSERT(ScGroupListLock.HaveExclusive());
  601. if (Group == ScGlobalTDIGroup)
  602. {
  603. ScGlobalTDIGroup = SC_INVALID_GROUP;
  604. }
  605. else if (Group == ScGlobalPNP_TDIGroup)
  606. {
  607. ScGlobalPNP_TDIGroup = SC_INVALID_GROUP;
  608. }
  609. }
  610. VOID
  611. ScGenerateDependencies(
  612. VOID
  613. )
  614. /*++
  615. Routine Description:
  616. Arguments:
  617. Return Value:
  618. Note:
  619. The GroupListLock must be held exclusively prior to calling this routine.
  620. --*/
  621. {
  622. SC_ASSERT(ScGroupListLock.HaveExclusive());
  623. FOR_ALL_SERVICES(Service)
  624. {
  625. (void) ScSetDependencyPointers(Service);
  626. }
  627. }
  628. DWORD
  629. ScSetDependencyPointers(
  630. IN LPSERVICE_RECORD Service
  631. )
  632. /*++
  633. Routine Description:
  634. Arguments:
  635. Return Value:
  636. Note:
  637. The GroupListLock must be held exclusively prior to calling this routine.
  638. --*/
  639. {
  640. SC_ASSERT(ScGroupListLock.HaveExclusive());
  641. DWORD status;
  642. if (Service->Dependencies != NULL) {
  643. status = ScCreateDependencies(
  644. Service,
  645. Service->Dependencies
  646. );
  647. if (status == NO_ERROR) {
  648. LocalFree(Service->Dependencies);
  649. Service->Dependencies = NULL;
  650. }
  651. return status;
  652. }
  653. return NO_ERROR;
  654. }
  655. DWORD
  656. ScResolveDependencyToService(
  657. LPSERVICE_RECORD DependOnService
  658. )
  659. /*++
  660. Routine Description:
  661. This function resolves all dependencies to the service we are
  662. currently installing via CreateService. The start depend entry
  663. of these services will point to the service record of the service
  664. we are installing instead of the unresolved depend record. A
  665. stop depend entry is created for the service we are installing to
  666. point back to every service that depends on it.
  667. Arguments:
  668. DependOnService - Supplies a pointer to the service we are installing
  669. via CreateService which other services may depend on.
  670. Return Value:
  671. NO_ERROR - The operation was successful.
  672. ERROR_NOT_ENOUGH_MEMORY - Fail to allocate memory for required data
  673. structures.
  674. Note:
  675. This routine assumes that the caller has exclusively acquired the
  676. database lock. It is called by RCreateServiceW.
  677. --*/
  678. {
  679. SC_ASSERT(ScGroupListLock.Have());
  680. SC_ASSERT(ScServiceRecordLock.HaveExclusive());
  681. DWORD status;
  682. LPUNRESOLVED_DEPEND UnresolvedEntry = ScGetUnresolvedDependList();
  683. //
  684. // Search the unresolved depend list for a matching entry
  685. //
  686. while (UnresolvedEntry != NULL) {
  687. if (_wcsicmp(UnresolvedEntry->Name, DependOnService->ServiceName) == 0) {
  688. SC_LOG1(DEPEND, "Found unresolved entry for " FORMAT_LPWSTR "\n",
  689. DependOnService->ServiceName);
  690. break;
  691. }
  692. UnresolvedEntry = UnresolvedEntry->Next;
  693. }
  694. if (UnresolvedEntry == NULL) {
  695. //
  696. // There are no service which depends on the service we are
  697. // installing; hence, no unresolved dependency to resolve.
  698. //
  699. SC_LOG1(DEPEND, "No service depends on " FORMAT_LPWSTR "\n",
  700. DependOnService->ServiceName);
  701. return NO_ERROR;
  702. }
  703. //
  704. // Loop through all services to see if any of them has a start depend
  705. // entry that points to UnresolvedEntry.
  706. //
  707. FOR_ALL_SERVICES(Service)
  708. {
  709. if (UnresolvedEntry == NULL)
  710. {
  711. break;
  712. }
  713. for (LPDEPEND_RECORD Start = Service->StartDepend;
  714. Start != NULL;
  715. Start = Start->Next)
  716. {
  717. if (Start->DependUnresolved == UnresolvedEntry)
  718. {
  719. status = ScSetServiceDependList(
  720. Start,
  721. Service,
  722. (PVOID)DependOnService,
  723. TypeDependOnService
  724. );
  725. if (status != NO_ERROR)
  726. {
  727. //
  728. // Error with creating the stop depend entry for
  729. // DependOnService. Back out changes set for the
  730. // current start depend entry.
  731. //
  732. Start->DependType = TypeDependOnUnresolved;
  733. Start->DependUnresolved = UnresolvedEntry;
  734. //
  735. // Back out of all other resolved dependencies to
  736. // DependOnService will be done in ScDecrementUseCountAndDelete.
  737. //
  738. SC_LOG2(ERROR, "ScResolvedDependencyToService " FORMAT_LPWSTR
  739. " failed " FORMAT_DWORD "\n",
  740. DependOnService->ServiceName, status);
  741. return status;
  742. }
  743. SC_LOG2(DEPEND, FORMAT_LPWSTR " depends on " FORMAT_LPWSTR
  744. ". Dependency resolved!\n", Service->ServiceName,
  745. UnresolvedEntry->Name);
  746. ScDeleteUnresolvedDepend(&UnresolvedEntry);
  747. }
  748. }
  749. }
  750. return NO_ERROR;
  751. }
  752. DWORD
  753. ScCreateDependencies(
  754. OUT PSERVICE_RECORD ServiceRecord,
  755. IN LPWSTR Dependencies OPTIONAL
  756. )
  757. /*++
  758. Routine Description:
  759. This function creates the start dependencies list of a service.
  760. If the service specified by ServiceRecord depends on a service that
  761. has not been inserted into the service list yet, that service entry
  762. will be created and inserted into the service list so that the depend
  763. record can point to it. The service this one points to in its start
  764. dependency list will get a new entry in its stop dependency list because
  765. this one must be stopped before it can stop.
  766. The dependencies list is not ordered.
  767. NOTE: This function is for call from RChangeServiceConfig.
  768. Arguments:
  769. ServiceRecord - Receives the start dependencies information in this
  770. service record.
  771. Dependencies - Supplies the string which contains the names this service
  772. depend on to be started first. This is a multi-sz string of
  773. service or group names.
  774. Return Value:
  775. NO_ERROR - The operation was successful.
  776. ERROR_NOT_ENOUGH_MEMORY - Fail to allocate memory for required data
  777. structures.
  778. Note:
  779. This routine assumes that the caller has exclusively acquired the
  780. database lock. It is called by ScSetDependencyPointers.
  781. It also assumes that the caller has exclusively acquired the group
  782. list lock.
  783. --*/
  784. {
  785. DWORD status;
  786. LPWSTR DependPtr = Dependencies;
  787. LPWSTR DependOnName;
  788. PVOID DependOnRecord = NULL;
  789. DEPEND_TYPE Type;
  790. PDEPEND_RECORD Start;
  791. SC_ASSERT(ScGroupListLock.HaveExclusive());
  792. SC_ASSERT(ScServiceRecordLock.HaveExclusive());
  793. if (! ARGUMENT_PRESENT(DependPtr)) {
  794. return NO_ERROR;
  795. }
  796. while (*DependPtr != 0) {
  797. if (ScGetToken(&DependPtr, &DependOnName)) {
  798. //
  799. // Initialize flag for noting that a new service record is
  800. // created for resolving the dependency chain.
  801. //
  802. Type = TypeNone;
  803. if (*DependOnName != SC_GROUP_IDENTIFIERW) {
  804. //
  805. // Depend on a service
  806. //
  807. //
  808. // Look for the service we depend on in the service record list
  809. //
  810. status = ScGetNamedServiceRecord(
  811. DependOnName,
  812. (LPSERVICE_RECORD *) &DependOnRecord
  813. );
  814. if (status == ERROR_SERVICE_DOES_NOT_EXIST) {
  815. //
  816. // Could not find the service we depend on. Create an
  817. // unresolved dependency entry.
  818. //
  819. status = ScCreateUnresolvedDepend(
  820. DependOnName,
  821. (PUNRESOLVED_DEPEND *) &DependOnRecord
  822. );
  823. if (status != NO_ERROR) {
  824. goto ErrorExit;
  825. }
  826. //
  827. // New unresolved depend entry created. We have to remove
  828. // it if any error occurs later.
  829. //
  830. Type = TypeDependOnUnresolved;
  831. }
  832. else {
  833. Type = TypeDependOnService;
  834. }
  835. if (status != NO_ERROR) {
  836. goto ErrorExit;
  837. }
  838. }
  839. else {
  840. //
  841. // Depend on a group
  842. //
  843. PLOAD_ORDER_GROUP GroupEntry = ScGetOrderGroupList();
  844. DependOnName++;
  845. //
  846. // Search for matching group name in load order list
  847. //
  848. while (GroupEntry != NULL) {
  849. if (_wcsicmp(GroupEntry->GroupName, DependOnName) == 0) {
  850. DependOnRecord = (PVOID) GroupEntry;
  851. Type = TypeDependOnGroup;
  852. break;
  853. }
  854. GroupEntry = GroupEntry->Next;
  855. }
  856. if (GroupEntry == NULL) {
  857. //
  858. // Could not find group in the OrderGroup list. Must
  859. // depend on a standalone group.
  860. //
  861. status = ScCreateStandaloneGroup(
  862. DependOnName,
  863. (LPLOAD_ORDER_GROUP *) &DependOnRecord
  864. );
  865. if (status != NO_ERROR) {
  866. goto ErrorExit;
  867. }
  868. Type = TypeDependOnGroup;
  869. }
  870. }
  871. //
  872. // Allocate memory for start depend record and insert it in the
  873. // front of the start depend list of the service we are processing.
  874. //
  875. if ((status = ScCreateDependRecord(
  876. TRUE, // For start list
  877. ServiceRecord,
  878. &Start
  879. )) != NO_ERROR) {
  880. goto ErrorExit;
  881. }
  882. //
  883. // Start depend record created OK, set fields. Set stop
  884. // depend if appropriate (Type == TypeDependOnService).
  885. //
  886. status = ScSetServiceDependList(
  887. Start,
  888. ServiceRecord,
  889. DependOnRecord,
  890. Type
  891. );
  892. if (status != NO_ERROR) {
  893. //
  894. // Remove the start depend record just created in the front of
  895. // the start depend list and delete it.
  896. //
  897. ServiceRecord->StartDepend = Start->Next;
  898. LocalFree(Start);
  899. goto ErrorExit;
  900. }
  901. } // if got token
  902. } // while there is a dependency
  903. return NO_ERROR;
  904. ErrorExit:
  905. //
  906. // Remove newly created service record because of errors and we cannot
  907. // proceed.
  908. //
  909. if (Type == TypeDependOnUnresolved) {
  910. ScDeleteUnresolvedDepend((PUNRESOLVED_DEPEND *) &DependOnRecord);
  911. }
  912. //
  913. // Clean up dependencies created up to the point of failure
  914. //
  915. ScDeleteStartDependencies(ServiceRecord);
  916. return status;
  917. }
  918. DWORD
  919. ScCreateUnresolvedDepend(
  920. IN LPWSTR Name,
  921. OUT LPUNRESOLVED_DEPEND *Unresolved
  922. )
  923. /*++
  924. Routine Description:
  925. This function looks for a matching unresolved entry in the unresolved
  926. depend list. If a match is found, the reference count is incremented
  927. and the pointer to the matching entry is returned.
  928. If no matching entry is found, this function creates a new unresolved
  929. entry, insert it into the end of the unresolved depend list, and
  930. return a pointer to the new entry.
  931. Arguments:
  932. Name - Supplies the name of the service or group which has not been
  933. installed yet, and thus needing this unresolved depend entry.
  934. Unresolved - Receives a pointer to the unresolved entry.
  935. Return Value:
  936. NO_ERROR - The operation was successful.
  937. ERROR_NOT_ENOUGH_MEMORY - Allocation of memory failed.
  938. Note:
  939. This routine assumes that the caller has exclusively acquired the
  940. database lock. It is called by ScCreateDependencies.
  941. --*/
  942. {
  943. SC_ASSERT(ScGroupListLock.HaveExclusive());
  944. SC_ASSERT(ScServiceRecordLock.HaveExclusive());
  945. LPUNRESOLVED_DEPEND UnresolvedList = ScGetUnresolvedDependList();
  946. BOOL Found = FALSE;
  947. //
  948. // Search the existing unresolved depend list for the matching
  949. // unresolved depend entry.
  950. //
  951. while (UnresolvedList != NULL) {
  952. if (_wcsicmp(UnresolvedList->Name, Name) == 0) {
  953. Found = TRUE;
  954. break;
  955. }
  956. UnresolvedList = UnresolvedList->Next;
  957. }
  958. if (Found) {
  959. UnresolvedList->RefCount++;
  960. SC_LOG2(DEPEND,
  961. "Found existing unresolved entry for " FORMAT_LPWSTR
  962. ", just increment refcount to %lu\n", UnresolvedList->Name,
  963. UnresolvedList->RefCount);
  964. *Unresolved = UnresolvedList;
  965. return NO_ERROR;
  966. }
  967. //
  968. // Not found. Allocate a new unresolved entry.
  969. //
  970. if ((*Unresolved = (LPUNRESOLVED_DEPEND)LocalAlloc(
  971. LMEM_ZEROINIT,
  972. sizeof(UNRESOLVED_DEPEND) + WCSSIZE(Name)
  973. )) == NULL) {
  974. SC_LOG1(ERROR,"ScCreateUnresolvedDepend: LocalAlloc failure %lu\n",
  975. GetLastError());
  976. return ERROR_NOT_ENOUGH_MEMORY;
  977. }
  978. (*Unresolved)->Name = (LPWSTR) ((DWORD_PTR) *Unresolved +
  979. sizeof(UNRESOLVED_DEPEND));
  980. wcscpy((*Unresolved)->Name, Name);
  981. (*Unresolved)->RefCount = 1;
  982. SC_LOG1(DEPEND, "Created new unresolved depend entry "
  983. FORMAT_LPWSTR "\n", (*Unresolved)->Name);
  984. UnresolvedList = &UnresolvedDependList;
  985. //
  986. // Add the new unresolved entry to the unresolved list at the end.
  987. //
  988. ADD_TO_LIST(UnresolvedList, *Unresolved);
  989. return NO_ERROR;
  990. }
  991. VOID
  992. ScDeleteUnresolvedDepend(
  993. IN OUT LPUNRESOLVED_DEPEND *Unresolved
  994. )
  995. {
  996. if ((*Unresolved)->RefCount) {
  997. (*Unresolved)->RefCount--;
  998. SC_LOG1(DEPEND, "ScDeleteUnresolvedDepend: Subtracted RefCount is "
  999. FORMAT_DWORD "\n", (*Unresolved)->RefCount);
  1000. }
  1001. else {
  1002. //
  1003. // The reference count better not be 0.
  1004. //
  1005. SC_LOG0(ERROR, "ScDeleteUnresolvedDepend: Before delete, refcount is 0!\n");
  1006. SC_ASSERT(FALSE);
  1007. }
  1008. if ((*Unresolved)->RefCount == 0) {
  1009. REMOVE_FROM_LIST(*Unresolved);
  1010. LocalFree(*Unresolved);
  1011. *Unresolved = NULL;
  1012. }
  1013. }
  1014. DWORD
  1015. ScCreateDependRecord(
  1016. IN BOOL IsStartList,
  1017. IN OUT PSERVICE_RECORD ServiceRecord,
  1018. OUT PDEPEND_RECORD *DependRecord
  1019. )
  1020. /*++
  1021. Routine Description:
  1022. This function allocates the memory for a depend record, and insert
  1023. it into the front of the specific depend list. If IsStartList is
  1024. TRUE, the depend record goes into the start depend list of
  1025. ServiceRecord, otherwise the depend record goes into the stop
  1026. depend list of the ServiceRecord.
  1027. Arguments:
  1028. IsStartList - TRUE indicates to insert into start list, FALSE indicates
  1029. to insert into stop list.
  1030. ServiceRecord - Receives the start/stop depend record in its dependency
  1031. list.
  1032. DependRecord - Receives a pointer to the new depend record created.
  1033. Return Value:
  1034. NO_ERROR - The operation was successful.
  1035. ERROR_NOT_ENOUGH_MEMORY - The call to allocate memory for a depend
  1036. record failed.
  1037. Note:
  1038. This routine assumes that the caller has exclusively acquired the
  1039. database lock. It is called by ScCreateDependencies.
  1040. --*/
  1041. {
  1042. SC_ASSERT(ScServiceRecordLock.HaveExclusive());
  1043. if ((*DependRecord = (PDEPEND_RECORD)LocalAlloc(
  1044. LMEM_ZEROINIT,
  1045. sizeof(DEPEND_RECORD)
  1046. )) == NULL) {
  1047. SC_LOG(ERROR,"ScCreateDependRecord: LocalAlloc failure %ld\n",
  1048. GetLastError());
  1049. return ERROR_NOT_ENOUGH_MEMORY;
  1050. }
  1051. //
  1052. // Insert the depend record into the front of the list
  1053. //
  1054. if (IsStartList) {
  1055. //
  1056. // Start depend
  1057. //
  1058. (*DependRecord)->Next = ServiceRecord->StartDepend;
  1059. ServiceRecord->StartDepend = *DependRecord;
  1060. }
  1061. else {
  1062. //
  1063. // Stop depend
  1064. //
  1065. (*DependRecord)->Next = ServiceRecord->StopDepend;
  1066. ServiceRecord->StopDepend = *DependRecord;
  1067. }
  1068. return NO_ERROR;
  1069. }
  1070. VOID
  1071. ScDeleteStartDependencies(
  1072. IN PSERVICE_RECORD ServiceRecord
  1073. )
  1074. /*++
  1075. Routine Description:
  1076. This function deletes the start dependencies list of a service. It also
  1077. deletes the the stop dependencies of other services which need this
  1078. service to be stopped first.
  1079. NOTE: This function is for call from RChangeServiceConfig.
  1080. Arguments:
  1081. ServiceRecord - Supplies the start dependencies information in this
  1082. service record.
  1083. Return Value:
  1084. None.
  1085. Note:
  1086. This routine assumes that the caller has exclusively acquired the
  1087. database lock. It is called by ScAddConfigInfoServiceRecord and
  1088. ScDecrementUseCountAndDelete.
  1089. It also assumes that the caller has exclusively acquired the group
  1090. list lock.
  1091. --*/
  1092. {
  1093. PDEPEND_RECORD StartEntry;
  1094. PDEPEND_RECORD StopEntry;
  1095. PDEPEND_RECORD StopBackPointer;
  1096. SC_ASSERT(ScGroupListLock.HaveExclusive());
  1097. SC_ASSERT(ScServiceRecordLock.HaveExclusive());
  1098. StartEntry = ServiceRecord->StartDepend;
  1099. while (StartEntry != NULL) {
  1100. if (StartEntry->DependType == TypeDependOnService) {
  1101. LPSERVICE_RECORD DependencyService = StartEntry->DependService;
  1102. //
  1103. // Find the stop depend record for the service which depends on this
  1104. // service to be stopped first, and delete it.
  1105. //
  1106. StopEntry = DependencyService->StopDepend;
  1107. StopBackPointer = StopEntry;
  1108. while ((StopEntry != NULL) &&
  1109. (StopEntry->DependService != ServiceRecord)) {
  1110. StopBackPointer = StopEntry;
  1111. StopEntry = StopEntry->Next;
  1112. }
  1113. if (StopEntry == NULL) {
  1114. #ifndef _CAIRO_
  1115. //
  1116. // We allow Netlogon to appear in the start dependency list, but
  1117. // not in the stop dependency list. This is for the case where
  1118. // we add a "soft" dependency on netlogon because the service runs
  1119. // in a remove account.
  1120. //
  1121. if (_wcsicmp(DependencyService->ServiceName,L"Netlogon") != 0) {
  1122. #endif // _CAIRO_
  1123. SC_LOG1(ERROR,
  1124. "ScDeleteStartDependencies: Failed to find matching stop depend node for "
  1125. FORMAT_LPWSTR "\n",
  1126. DependencyService->ServiceName);
  1127. SC_ASSERT(FALSE);
  1128. return;
  1129. #ifndef _CAIRO_
  1130. }
  1131. #endif // _CAIRO_
  1132. }
  1133. else {
  1134. if (StopEntry->DependService == ServiceRecord) {
  1135. if ((PVOID) StopBackPointer == StopEntry) {
  1136. //
  1137. // Unchaining from the front of the list
  1138. //
  1139. DependencyService->StopDepend = StopEntry->Next;
  1140. }
  1141. else {
  1142. //
  1143. // Unchaining from the middle or end of the list
  1144. //
  1145. StopBackPointer->Next = StopEntry->Next;
  1146. }
  1147. LocalFree(StopEntry);
  1148. }
  1149. }
  1150. }
  1151. else if (StartEntry->DependType == TypeDependOnGroup) {
  1152. //
  1153. // Decrement the reference count on the standalone group
  1154. // entry and deletes it if 0.
  1155. //
  1156. if (StartEntry->DependGroup->RefCount != MAXULONG) {
  1157. ScDeleteStandaloneGroup(StartEntry->DependGroup);
  1158. }
  1159. }
  1160. else {
  1161. //
  1162. // Dependency type is unresolved.
  1163. //
  1164. ScDeleteUnresolvedDepend(&StartEntry->DependUnresolved);
  1165. }
  1166. //
  1167. // Now delete the start depend record.
  1168. //
  1169. ServiceRecord->StartDepend = StartEntry->Next;
  1170. LocalFree(StartEntry);
  1171. StartEntry = ServiceRecord->StartDepend;
  1172. }
  1173. }
  1174. VOID
  1175. ScDeleteStopDependencies(
  1176. IN PSERVICE_RECORD ServiceToBeDeleted
  1177. )
  1178. /*++
  1179. Routine Description:
  1180. This function deletes the stop dependencies list of a service. For
  1181. every stop depend service, it makes the start depend pointer of that
  1182. service to point to an unresolved depend entry.
  1183. This function is called when the service is to be deleted.
  1184. Arguments:
  1185. ServiceToBeDeleted - Supplies the pointer to the service that will
  1186. be deleted.
  1187. Return Value:
  1188. None.
  1189. Note:
  1190. This routine assumes that the caller has exclusively acquired the
  1191. database lock. It is called by ScDecrementUseCountAndDelete.
  1192. --*/
  1193. {
  1194. DWORD status;
  1195. PDEPEND_RECORD StartEntry;
  1196. PDEPEND_RECORD StopEntry;
  1197. LPUNRESOLVED_DEPEND Unresolved;
  1198. SC_ASSERT(ScServiceRecordLock.HaveExclusive());
  1199. StopEntry = ServiceToBeDeleted->StopDepend;
  1200. while (StopEntry != NULL) {
  1201. LPSERVICE_RECORD DependencyService = StopEntry->DependService;
  1202. //
  1203. // Loop through the start depend entries of the service which
  1204. // depends on ServiceToBeDeleted.
  1205. //
  1206. StartEntry = DependencyService->StartDepend;
  1207. while (StartEntry != NULL) {
  1208. if (StartEntry->DependService == ServiceToBeDeleted) {
  1209. break;
  1210. }
  1211. StartEntry = StartEntry->Next;
  1212. }
  1213. if (StartEntry != NULL) {
  1214. //
  1215. // Found a start depend entry that points to the service to be.
  1216. // deleted. Make it point to an unresolved depend entry that
  1217. // represents that service.
  1218. //
  1219. status = ScCreateUnresolvedDepend(
  1220. ServiceToBeDeleted->ServiceName,
  1221. &Unresolved
  1222. );
  1223. if (status == NO_ERROR) {
  1224. StartEntry->DependType = TypeDependOnUnresolved;
  1225. StartEntry->DependUnresolved = Unresolved;
  1226. }
  1227. }
  1228. //
  1229. // Now delete the start depend record.
  1230. //
  1231. ServiceToBeDeleted->StopDepend = StopEntry->Next;
  1232. LocalFree(StopEntry);
  1233. StopEntry = ServiceToBeDeleted->StopDepend;
  1234. }
  1235. }
  1236. DWORD
  1237. ScSetServiceDependList(
  1238. LPDEPEND_RECORD Start,
  1239. LPSERVICE_RECORD ServiceRecord,
  1240. PVOID DependOnRecord,
  1241. DEPEND_TYPE DependOnType
  1242. )
  1243. /*++
  1244. Routine Description:
  1245. This function
  1246. Arguments:
  1247. Return Value:
  1248. None.
  1249. Note:
  1250. This routine assumes that the caller has exclusively acquired the
  1251. database lock. It is called by ScResolveDependencyToService and
  1252. ScCreateDependencies.
  1253. --*/
  1254. {
  1255. DWORD status;
  1256. LPDEPEND_RECORD Stop;
  1257. SC_ASSERT(ScServiceRecordLock.HaveExclusive());
  1258. //
  1259. // Set fields for start depend entry.
  1260. //
  1261. Start->DependType = DependOnType;
  1262. Start->Depend = DependOnRecord;
  1263. if (DependOnType == TypeDependOnService) {
  1264. //
  1265. // Allocate memory for stop depend record and insert it in the
  1266. // front of the stop depend list of the service we depend on.
  1267. //
  1268. if ((status = ScCreateDependRecord(
  1269. FALSE, // For stop list
  1270. (LPSERVICE_RECORD) DependOnRecord,
  1271. &Stop
  1272. )) != NO_ERROR) {
  1273. return status;
  1274. }
  1275. Stop->DependType = TypeDependOnService;
  1276. Stop->DependService = ServiceRecord;
  1277. }
  1278. return NO_ERROR;
  1279. }
  1280. LPLOAD_ORDER_GROUP
  1281. ScGetNamedGroupRecord(
  1282. IN LPCWSTR GroupName
  1283. )
  1284. /*++
  1285. Routine Description:
  1286. This function searches for a named group, first in the order group
  1287. list and next in the standalone group list.
  1288. Arguments:
  1289. GroupName - Supplies the name of the group to look for.
  1290. Return Value:
  1291. Returns the pointer to group found. If not found, this value is
  1292. NULL.
  1293. Note:
  1294. This routine assumes that the caller has exclusively acquired the
  1295. group list lock.
  1296. --*/
  1297. {
  1298. LPLOAD_ORDER_GROUP Group;
  1299. for (Group = ScGetOrderGroupList();
  1300. Group != NULL;
  1301. Group = Group->Next)
  1302. {
  1303. if (_wcsicmp(Group->GroupName, GroupName) == 0)
  1304. {
  1305. break;
  1306. }
  1307. }
  1308. if (Group == NULL)
  1309. {
  1310. for (Group = ScGetStandaloneGroupList();
  1311. Group != NULL;
  1312. Group = Group->Next)
  1313. {
  1314. if (_wcsicmp(Group->GroupName, GroupName) == 0)
  1315. {
  1316. break;
  1317. }
  1318. }
  1319. }
  1320. return Group;
  1321. }
  1322. VOID
  1323. ScGetUniqueTag(
  1324. IN LPWSTR GroupName,
  1325. OUT LPDWORD Tag
  1326. )
  1327. /*++
  1328. Routine Description:
  1329. This function looks for a unique tag value within the specified
  1330. group.
  1331. Arguments:
  1332. GroupName - Specifies the group name within which the value tag
  1333. returned must be unique.
  1334. Tag - Receives the unique tag value.
  1335. Return Value:
  1336. None.
  1337. Note:
  1338. This function acquires share access to the group list lock.
  1339. It assumes that the exclusive service database lock is already
  1340. acquired so that no other caller can execute this code until
  1341. the returned tag is fully assigned to the service, and that the
  1342. service entries in the database list don't change.
  1343. The GroupListLock must be held exclusively prior to calling this
  1344. function.
  1345. --*/
  1346. {
  1347. LPDWORD TagArray;
  1348. DWORD TagArrayLength;
  1349. DWORD ReturnTag = 1;
  1350. LPLOAD_ORDER_GROUP Group;
  1351. SC_ASSERT(ScGroupListLock.Have());
  1352. SC_ASSERT(ScServiceRecordLock.Have());
  1353. if (ScGetGroupVector(
  1354. GroupName,
  1355. (LPBYTE *) &TagArray,
  1356. &TagArrayLength
  1357. ) == NO_ERROR) {
  1358. if (TagArray != NULL) {
  1359. //
  1360. // The returned values is actually the number of bytes. Divide it
  1361. // by size of DWORD to make it the number of array entries.
  1362. //
  1363. TagArrayLength = TagArrayLength / sizeof(DWORD);
  1364. SC_ASSERT((TagArrayLength - 1) == TagArray[0]);
  1365. ScCompareVector(
  1366. TagArray,
  1367. TagArrayLength,
  1368. &ReturnTag
  1369. );
  1370. }
  1371. }
  1372. else {
  1373. TagArray = NULL;
  1374. }
  1375. Group = ScGetNamedGroupRecord(GroupName);
  1376. if (Group != NULL) {
  1377. GroupAgain:
  1378. FOR_ALL_SERVICES(Service) {
  1379. if ((Service->RegistryGroup == Group) &&
  1380. (Service->Tag == ReturnTag)) {
  1381. ReturnTag++;
  1382. if (TagArray != NULL) {
  1383. ScCompareVector(
  1384. TagArray,
  1385. TagArrayLength,
  1386. &ReturnTag
  1387. );
  1388. }
  1389. goto GroupAgain;
  1390. }
  1391. } // while all services
  1392. }
  1393. *Tag = ReturnTag;
  1394. SC_LOG(DEPEND, "ScGetUniqueTag: Tag=" FORMAT_DWORD "\n", *Tag);
  1395. }
  1396. VOID
  1397. ScCompareVector(
  1398. IN LPDWORD TagArray,
  1399. IN DWORD TagArrayLength,
  1400. IN OUT LPDWORD ReturnTagPtr
  1401. )
  1402. {
  1403. DWORD i;
  1404. VectorAgain:
  1405. for (i = 1; i < TagArrayLength; i++) {
  1406. if (TagArray[i] == (*ReturnTagPtr)) {
  1407. SC_LOG(DEPEND_DUMP, "Tag " FORMAT_DWORD " is not unique\n",
  1408. *ReturnTagPtr);
  1409. (*ReturnTagPtr)++;
  1410. goto VectorAgain;
  1411. }
  1412. }
  1413. }
  1414. VOID
  1415. ScGetDependencySize(
  1416. LPSERVICE_RECORD ServiceRecord,
  1417. LPDWORD DependSize,
  1418. LPDWORD MaxDependSize
  1419. )
  1420. /*++
  1421. Routine Description:
  1422. Arguments:
  1423. ServiceRecord -
  1424. DependSize - This points to a location that will contain the number
  1425. of bytes required for the list of dependency strings.
  1426. MaxDependSize - This points to a location that will contain the
  1427. number of bytes in the longest dependency string in the set.
  1428. Return Value:
  1429. --*/
  1430. {
  1431. LPDEPEND_RECORD dependRecord;
  1432. DWORD bytesNeeded = 0;
  1433. DWORD StrSize=0;
  1434. dependRecord = ServiceRecord->StartDepend;
  1435. //
  1436. // NOTE: Dependencies are expected to be a double NULL terminated
  1437. // terminated set of strings.
  1438. //
  1439. bytesNeeded += sizeof(WCHAR);
  1440. if (dependRecord == NULL) {
  1441. bytesNeeded += sizeof(WCHAR);
  1442. }
  1443. while (dependRecord != NULL) {
  1444. SC_ASSERT( dependRecord->Depend != NULL );
  1445. // Add room. WCSSIZE adds 1 char. For final entry, we'll
  1446. // use null char. In between, we'll put some separator.
  1447. if (dependRecord->DependType == TypeDependOnService) {
  1448. StrSize =
  1449. (DWORD) WCSSIZE(dependRecord->DependService->ServiceName); // sizes...
  1450. }
  1451. else if (dependRecord->DependType == TypeDependOnGroup) {
  1452. StrSize =
  1453. (DWORD) WCSSIZE(dependRecord->DependGroup->GroupName) +
  1454. sizeof(WCHAR); // name size plus SC_GROUP_IDENTIFIERW
  1455. }
  1456. else {
  1457. //
  1458. // Unresolved service dependency
  1459. //
  1460. StrSize = (DWORD) WCSSIZE(dependRecord->DependUnresolved->Name);
  1461. }
  1462. bytesNeeded += StrSize;
  1463. if (StrSize > *MaxDependSize) {
  1464. *MaxDependSize = StrSize;
  1465. }
  1466. dependRecord = dependRecord->Next;
  1467. }
  1468. *DependSize = bytesNeeded;
  1469. }
  1470. DWORD
  1471. ScGetDependencyString(
  1472. LPSERVICE_RECORD ServiceRecord,
  1473. DWORD MaxDependSize,
  1474. DWORD DependSize,
  1475. LPWSTR lpDependencies
  1476. )
  1477. /*++
  1478. Routine Description:
  1479. Arguments:
  1480. ServiceRecord -
  1481. MaxDependSize - This is the size of the largest string in the
  1482. dependency list.
  1483. lpDependencies - This is a pointer to the location where the
  1484. list of dependency strings is to be stored.
  1485. Return Value:
  1486. --*/
  1487. {
  1488. LPWSTR endOfVariableData;
  1489. LPWSTR fixedDataEnd;
  1490. LPDEPEND_RECORD dependRecord;
  1491. DWORD bufSize;
  1492. DWORD ApiStatus = NO_ERROR;
  1493. //
  1494. // Put dependencies in the return buffer. Since it is a NULL-NULL
  1495. // string, put an extra NULL at the end to begin with.
  1496. //
  1497. endOfVariableData = (LPWSTR) (((LPBYTE)lpDependencies) + DependSize);
  1498. endOfVariableData = endOfVariableData - 1;
  1499. * endOfVariableData = L'\0';
  1500. fixedDataEnd = lpDependencies;
  1501. dependRecord = ServiceRecord->StartDepend;
  1502. if (dependRecord == NULL) {
  1503. //
  1504. // If there are no dependencies, then we need to add a separator
  1505. // that will be followed by the NULL (immediately above).
  1506. // This separator is used to get us across the RPC interface.
  1507. // Then on the client side, it is changed to a NULL. So we end
  1508. // up with an empty-double-NULL-terminated-string.
  1509. //
  1510. endOfVariableData = endOfVariableData - 1;
  1511. * endOfVariableData = L'/';
  1512. lpDependencies = endOfVariableData;
  1513. }
  1514. else {
  1515. LPWSTR DependName;
  1516. DependName = (LPWSTR)LocalAlloc(0, (UINT) MaxDependSize);
  1517. if (DependName == NULL) {
  1518. ApiStatus = ERROR_NOT_ENOUGH_MEMORY;
  1519. goto Cleanup;
  1520. }
  1521. lpDependencies = endOfVariableData;
  1522. while (dependRecord != NULL) {
  1523. SC_ASSERT( dependRecord->Depend != NULL );
  1524. if (dependRecord->DependType == TypeDependOnService) {
  1525. wcscpy(DependName, dependRecord->DependService->ServiceName);
  1526. }
  1527. else if (dependRecord->DependType == TypeDependOnGroup) {
  1528. *DependName = SC_GROUP_IDENTIFIERW;
  1529. wcscpy(DependName + 1, dependRecord->DependGroup->GroupName);
  1530. }
  1531. else {
  1532. //
  1533. // Unresolved service dependency
  1534. //
  1535. wcscpy(DependName, dependRecord->DependUnresolved->Name);
  1536. }
  1537. bufSize = (DWORD) wcslen(DependName);
  1538. if ( !ScCopyStringToBufferW (
  1539. DependName,
  1540. bufSize,
  1541. fixedDataEnd,
  1542. &endOfVariableData,
  1543. &lpDependencies,
  1544. NULL
  1545. ) ) {
  1546. SC_LOG0(ERROR,
  1547. "RQueryServiceConfigW:ScCopyStringtoBufferW (Dependencies)Failed\n");
  1548. SC_ASSERT( FALSE );
  1549. ApiStatus = ERROR_INSUFFICIENT_BUFFER;
  1550. LocalFree(DependName);
  1551. goto Cleanup;
  1552. }
  1553. else {
  1554. //
  1555. // Add separator character.
  1556. //
  1557. lpDependencies[bufSize] = L'/';
  1558. }
  1559. dependRecord = dependRecord->Next;
  1560. }
  1561. LocalFree(DependName);
  1562. }
  1563. Cleanup:
  1564. return(ApiStatus);
  1565. }
  1566. #if DBG
  1567. VOID
  1568. ScDumpGroups(
  1569. VOID
  1570. )
  1571. /*++
  1572. Routine Description:
  1573. This function walks group list prints out each entry.
  1574. Arguments:
  1575. None.
  1576. Return Value:
  1577. None.
  1578. Note:
  1579. Calls to this routine must be enclosed within #if DBG.
  1580. --*/
  1581. {
  1582. PLOAD_ORDER_GROUP GroupEntry = ScGetOrderGroupList();
  1583. while (GroupEntry != NULL) {
  1584. KdPrintEx((DPFLTR_SCSERVER_ID,
  1585. DEBUG_DEPEND_DUMP,
  1586. "\nOrdered Groups:\n"));
  1587. KdPrintEx((DPFLTR_SCSERVER_ID,
  1588. DEBUG_DEPEND_DUMP,
  1589. "Group: Handle=%08lx Name=%ws RefCount=x%lx\n",
  1590. GroupEntry,
  1591. GroupEntry->GroupName,
  1592. GroupEntry->RefCount));
  1593. GroupEntry = GroupEntry->Next;
  1594. }
  1595. GroupEntry = ScGetStandaloneGroupList();
  1596. while (GroupEntry != NULL) {
  1597. KdPrintEx((DPFLTR_SCSERVER_ID,
  1598. DEBUG_DEPEND_DUMP,
  1599. "Standalone Groups:\n"));
  1600. KdPrintEx((DPFLTR_SCSERVER_ID,
  1601. DEBUG_DEPEND_DUMP,
  1602. "Group: Handle=%08lx Name=%ws RefCount=x%lx\n",
  1603. GroupEntry,
  1604. GroupEntry->GroupName,
  1605. GroupEntry->RefCount));
  1606. GroupEntry = GroupEntry->Next;
  1607. }
  1608. KdPrintEx((DPFLTR_SCSERVER_ID,
  1609. DEBUG_DEPEND_DUMP,
  1610. "\nTDI group is at %08lx" "\nPNP_TDI group is at %08lx\n",
  1611. ScGlobalTDIGroup,
  1612. ScGlobalPNP_TDIGroup));
  1613. }
  1614. VOID
  1615. ScDumpServiceDependencies(
  1616. VOID
  1617. )
  1618. /*++
  1619. Routine Description:
  1620. This function walks the start and stop dependencies lists of every
  1621. service in the service record list.
  1622. Arguments:
  1623. None.
  1624. Return Value:
  1625. None.
  1626. Note:
  1627. Calls to this routine must be enclosed within #if DBG.
  1628. --*/
  1629. {
  1630. PDEPEND_RECORD DependList;
  1631. FOR_ALL_SERVICES(ServiceRecord)
  1632. {
  1633. KdPrintEx((DPFLTR_SCSERVER_ID,
  1634. DEBUG_DEPEND_DUMP,
  1635. "Service: %-20ws UseCount=%lu",
  1636. ServiceRecord->ServiceName,
  1637. ServiceRecord->UseCount));
  1638. KdPrintEx((DPFLTR_SCSERVER_ID,
  1639. DEBUG_DEPEND_DUMP,
  1640. " MemberOfGroup=%08lx ",
  1641. ServiceRecord->MemberOfGroup));
  1642. if (ServiceRecord->MemberOfGroup != NULL) {
  1643. if (ServiceRecord->MemberOfGroup->RefCount != MAXULONG) {
  1644. KdPrintEx((DPFLTR_SCSERVER_ID,
  1645. DEBUG_DEPEND_DUMP,
  1646. "SG=%ws\n",
  1647. ServiceRecord->MemberOfGroup->GroupName));
  1648. }
  1649. else if (ServiceRecord->MemberOfGroup->RefCount == MAXULONG) {
  1650. KdPrintEx((DPFLTR_SCSERVER_ID,
  1651. DEBUG_DEPEND_DUMP,
  1652. "OG=%ws\n",
  1653. ServiceRecord->MemberOfGroup->GroupName));
  1654. }
  1655. }
  1656. else {
  1657. KdPrintEx((DPFLTR_SCSERVER_ID, DEBUG_DEPEND_DUMP, "\n"));
  1658. }
  1659. if (ServiceRecord->RegistryGroup != NULL) {
  1660. KdPrintEx((DPFLTR_SCSERVER_ID,
  1661. DEBUG_DEPEND_DUMP,
  1662. " RG=%ws\n",
  1663. ServiceRecord->RegistryGroup->GroupName));
  1664. }
  1665. //
  1666. // Dump start depend
  1667. //
  1668. DependList = ServiceRecord->StartDepend;
  1669. if (DependList != NULL) {
  1670. KdPrintEx((DPFLTR_SCSERVER_ID, DEBUG_DEPEND_DUMP, " StartDepend:\n"));
  1671. }
  1672. while (DependList != NULL) {
  1673. KdPrintEx((DPFLTR_SCSERVER_ID,
  1674. DEBUG_DEPEND_DUMP,
  1675. " %ws\n",
  1676. DependList->DependService->ServiceName));
  1677. DependList = DependList->Next;
  1678. }
  1679. //
  1680. // Dump stop depend
  1681. //
  1682. DependList = ServiceRecord->StopDepend;
  1683. if (DependList != NULL) {
  1684. KdPrintEx((DPFLTR_SCSERVER_ID, DEBUG_DEPEND_DUMP, " StopDepend:\n"));
  1685. }
  1686. while (DependList != NULL) {
  1687. KdPrintEx((DPFLTR_SCSERVER_ID,
  1688. DEBUG_DEPEND_DUMP,
  1689. " %ws\n",
  1690. DependList->DependService->ServiceName));
  1691. DependList = DependList->Next;
  1692. }
  1693. }
  1694. }
  1695. #endif // #if DBG