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.

820 lines
21 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name :
  4. svcsetup.c
  5. Abstract:
  6. Setup program for installing / removing the Internet Services.
  7. This enables setting up the Service GUID and protocol bindings.
  8. Author:
  9. Murali R. Krishnan ( MuraliK ) 08-March-1995
  10. Project:
  11. Internet Services Setup Application
  12. Functions Exported:
  13. Revision History:
  14. --*/
  15. /*++
  16. NOTE:
  17. There are sections in this code which should be modified
  18. whenever a new service is added.
  19. Please look for begin_modifiable_code to identify the code that
  20. may require modification when a new service is added.
  21. -MuraliK
  22. --*/
  23. /************************************************************
  24. * Include Headers
  25. ************************************************************/
  26. #include <nt.h>
  27. #include <ntrtl.h>
  28. #include <nturtl.h>
  29. #include <ntsam.h>
  30. #include <ntlsa.h>
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <windows.h>
  34. #include <winsock2.h>
  35. #include <nspapi.h>
  36. //#include <inetasrv.h>
  37. #include <ftpd.h>
  38. #include <w3svc.h>
  39. #include <msnsvc.h>
  40. // begin_modifiable_code
  41. //
  42. // For each service create a GUID using uuidgen and store it in static
  43. // variable for further use below.
  44. // Gopher Service GUID: 62388f10-58a2-11ce-bec8-00aa0047ae4e
  45. //
  46. static GUID g_GopherGuid = { 0x62388f10, 0x58a2, 0x11ce, 0xbe, 0xc8,
  47. 0x00, 0xaa, 0x00, 0x47, 0xae, 0x4e };
  48. static GUID g_HTTPGuid = { 0x585908c0, 0x6305, 0x11ce, 0xae, 0x00,
  49. 0x00, 0xaa, 0x00, 0x4a, 0x38, 0xb9 };
  50. static GUID g_FTPGuid = { 0x91604620, 0x6305, 0x11ce, 0xae, 0x00,
  51. 0x00, 0xaa, 0x00, 0x4a, 0x38, 0xb9 };
  52. static GUID g_MsnGuid = { 0x11f5d300, 0xada7, 0x11ce, 0xb4, 0x8f,
  53. 0x00, 0xaa, 0x00, 0x6c, 0x35, 0x02 };
  54. //
  55. // For each of the service make an entry in the following list of services
  56. //
  57. // Format for each service info is:
  58. // ServiceInfo( SymbolicName, ServiceName, DisplayName, TcpPort,
  59. // pointer-to-guid-for-the-service)
  60. //
  61. // This is a macro. Please be considerate to use a terminating "\"
  62. //
  63. # define AllServicesInfo() \
  64. ServiceInfo( GOPHER_SERVICE, "GopherSvc", \
  65. "Microsoft Gopher Service (1995)", \
  66. ( 70), &g_GopherGuid, \
  67. GOPHERD_ANONYMOUS_SECRET_W, \
  68. GOPHERD_ROOT_SECRET_W) \
  69. \
  70. ServiceInfo( W3_SERVICE_NAME, "W3Svc", \
  71. "Microsoft HTTP Service (1995)", \
  72. (80), &g_HTTPGuid, \
  73. W3_ANONYMOUS_SECRET_W, \
  74. W3_ROOT_SECRET_W) \
  75. \
  76. ServiceInfo( FTP_SERVICE_NAME, "FtpSvc", \
  77. "Microsoft FTP Service (1995)", \
  78. (21), &g_FTPGuid, \
  79. FTPD_ANONYMOUS_SECRET_W, \
  80. FTPD_ROOT_SECRET_W) \
  81. \
  82. ServiceInfo( MSN_SERVICE_NAME, "MsnSvc", \
  83. "MSN Gateway Service (1995)", \
  84. (568), &g_MsnGuid, \
  85. MSN_ANONYMOUS_SECRET_W, \
  86. MSN_ROOT_SECRET_W) \
  87. //
  88. // end_modifiable_code
  89. //
  90. // begin_unmodifiable_code
  91. //
  92. // Few convenience macros
  93. //
  94. // For setting up the Values in ServiceTypeValue structure.
  95. # define SetServiceTypeValues( pSvcTypeValue, dwNS, dwType, dwSize, lpValName, lpVal) \
  96. ( pSvcTypeValue)->dwNameSpace = ( dwNS); \
  97. ( pSvcTypeValue)->dwValueType = ( dwType); \
  98. ( pSvcTypeValue)->dwValueSize = ( dwSize); \
  99. ( pSvcTypeValue)->lpValueName = ( lpValName); \
  100. ( pSvcTypeValue)->lpValue = (PVOID ) ( lpVal); \
  101. # define SetServiceTypeValuesDword( pSvcTypeValue, dwNS, lpValName, lpVal) \
  102. SetServiceTypeValues( (pSvcTypeValue), (dwNS), REG_DWORD, sizeof( DWORD), \
  103. ( lpValName), ( lpVal))
  104. typedef struct _ServiceSetupInfo {
  105. char * m_pszServiceName;
  106. char * m_pszDisplayName;
  107. DWORD m_tcpPort; // TCP/IP port number
  108. LPGUID m_lpGuid;
  109. WCHAR * m_pszAnonPwdSecret; // Anonymous password secret name
  110. WCHAR * m_pszRootPwdSecret; // Virtual roots password secret name
  111. } ServiceSetupInfo;
  112. //
  113. // Macro to be used for defining a value for ServiceSetupInfo structure
  114. //
  115. # define ServiceInfoValue( svcName, dispName, tcpPort, lpGuid, AnonPwd, RootPwd) \
  116. { svcName, dispName, tcpPort, lpGuid, AnonPwd, RootPwd }
  117. //
  118. // Form an enumerated list of the service names. These form the
  119. // index into the array of service setup information structures.
  120. //
  121. # define ServiceInfo( sym, svc, disp, tcpport, lpGuid, AnonPwd, RootPwd) \
  122. i ## sym,
  123. typedef enum {
  124. AllServicesInfo()
  125. iMaxService
  126. } eServiceInfo;
  127. # undef ServiceInfo
  128. //
  129. // Form the array of ServiceSetyupInfo objects.
  130. //
  131. # define ServiceInfo( sym, svc, disp, tcpport, lpGuid, AnonPwd, RootPwd) \
  132. ServiceInfoValue( svc, disp, tcpport, lpGuid, AnonPwd, RootPwd),
  133. static ServiceSetupInfo g_svcSetupInfo[] = {
  134. AllServicesInfo()
  135. { NULL, NULL, 0, 0, NULL, NULL} // a sentinel for the array
  136. };
  137. # undef ServiceInfo
  138. // end_unmodifiable_code
  139. /************************************************************
  140. * Functions
  141. ************************************************************/
  142. //
  143. // Local functions
  144. //
  145. static BOOL
  146. CreateServiceEntry( IN char * pszServiceName,
  147. IN char * pszDisplayName,
  148. IN char * pszPath);
  149. static BOOL
  150. CreateEventLogEntry( IN char * pszServiceName,
  151. IN char * pszServicePath
  152. );
  153. static VOID PrintUsageMessage( IN char * pszProgramName);
  154. static BOOL
  155. PerformSetService( IN const ServiceSetupInfo * pSvcSetupInfo,
  156. IN DWORD svcOperation);
  157. DWORD
  158. SetSecret(
  159. IN LPWSTR Server,
  160. IN LPWSTR SecretName,
  161. IN LPWSTR pSecret,
  162. IN DWORD cbSecret
  163. );
  164. int __cdecl
  165. main( int argc, char * argv[] )
  166. {
  167. BOOL fRet = TRUE;
  168. char * pszProgram = argv[ 0];
  169. char * pszOperation;
  170. char * pszSvc;
  171. int i;
  172. ServiceSetupInfo * pSvcSetupInfo = NULL;
  173. DWORD svcOperation = SERVICE_ADD_TYPE;
  174. //
  175. // Parse the command line arguments.
  176. //
  177. if ( argc != 3) {
  178. PrintUsageMessage( argv[ 0]);
  179. return ( 1);
  180. }
  181. pszSvc = argv[ 1];
  182. pszOperation = argv[ 2];
  183. //
  184. // Lookup the service setup info structure from the array
  185. // command line argument 1 is the service name.
  186. // Find the associated service setup info structure.
  187. //
  188. for( i = 0; i < iMaxService; i++) {
  189. if ( _stricmp( g_svcSetupInfo[ i].m_pszServiceName, pszSvc) == 0) {
  190. pSvcSetupInfo = ( g_svcSetupInfo + i);
  191. break;
  192. }
  193. } // for
  194. if ( pSvcSetupInfo == NULL) {
  195. fprintf( stderr, " Unknown Service Name %s specified.\n", pszSvc);
  196. PrintUsageMessage( pszProgram);
  197. return ( 1);
  198. }
  199. //
  200. // Identify the operation to be performed and execute the same.
  201. //
  202. if ( _strnicmp( pszOperation, "/add", 4) == 0) {
  203. svcOperation = SERVICE_ADD_TYPE;
  204. } else if ( _strnicmp( pszOperation, "/delete", 4) == 0) {
  205. svcOperation = SERVICE_DELETE_TYPE;
  206. } else if ( _strnicmp( pszOperation, "/svc:", 5) == 0) {
  207. fRet = CreateServiceEntry( pSvcSetupInfo->m_pszServiceName,
  208. pSvcSetupInfo->m_pszDisplayName,
  209. strchr( pszOperation, ':') + 1);
  210. } else if ( _strnicmp( pszOperation, "/eventlog:", 10) == 0) {
  211. fRet = CreateEventLogEntry( pSvcSetupInfo->m_pszServiceName,
  212. strchr( pszOperation, ':') + 1);
  213. } else {
  214. PrintUsageMessage( pszProgram);
  215. SetLastError( ERROR_INVALID_PARAMETER);
  216. fRet = FALSE;
  217. }
  218. fRet = fRet && PerformSetService( pSvcSetupInfo, svcOperation);
  219. return ( (fRet) ? NO_ERROR : GetLastError());
  220. } // main()
  221. VOID
  222. PrintUsageMessage( IN char * pszProgramName)
  223. /*++
  224. Prints the usage message along with possible list of services allowed.
  225. --*/
  226. {
  227. int i;
  228. fprintf( stderr,
  229. "Usage:\n %s <service-name> "
  230. " [ /add | /delete | /svc:<path-of-process>"
  231. " /eventlog:<eventlog-messages-binary> \n",
  232. pszProgramName);
  233. //
  234. // Print the services name.
  235. //
  236. fprintf( stderr, "\t Possible Services: \n\t\tName\t Other Details\n");
  237. for( i = 0; i < iMaxService; i++) {
  238. fprintf( stderr, "\t\t %s [ %s] TcpPort=%d) \n",
  239. g_svcSetupInfo[ i].m_pszServiceName,
  240. g_svcSetupInfo[ i].m_pszDisplayName,
  241. g_svcSetupInfo[ i].m_tcpPort
  242. );
  243. } // for
  244. return;
  245. } // PrintUsageMessage()
  246. /************************************************************
  247. * Following are general functions usable by other Internet services
  248. ************************************************************/
  249. static BOOL
  250. PerformSetService( IN const ServiceSetupInfo * pSvcSetupInfo,
  251. IN DWORD svcOperation)
  252. {
  253. int err;
  254. WSADATA WsaData;
  255. SERVICE_INFO serviceInfo;
  256. LPSERVICE_TYPE_INFO_ABS lpServiceTypeInfo ;
  257. LPSERVICE_TYPE_VALUE_ABS lpServiceTypeValues ;
  258. BYTE serviceTypeInfoBuffer[sizeof(SERVICE_TYPE_INFO) + 1024];
  259. // Buffer large enough for 3 values ( SERVICE_TYPE_VALUE_ABS)
  260. DWORD Value1 = 1 ;
  261. DWORD TcpPortValue = pSvcSetupInfo->m_tcpPort;
  262. DWORD statusFlags;
  263. //
  264. // Initialize Windows Sockets DLL
  265. //
  266. err = WSAStartup( 0x0101, & WsaData);
  267. if ( err == SOCKET_ERROR) {
  268. fprintf( stderr, " WSAStartup() Failed. Error = %ld\n",
  269. GetLastError());
  270. return ( FALSE);
  271. }
  272. //
  273. // Setup the service information to be passed to SetService() for adding
  274. // or deleting this service. Most of the SERVICE_INFO fields are not
  275. // required for add or delete operation. The main things of interests are
  276. // GUIDs and ServiceSpecificInfo structure.
  277. //
  278. memset( (PVOID ) & serviceInfo, 0, sizeof( serviceInfo)); //null all fields
  279. serviceInfo.lpServiceType = pSvcSetupInfo->m_lpGuid;
  280. //
  281. // The "Blob" will contain the service specific information.
  282. // In this case, fill it with a SERVICE_TYPE_INFO_ABS structure
  283. // and associated information.
  284. //
  285. serviceInfo.ServiceSpecificInfo.pBlobData = serviceTypeInfoBuffer;
  286. serviceInfo.ServiceSpecificInfo.cbSize = sizeof( serviceTypeInfoBuffer);
  287. lpServiceTypeInfo = (LPSERVICE_TYPE_INFO_ABS ) serviceTypeInfoBuffer;
  288. //
  289. // There's only one value for TCP.
  290. //
  291. lpServiceTypeInfo->dwValueCount = 1;
  292. lpServiceTypeInfo->lpTypeName = pSvcSetupInfo->m_pszServiceName;
  293. lpServiceTypeValues = lpServiceTypeInfo->Values;
  294. SetServiceTypeValuesDword( ( lpServiceTypeValues + 0),
  295. NS_DNS,
  296. SERVICE_TYPE_VALUE_TCPPORT,
  297. &TcpPortValue);
  298. //
  299. // Finally, call SetService to actually perform the operation.
  300. //
  301. err = SetService(
  302. NS_DEFAULT, // all default name spaces
  303. svcOperation, // either ADD or DELETE
  304. 0, // dwFlags not used
  305. &serviceInfo, // the service info structure
  306. NULL, // lpServiceAsyncInfo
  307. &statusFlags // additional status information
  308. );
  309. if ( err != NO_ERROR ) {
  310. fprintf( stderr, "SetService failed: %ld\n", GetLastError( ) );
  311. } else {
  312. printf( "SetService( %s) succeeded, status flags = %ld\n",
  313. pSvcSetupInfo->m_pszServiceName, statusFlags );
  314. }
  315. //
  316. // Create the LSA secrets for the anonymous user password and the virtual
  317. // root passwords
  318. //
  319. if ( !SetSecret( NULL,
  320. pSvcSetupInfo->m_pszAnonPwdSecret,
  321. L"",
  322. sizeof(WCHAR) ) ||
  323. !SetSecret( NULL,
  324. pSvcSetupInfo->m_pszRootPwdSecret,
  325. L"",
  326. sizeof(WCHAR) ))
  327. {
  328. err = GetLastError();
  329. fprintf( stderr,
  330. "SetService( %s ) failed to create Lsa Secrets for anonymous\n"
  331. "username password or virtual root passwords. Error = %d\n",
  332. pSvcSetupInfo->m_pszServiceName,
  333. err);
  334. }
  335. //
  336. // For HTTP, set the catapult impersonation user for the proxy
  337. //
  338. if ( pSvcSetupInfo->m_lpGuid == &g_HTTPGuid )
  339. {
  340. if ( !SetSecret( NULL,
  341. W3_PROXY_USER_SECRET_W,
  342. L"",
  343. sizeof(WCHAR) ))
  344. {
  345. err = GetLastError();
  346. fprintf( stderr,
  347. "SetService( %s ) failed to create Lsa Secrets proxy user\n"
  348. "Error = %d\n",
  349. pSvcSetupInfo->m_pszServiceName,
  350. err);
  351. }
  352. }
  353. return ( err != NO_ERROR);
  354. } // PerformSetService()
  355. static BOOL
  356. CreateServiceEntry( IN char * pszServiceName,
  357. IN char * pszDisplayName,
  358. IN char * pszPath)
  359. /*++
  360. This function calls the service controller to create a new service.
  361. Arguments:
  362. pszServiceName pointer to service name
  363. pszDisplayName pointer to Display name
  364. pszPath pointer to null-terminated string containing the path for
  365. the service DLL.
  366. Returns:
  367. TRUE on success and FALSE if there is any failure.
  368. Use GetLastError() to get further error code on failure.
  369. --*/
  370. {
  371. BOOL fReturn = FALSE;
  372. SC_HANDLE hServiceManager;
  373. //
  374. // Create the service.
  375. //
  376. hServiceManager = OpenSCManager( NULL, // machine name
  377. NULL, // database name
  378. STANDARD_RIGHTS_REQUIRED
  379. | SC_MANAGER_CREATE_SERVICE );
  380. if ( hServiceManager != NULL) {
  381. SC_HANDLE hService;
  382. //
  383. // create the service itself.
  384. //
  385. hService = CreateService( hServiceManager,
  386. pszServiceName,
  387. pszDisplayName,
  388. GENERIC_READ | GENERIC_WRITE,
  389. SERVICE_WIN32_SHARE_PROCESS,
  390. SERVICE_DEMAND_START,
  391. SERVICE_ERROR_NORMAL,
  392. pszPath,
  393. NULL, // lpszLoadOrderGroup
  394. NULL, // lpdwTagId
  395. NULL, // lpszDependencies
  396. NULL, // lpszStartUserName
  397. NULL ); // lpszPassword
  398. if( hService != NULL ) {
  399. fReturn = TRUE;
  400. CloseServiceHandle( hService);
  401. }
  402. CloseServiceHandle( hServiceManager);
  403. } else {
  404. fprintf( stderr, "OpenSCManager failed: %ld\n", GetLastError() );
  405. }
  406. fprintf( stderr, " %s created with path %s. Return %d ( Error = %ld)\n",
  407. pszServiceName, pszPath,
  408. fReturn, ( fReturn) ? NO_ERROR : GetLastError());
  409. return ( fReturn);
  410. } // CreateServiceEntry()
  411. # define EVENT_LOG_REG_KEY \
  412. "System\\CurrentControlSet\\Services\\EventLog\\System"
  413. # define LEN_EVENT_LOG_REG_KEY ( sizeof( EVENT_LOG_REG_KEY))
  414. static BOOL
  415. CreateEventLogEntry( IN char * pszServiceName,
  416. IN char * pszServicePath
  417. )
  418. /*++
  419. This function creates an entry for a service in the Eventlog registry
  420. so that the messages of the service may be decoded.
  421. Arguments:
  422. pszServiceName pointer to string containing the service name.
  423. pszServicePath pointer to string containing the path for the service
  424. dll with the embedded messages.
  425. Returns:
  426. TRUE on success and FALSE if there are any errors. Use GetLastError()
  427. to get detailed error message.
  428. --*/
  429. {
  430. char rgchKeyName[ LEN_EVENT_LOG_REG_KEY + 100];
  431. HKEY hkeyReg;
  432. LONG err;
  433. DWORD Disposition;
  434. if ( strlen( pszServiceName) >= 100) {
  435. SetLastError( ERROR_NOT_ENOUGH_MEMORY);
  436. return ( FALSE);
  437. }
  438. sprintf( rgchKeyName, "%s\\%s", EVENT_LOG_REG_KEY, pszServiceName);
  439. //
  440. // Add the data to the EventLog's registry key so that the
  441. // log insertion strings may be found by the Event Viewer.
  442. //
  443. err = RegCreateKeyEx( HKEY_LOCAL_MACHINE,
  444. rgchKeyName,
  445. 0,
  446. NULL,
  447. REG_OPTION_NON_VOLATILE,
  448. KEY_WRITE,
  449. NULL,
  450. &hkeyReg,
  451. &Disposition );
  452. if( err != 0 ) {
  453. fprintf( stderr, "RegCreateKeyEx failed: %ld\n", err );
  454. SetLastError( err);
  455. return ( FALSE);
  456. }
  457. err = RegSetValueEx( hkeyReg,
  458. "EventMessageFile",
  459. 0,
  460. REG_EXPAND_SZ,
  461. pszServicePath,
  462. strlen( pszServicePath ) + 1 );
  463. if( err == 0 ) {
  464. DWORD Value;
  465. Value = ( EVENTLOG_ERROR_TYPE |
  466. EVENTLOG_WARNING_TYPE |
  467. EVENTLOG_INFORMATION_TYPE
  468. );
  469. err = RegSetValueEx( hkeyReg,
  470. "TypesSupported",
  471. 0,
  472. REG_DWORD,
  473. (CONST BYTE *)&Value,
  474. sizeof(Value) );
  475. }
  476. RegCloseKey( hkeyReg );
  477. if( err != 0 ) {
  478. fprintf( stderr, "RegSetValueEx failed: %ld\n", err );
  479. SetLastError( err);
  480. }
  481. return ( err == 0);
  482. } // CreateEventLogEntry()
  483. DWORD
  484. SetSecret(
  485. IN LPWSTR Server,
  486. IN LPWSTR SecretName,
  487. IN LPWSTR pSecret,
  488. IN DWORD cbSecret
  489. )
  490. /*++
  491. Description
  492. Sets the specified LSA secret
  493. Arguments:
  494. Server - Server name (or NULL) secret lives on
  495. SecretName - Name of the LSA secret
  496. pSecret - Pointer to secret memory
  497. cbSecret - Size of pSecret memory block
  498. Note:
  499. --*/
  500. {
  501. LSA_HANDLE hPolicy;
  502. UNICODE_STRING unicodePassword;
  503. UNICODE_STRING unicodeServer;
  504. NTSTATUS ntStatus;
  505. OBJECT_ATTRIBUTES ObjectAttributes;
  506. LSA_HANDLE hSecret;
  507. UNICODE_STRING unicodeSecret;
  508. RtlInitUnicodeString( &unicodeServer,
  509. Server );
  510. //
  511. // Initialize the unicode string by hand so we can handle '\0' in the
  512. // string
  513. //
  514. unicodePassword.Buffer = pSecret;
  515. unicodePassword.Length = (USHORT) cbSecret;
  516. unicodePassword.MaximumLength = (USHORT) cbSecret;
  517. //
  518. // Open a policy to the remote LSA
  519. //
  520. InitializeObjectAttributes( &ObjectAttributes,
  521. NULL,
  522. 0L,
  523. NULL,
  524. NULL );
  525. ntStatus = LsaOpenPolicy( &unicodeServer,
  526. &ObjectAttributes,
  527. POLICY_ALL_ACCESS,
  528. &hPolicy );
  529. if ( !NT_SUCCESS( ntStatus ) )
  530. {
  531. SetLastError( RtlNtStatusToDosError( ntStatus ) );
  532. return FALSE;
  533. }
  534. //
  535. // Create or open the LSA secret
  536. //
  537. RtlInitUnicodeString( &unicodeSecret,
  538. SecretName );
  539. ntStatus = LsaCreateSecret( hPolicy,
  540. &unicodeSecret,
  541. SECRET_ALL_ACCESS,
  542. &hSecret );
  543. if ( !NT_SUCCESS( ntStatus ))
  544. {
  545. //
  546. // If the secret already exists, then we just need to open it
  547. //
  548. if ( ntStatus == STATUS_OBJECT_NAME_COLLISION )
  549. {
  550. ntStatus = LsaOpenSecret( hPolicy,
  551. &unicodeSecret,
  552. SECRET_ALL_ACCESS,
  553. &hSecret );
  554. }
  555. if ( !NT_SUCCESS( ntStatus ))
  556. {
  557. LsaClose( hPolicy );
  558. SetLastError( RtlNtStatusToDosError( ntStatus ) );
  559. return FALSE;
  560. }
  561. }
  562. //
  563. // Set the secret value
  564. //
  565. ntStatus = LsaSetSecret( hSecret,
  566. &unicodePassword,
  567. &unicodePassword );
  568. LsaClose( hSecret );
  569. LsaClose( hPolicy );
  570. if ( !NT_SUCCESS( ntStatus ))
  571. {
  572. return RtlNtStatusToDosError( ntStatus );
  573. }
  574. return TRUE;
  575. }
  576. /************************ End of File ***********************/