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.

733 lines
19 KiB

  1. #include "precomp.h"
  2. #pragma hdrstop
  3. /*++
  4. Copyright (c) 1991 Microsoft Corporation
  5. Module Name:
  6. sc.c
  7. Abstract:
  8. This contains all the service controller functions.
  9. Author:
  10. Sunil Pai (sunilp) December 1992
  11. --*/
  12. //
  13. // Private function prototypes.
  14. //
  15. VOID
  16. AddServiceToModifiedServiceList(
  17. IN LPSTR ServiceName
  18. );
  19. BOOL
  20. TestAdminWorker(
  21. )
  22. /*++
  23. Routine Description:
  24. Tests for admin privileges by opening the service control manager
  25. with read/write/execute access. Note that this is not a conclusive
  26. test that setup can do whatever it wants. There may still be
  27. operations which fail for lack of security privilege.
  28. Arguments:
  29. None
  30. Return value:
  31. Returns TRUE always. ReturnTextBuffer has "YES" if the current process
  32. has administrative privileges, "NO" otherwise.
  33. --*/
  34. {
  35. SC_HANDLE hSC;
  36. hSC = OpenSCManager(
  37. NULL,
  38. NULL,
  39. GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE
  40. );
  41. if( hSC != NULL ) {
  42. SetReturnText( "YES" );
  43. CloseServiceHandle( hSC );
  44. }
  45. else {
  46. SetReturnText( "NO" );
  47. }
  48. return( TRUE );
  49. }
  50. BOOL
  51. SetupCreateServiceWorker(
  52. LPSTR lpServiceName,
  53. LPSTR lpDisplayName,
  54. DWORD dwServiceType,
  55. DWORD dwStartType,
  56. DWORD dwErrorControl,
  57. LPSTR lpBinaryPathName,
  58. LPSTR lpLoadOrderGroup,
  59. LPSTR lpDependencies,
  60. LPSTR lpServiceStartName,
  61. LPSTR lpPassword
  62. )
  63. /*++
  64. Routine Description:
  65. Setupdll stub for calling CreateService. If CreateService fails with
  66. the error code indicating that the service already exists, this routine
  67. calls the Setupdll stub for ChangeServiceConfig to ensure that the
  68. parameters passed in are reflected in the services database.
  69. Arguments:
  70. lpServiceName - Name of service
  71. lpDisplayName - Localizable name of Service or ""
  72. dwServiceType - Service type, e.g. SERVICE_KERNEL_DRIVER
  73. dwStartType - Service Start value, e.g. SERVICE_BOOT_START
  74. dwErrorControl - Error control value, e.g. SERVICE_ERROR_NORMAL
  75. lpBinaryPathName - Full Path of the binary image containing service
  76. lpLoadOrderGroup - Group name for load ordering or ""
  77. lpDependencies - Multisz string having dependencies. Any dependency
  78. component having + as the first character is a
  79. group dependency. The others are service
  80. dependencies.
  81. lpServiceStartName - Service Start name ( account name in which this
  82. service is run ).
  83. lpPassword - Password used for starting the service.
  84. Return value:
  85. Returns TRUE if successful. FALSE otherwise.
  86. if TRUE then ReturnTextBuffer has "SUCCESS" else it has the error text
  87. to be displayed by the caller.
  88. --*/
  89. {
  90. SC_HANDLE hSC;
  91. SC_HANDLE hSCService;
  92. DWORD dwTag, dw;
  93. BOOL Status = TRUE;
  94. //
  95. // Open a handle to the service controller manager
  96. //
  97. hSC = OpenSCManager(
  98. NULL,
  99. NULL,
  100. SC_MANAGER_ALL_ACCESS
  101. );
  102. if( hSC == NULL ) {
  103. Status = FALSE;
  104. dw = GetLastError();
  105. KdPrint(("SETUPDLL: OpenSCManager Last Error Code: %x", dw));
  106. switch( dw ) {
  107. case ERROR_ACCESS_DENIED:
  108. SetErrorText( IDS_ERROR_PRIVILEGE );
  109. break;
  110. case ERROR_DATABASE_DOES_NOT_EXIST:
  111. case ERROR_INVALID_PARAMETER:
  112. default:
  113. SetErrorText( IDS_ERROR_SCOPEN );
  114. break;
  115. }
  116. return( Status );
  117. }
  118. //
  119. // Create the service using the parameters passed in. Process the optional
  120. // "" parameters passed in and make them NULL.
  121. //
  122. hSCService = CreateService(
  123. hSC,
  124. lpServiceName,
  125. lstrcmpi(lpDisplayName, "") ? lpDisplayName : NULL,
  126. 0,
  127. dwServiceType,
  128. dwStartType,
  129. dwErrorControl,
  130. lpBinaryPathName,
  131. lstrcmpi(lpLoadOrderGroup, "") ? lpLoadOrderGroup : NULL,
  132. lstrcmpi(lpLoadOrderGroup, "") ? &dwTag : NULL,
  133. lpDependencies,
  134. lstrcmpi(lpServiceStartName, "") ? lpServiceStartName : NULL,
  135. lstrcmpi(lpPassword, "") ? lpPassword : NULL
  136. );
  137. //
  138. // If we were unable to create the service, check if the service already
  139. // exists in which case all we need to do is change the configuration
  140. // parameters in the service. If it is any other error return the error
  141. // to the inf
  142. //
  143. if( hSCService != NULL ) {
  144. //
  145. // Note that we won't do anything with the tag. The person calling
  146. // this function will have to do something intelligently with the
  147. // tag. Most of our services have tag values stored in the inf which
  148. // we will directly plop down into the registry entry created. Since
  149. // tags are not important for this boot, the fact that the service
  150. // controller has some tag and the registry entry may have a different
  151. // tag is not important.
  152. //
  153. //
  154. CloseServiceHandle( hSCService );
  155. //
  156. // Log this service name in our 'modified services' list.
  157. //
  158. AddServiceToModifiedServiceList(lpServiceName);
  159. SetReturnText( "SUCCESS" );
  160. Status = TRUE;
  161. }
  162. else {
  163. dw = GetLastError();
  164. if (dw == ERROR_SERVICE_EXISTS) {
  165. Status = SetupChangeServiceConfigWorker(
  166. lpServiceName,
  167. dwServiceType,
  168. dwStartType,
  169. dwErrorControl,
  170. lpBinaryPathName,
  171. lpLoadOrderGroup,
  172. lpDependencies,
  173. lpServiceStartName,
  174. lpPassword,
  175. lpDisplayName
  176. );
  177. }
  178. else {
  179. KdPrint(("SETUPDLL: CreateService Last Error Code: %x", dw));
  180. //
  181. // process error returned
  182. //
  183. switch( dw ) {
  184. case ERROR_ACCESS_DENIED:
  185. SetErrorText( IDS_ERROR_PRIVILEGE );
  186. break;
  187. case ERROR_INVALID_HANDLE:
  188. case ERROR_INVALID_NAME:
  189. case ERROR_INVALID_SERVICE_ACCOUNT:
  190. case ERROR_INVALID_PARAMETER:
  191. case ERROR_CIRCULAR_DEPENDENCY:
  192. default:
  193. SetErrorText( IDS_ERROR_SCSCREATE );
  194. break;
  195. }
  196. Status = FALSE;
  197. }
  198. }
  199. CloseServiceHandle( hSC );
  200. return( Status );
  201. }
  202. BOOL
  203. SetupChangeServiceStartWorker(
  204. LPSTR lpServiceName,
  205. DWORD dwStartType
  206. )
  207. /*++
  208. Routine Description:
  209. Routine to change the start value of a service. This turns
  210. around and calls the setupdll stub to ChangeServiceConfig.
  211. Arguments:
  212. lpServiceName - Name of service
  213. dwStartType - Service Start value, e.g. SERVICE_BOOT_START
  214. Return value:
  215. Returns TRUE if successful. FALSE otherwise.
  216. if TRUE then ReturnTextBuffer has "SUCCESS" else it has the error text
  217. to be displayed by the caller.
  218. --*/
  219. {
  220. return( SetupChangeServiceConfigWorker(
  221. lpServiceName,
  222. SERVICE_NO_CHANGE,
  223. dwStartType,
  224. SERVICE_NO_CHANGE,
  225. "",
  226. "",
  227. NULL,
  228. "",
  229. "",
  230. ""
  231. ));
  232. }
  233. BOOL
  234. SetupChangeServiceConfigWorker(
  235. LPSTR lpServiceName,
  236. DWORD dwServiceType,
  237. DWORD dwStartType,
  238. DWORD dwErrorControl,
  239. LPSTR lpBinaryPathName,
  240. LPSTR lpLoadOrderGroup,
  241. LPSTR lpDependencies,
  242. LPSTR lpServiceStartName,
  243. LPSTR lpPassword,
  244. LPSTR lpDisplayName
  245. )
  246. /*++
  247. Routine Description:
  248. Setupdll stub for ChangeServiceConfig.
  249. Arguments:
  250. lpServiceName - Name of service
  251. dwServiceType - Service type, e.g. SERVICE_KERNEL_DRIVER
  252. dwStartType - Service Start value, e.g. SERVICE_BOOT_START
  253. dwErrorControl - Error control value, e.g. SERVICE_ERROR_NORMAL
  254. lpBinaryPathName - Full Path of the binary image containing service
  255. lpLoadOrderGroup - Group name for load ordering or ""
  256. lpDependencies - Multisz string having dependencies. Any dependency
  257. component having + as the first character is a
  258. group dependency. The others are service
  259. dependencies.
  260. lpServiceStartName - Service Start name ( account name in which this
  261. service is run ).
  262. lpPassword - Password used for starting the service.
  263. lpDisplayName - Localizable name of Service or ""
  264. Return value:
  265. Returns TRUE if successful. FALSE otherwise.
  266. if TRUE then ReturnTextBuffer has "SUCCESS" else it has the error text
  267. to be displayed by the caller.
  268. --*/
  269. {
  270. SC_LOCK sclLock;
  271. SC_HANDLE hSC;
  272. SC_HANDLE hSCService;
  273. DWORD dw;
  274. BOOL Status = TRUE;
  275. //
  276. // Open a handle to the service controller manager
  277. //
  278. hSC = OpenSCManager(
  279. NULL,
  280. NULL,
  281. SC_MANAGER_ALL_ACCESS
  282. );
  283. if( hSC == NULL ) {
  284. Status = FALSE;
  285. dw = GetLastError();
  286. KdPrint(("SETUPDLL: OpenSCManager Last Error Code: %x", dw));
  287. switch( dw ) {
  288. case ERROR_ACCESS_DENIED:
  289. SetErrorText( IDS_ERROR_PRIVILEGE );
  290. break;
  291. case ERROR_DATABASE_DOES_NOT_EXIST:
  292. case ERROR_INVALID_PARAMETER:
  293. default:
  294. SetErrorText( IDS_ERROR_SCOPEN );
  295. break;
  296. }
  297. return( Status );
  298. }
  299. //
  300. // Try to lock the database, if possible. if we are not able to lock
  301. // the database we will still modify the services entry. this is because
  302. // we are just modifying a single service and chances are very low that
  303. // anybody else is manipulating the same entry at the same time.
  304. //
  305. sclLock = LockServiceDatabase( hSC );
  306. //
  307. // Open the service with SERVICE_CHANGE_CONFIG access
  308. //
  309. hSCService = OpenService(
  310. hSC,
  311. lpServiceName,
  312. SERVICE_CHANGE_CONFIG
  313. );
  314. if( hSCService != NULL ) {
  315. if( ChangeServiceConfig(
  316. hSCService,
  317. dwServiceType,
  318. dwStartType,
  319. dwErrorControl,
  320. lstrcmpi(lpBinaryPathName, "") ? lpBinaryPathName : NULL,
  321. lstrcmpi(lpLoadOrderGroup, "") ? lpLoadOrderGroup : NULL,
  322. NULL,
  323. lpDependencies,
  324. lstrcmpi(lpServiceStartName, "") ? lpServiceStartName : NULL,
  325. lstrcmpi(lpPassword, "") ? lpPassword : NULL,
  326. lstrcmpi(lpDisplayName, "") ? lpDisplayName : NULL
  327. ))
  328. {
  329. //
  330. // Log this service name in our 'modified services' list.
  331. //
  332. AddServiceToModifiedServiceList(lpServiceName);
  333. SetReturnText("SUCCESS");
  334. }
  335. else {
  336. dw = GetLastError();
  337. KdPrint(("SETUPDLL: ChangeServiceConfig Last Error Code: %x", dw));
  338. switch( dw ) {
  339. case ERROR_ACCESS_DENIED:
  340. SetErrorText( IDS_ERROR_PRIVILEGE );
  341. break;
  342. case ERROR_SERVICE_MARKED_FOR_DELETE:
  343. SetErrorText( IDS_ERROR_SERVDEL );
  344. break;
  345. case ERROR_INVALID_HANDLE:
  346. case ERROR_INVALID_SERVICE_ACCOUNT:
  347. case ERROR_INVALID_PARAMETER:
  348. case ERROR_CIRCULAR_DEPENDENCY:
  349. default:
  350. SetErrorText( IDS_ERROR_SCSCHANGE );
  351. break;
  352. }
  353. Status = FALSE;
  354. }
  355. CloseServiceHandle( hSCService );
  356. }
  357. else {
  358. dw = GetLastError();
  359. KdPrint(("SETUPDLL: OpenService Last Error Code: %x", dw));
  360. switch( dw ) {
  361. case ERROR_ACCESS_DENIED:
  362. SetErrorText( IDS_ERROR_PRIVILEGE );
  363. break;
  364. case ERROR_INVALID_HANDLE:
  365. case ERROR_INVALID_NAME:
  366. case ERROR_SERVICE_DOES_NOT_EXIST:
  367. default:
  368. SetErrorText( IDS_ERROR_SCSOPEN );
  369. break;
  370. }
  371. Status = FALSE;
  372. }
  373. //
  374. // Unlock the database if locked and then close the service controller
  375. // handle
  376. //
  377. if( sclLock != NULL ) {
  378. UnlockServiceDatabase( sclLock );
  379. }
  380. CloseServiceHandle( hSC );
  381. return( Status );
  382. }
  383. LPSTR
  384. ProcessDependencyList(
  385. LPSTR lpDependenciesList
  386. )
  387. /*++
  388. Routine Description:
  389. This processes an LPSTR containing a list of dependencies {...}
  390. and converts it into a MULTI_SZ string.
  391. Arguments:
  392. lpDependenciesList - List of dependencies. {blah, blah, ... }
  393. Return value:
  394. Returns LPSTR containing a MULTI_SZ string which has the dependencies.
  395. NULL otherwise. Caller should free the string after use.
  396. --*/
  397. {
  398. LPSTR lp = NULL;
  399. RGSZ rgsz;
  400. PSZ psz;
  401. SZ sz;
  402. if ( !lstrcmpi( lpDependenciesList, "" ) ) {
  403. return( lp );
  404. }
  405. rgsz = RgszFromSzListValue( lpDependenciesList );
  406. if( rgsz ) {
  407. //
  408. // process GROUP_IDENTIFIER character
  409. //
  410. psz = rgsz;
  411. while( sz = *psz++ ) {
  412. if( *sz == '\\' ) {
  413. *sz = SC_GROUP_IDENTIFIER;
  414. }
  415. }
  416. //
  417. // Convert the rgsz into a multi sz
  418. //
  419. lp = RgszToMultiSz( rgsz );
  420. RgszFree( rgsz );
  421. }
  422. return ( lp );
  423. }
  424. DWORD
  425. LegacyInfGetModifiedSvcList(
  426. IN LPSTR SvcNameBuffer,
  427. IN UINT SvcNameBufferSize,
  428. OUT PUINT RequiredSize
  429. )
  430. /*++
  431. Routine Description:
  432. This routine is provided solely for use by the Device Installer APIs to be
  433. used immediately after installing a device via a legacy INF (i.e., using
  434. LegacyInfInterpret). The Device Installer sets a variable, LEGACY_DODEVINSTALL,
  435. that causes the service modifications to be logged (the service names are
  436. written to a global multi-sz buffer). If the legacy INF runs successfully,
  437. then the Device Installer calls this API to retrieve the list of services that
  438. were modified. Upon successful completion of this call (i.e., the caller supplies
  439. us with a large enough buffer), we will free our list, and subsequent calls will
  440. return ERROR_NO_MORE_ITEMS.
  441. Arguments:
  442. SvcNameBuffer - Supplies the address of the character buffer that will receive
  443. the list of service names. If this parameter is NULL, then SvcNameBufferSize
  444. must be zero, and the call will fail with ERROR_INSUFFICIENT_BUFFER if there
  445. is a list to retrieve.
  446. SvcNameBufferSize - Supplies the size, in characters, of SvcNameBuffer.
  447. RequiredSize - Supplies the address of a variable that receives the size, in characters,
  448. required to store the service name list.
  449. Return Value:
  450. If the function succeeds (i.e., there's a list to return, and the caller's buffer
  451. was big enough to hold it), the return value is NO_ERROR.
  452. If the function fails, the return value will be one of the following error codes:
  453. ERROR_NO_MORE_ITEMS : Either no services were modified during this INF run,
  454. or the list has already been successfully retrieved via
  455. this API.
  456. ERROR_INSUFFICIENT_BUFFER : The caller-supplied buffer was not large enough to
  457. hold the service name list. In this case, 'RequiredSize'
  458. will contain the necessary buffer size upon return.
  459. --*/
  460. {
  461. //
  462. // If we don't have a service name list, then there's nothing to do.
  463. //
  464. if(!ServicesModified) {
  465. return ERROR_NO_MORE_ITEMS;
  466. }
  467. *RequiredSize = ServicesModifiedSize;
  468. if(ServicesModifiedSize > SvcNameBufferSize) {
  469. return ERROR_INSUFFICIENT_BUFFER;
  470. }
  471. //
  472. // OK, the caller's buffer is large enough to hold our list. Store the list in their
  473. // buffer, and get rid of ours.
  474. //
  475. CopyMemory(SvcNameBuffer,
  476. ServicesModified,
  477. ServicesModifiedSize * sizeof(CHAR)
  478. );
  479. SFree(ServicesModified);
  480. ServicesModified = NULL;
  481. ServicesModifiedSize = 0;
  482. return NO_ERROR;
  483. }
  484. VOID
  485. AddServiceToModifiedServiceList(
  486. IN LPSTR ServiceName
  487. )
  488. /*++
  489. Routine Description:
  490. This routine adds the specified service name to our global 'modified services' list,
  491. if it's not already in the list.
  492. This is only done if the global variable, !LEGACY_DODEVINSTALL, is set.
  493. Arguments:
  494. ServiceName - Specifies the service name to be added to the list.
  495. Return Value:
  496. None.
  497. --*/
  498. {
  499. LPSTR CurSvcName, TempPtr;
  500. DWORD ServiceNameLen, NewBufferSize;
  501. //
  502. // First, check to make sure that we're supposed to be logging service modifications.
  503. //
  504. if(!(TempPtr = SzFindSymbolValueInSymTab("!LEGACY_DODEVINSTALL")) ||
  505. lstrcmp(TempPtr, "YES")) {
  506. //
  507. // Then we weren't invoked by the Device Installer, so no logging should be done.
  508. //
  509. return;
  510. }
  511. //
  512. // Now, search through the existing list to see if this service name is already
  513. // present.
  514. //
  515. if(ServicesModified) {
  516. for(CurSvcName = ServicesModified;
  517. *CurSvcName;
  518. CurSvcName += lstrlen(CurSvcName) + 1) {
  519. if(!lstrcmpi(ServiceName, CurSvcName)) {
  520. //
  521. // The service is already in the list--nothing to do.
  522. //
  523. return;
  524. }
  525. }
  526. }
  527. //
  528. // The service wasn't already in the list. Allocate/grow the buffer to accommodate
  529. // this new name.
  530. //
  531. ServiceNameLen = lstrlen(ServiceName);
  532. if(ServicesModified) {
  533. TempPtr = SRealloc(ServicesModified,
  534. (NewBufferSize = ServicesModifiedSize + ServiceNameLen + 1) * sizeof(CHAR)
  535. );
  536. if(TempPtr) {
  537. ServicesModified = TempPtr;
  538. lstrcpy(&(ServicesModified[ServicesModifiedSize-1]), ServiceName);
  539. ServicesModifiedSize = NewBufferSize;
  540. //
  541. // Now add extra terminating NULL at the end.
  542. //
  543. ServicesModified[ServicesModifiedSize-1] = '\0';
  544. }
  545. } else {
  546. if(ServicesModified = SAlloc((NewBufferSize = ServiceNameLen + 2) * sizeof(CHAR))) {
  547. ServicesModifiedSize = NewBufferSize;
  548. lstrcpy(ServicesModified, ServiceName);
  549. //
  550. // Now add extra terminating NULL at the end.
  551. //
  552. ServicesModified[ServiceNameLen+1] = '\0';
  553. }
  554. }
  555. }