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.

624 lines
14 KiB

  1. /**********************************************************************/
  2. /** Microsoft Windows NT **/
  3. /** Copyright(c) Microsoft Corp., 1993 **/
  4. /**********************************************************************/
  5. /*
  6. main.cxx
  7. This module contains the main startup code for the FTPD Service.
  8. Functions exported by this module:
  9. ServiceEntry
  10. FILE HISTORY:
  11. KeithMo 07-Mar-1993 Created.
  12. KeithMo 07-Jan-1994 Made it a DLL (part of TCPSVCS.EXE).
  13. MuraliK 21-March-1995 Modified it to use InternetServices
  14. common dll ( tcpsvcs.dll)
  15. MuraliK 11-April-1995 Added global ftp server config objects etc.
  16. ( removed usage of Init and Terminate UserDatabase)
  17. */
  18. #include <ftpdp.hxx>
  19. #include <apiutil.h>
  20. #include <inetsvcs.h>
  21. //
  22. // Private constants.
  23. //
  24. #define FTPD_MODULE_NAME_A "ftpsvc2.dll"
  25. #define DEFAULT_RECV_BUFFER_SIZE (8192)
  26. //
  27. // Global variables for service info and debug variables.
  28. //
  29. DEFINE_TSVC_INFO_INTERFACE( );
  30. DECLARE_DEBUG_PRINTS_OBJECT();
  31. #ifndef _NO_TRACING_
  32. #include <initguid.h>
  33. DEFINE_GUID(IisFtpGuid,
  34. 0x784d891F, 0xaa8c, 0x11d2, 0x92, 0x5e, 0x00, 0xc0, 0x4f, 0x72, 0xd9, 0x0e);
  35. #else
  36. DECLARE_DEBUG_VARIABLE();
  37. #endif
  38. //
  39. // The following critical section synchronizes execution in ServiceEntry().
  40. // This is necessary because the NT Service Controller may reissue a service
  41. // start notification immediately after we have set our status to stopped.
  42. // This can lead to an unpleasant race condition in ServiceEntry() as one
  43. // thread cleans up global state as another thread is initializing it.
  44. //
  45. CRITICAL_SECTION g_csServiceEntryLock;
  46. //
  47. // Private prototypes.
  48. //
  49. APIERR
  50. InitializeService(
  51. LPVOID lpContext
  52. );
  53. APIERR
  54. TerminateService(
  55. LPVOID lpContext
  56. );
  57. extern
  58. VOID
  59. FtpdNewConnection(
  60. IN SOCKET sNew,
  61. IN SOCKADDR_IN * psockaddr,
  62. IN PVOID EndpointContext,
  63. IN PVOID EndpointObject
  64. );
  65. extern
  66. VOID
  67. FtpdNewConnectionEx(
  68. IN PVOID patqContext,
  69. IN DWORD cbWritten,
  70. IN DWORD dwError,
  71. IN OVERLAPPED * lpo
  72. );
  73. DWORD
  74. PrintOutCurrentTime(
  75. IN CHAR * pszFile,
  76. IN int lineNum
  77. );
  78. # ifdef CHECK_DBG
  79. # define PRINT_CURRENT_TIME_TO_DBG() PrintOutCurrentTime( __FILE__, __LINE__)
  80. # else
  81. # define PRINT_CURRENT_TIME_TO_DBG() ( NO_ERROR)
  82. # endif // CHECK_DBG
  83. VOID
  84. ServiceEntry(
  85. DWORD cArgs,
  86. LPSTR pArgs[],
  87. PTCPSVCS_GLOBAL_DATA pGlobalData // unused
  88. )
  89. /*++
  90. Routine:
  91. This is the "real" entrypoint for the service. When
  92. the Service Controller dispatcher is requested to
  93. start a service, it creates a thread that will begin
  94. executing this routine.
  95. Arguments:
  96. cArgs - Number of command line arguments to this service.
  97. pArgs - Pointers to the command line arguments.
  98. Returns:
  99. None. Does not return until service is stopped.
  100. --*/
  101. {
  102. APIERR err = NO_ERROR;
  103. BOOL fInitSvcObject = FALSE;
  104. EnterCriticalSection( &g_csServiceEntryLock );
  105. if ( !InitCommonDlls() )
  106. {
  107. err = GetLastError();
  108. LeaveCriticalSection( &g_csServiceEntryLock );
  109. goto notify_scm;
  110. }
  111. //
  112. // Initialize the service status structure.
  113. //
  114. g_pInetSvc = new FTP_IIS_SERVICE(
  115. FTPD_SERVICE_NAME,
  116. FTPD_MODULE_NAME_A,
  117. FTPD_PARAMETERS_KEY_A,
  118. INET_FTP_SVC_ID,
  119. INET_FTP_SVCLOC_ID,
  120. FALSE,
  121. 0,
  122. FtpdNewConnection,
  123. FtpdNewConnectionEx,
  124. ProcessAtqCompletion
  125. );
  126. //
  127. // If we couldn't allocate memory for the service info structure,
  128. // then we're totally hozed.
  129. //
  130. if( (g_pInetSvc != NULL) && g_pInetSvc->IsActive() ) {
  131. fInitSvcObject = TRUE;
  132. //
  133. // Start the service. This blocks until the service is shutdown.
  134. //
  135. err = g_pInetSvc->StartServiceOperation(
  136. SERVICE_CTRL_HANDLER(),
  137. InitializeService,
  138. TerminateService
  139. );
  140. if( err != NO_ERROR) {
  141. //
  142. // The event has already been logged.
  143. //
  144. DBGPRINTF(( DBG_CONTEXT,
  145. "FTP ServiceEntry: StartServiceOperation returned %d\n",
  146. err ));
  147. }
  148. } else {
  149. if ( g_pInetSvc ) {
  150. err = g_pInetSvc->QueryCurrentServiceError();
  151. } else {
  152. err = ERROR_NOT_ENOUGH_MEMORY;
  153. }
  154. }
  155. if( g_pInetSvc != NULL ) {
  156. //
  157. // delete the service object
  158. //
  159. g_pInetSvc->CloseService( );
  160. g_pInetSvc = NULL;
  161. }
  162. TerminateCommonDlls();
  163. LeaveCriticalSection( &g_csServiceEntryLock );
  164. notify_scm:
  165. //
  166. // We need to tell the Service Control Manager that the service
  167. // is stopped if we haven't called g_pInetSvc->StartServiceOperation.
  168. // 1) InitCommonDlls fails, or
  169. // 2) new operator failed, or
  170. // 3) FTP_IIS_SERVICE constructor couldn't initialize properly
  171. //
  172. if ( !fInitSvcObject ) {
  173. SERVICE_STATUS_HANDLE hsvcStatus;
  174. SERVICE_STATUS svcStatus;
  175. hsvcStatus = RegisterServiceCtrlHandler( FTPD_SERVICE_NAME,
  176. SERVICE_CTRL_HANDLER() );
  177. if ( hsvcStatus != NULL_SERVICE_STATUS_HANDLE ) {
  178. svcStatus.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
  179. svcStatus.dwCurrentState = SERVICE_STOPPED;
  180. svcStatus.dwWin32ExitCode = err;
  181. svcStatus.dwServiceSpecificExitCode = err;
  182. svcStatus.dwControlsAccepted = 0;
  183. svcStatus.dwCheckPoint = 0;
  184. svcStatus.dwWaitHint = 0;
  185. SetServiceStatus( hsvcStatus, (LPSERVICE_STATUS) &svcStatus );
  186. }
  187. }
  188. } // ServiceEntry()
  189. //
  190. // Private functions.
  191. //
  192. DWORD
  193. InitializeInstances(
  194. PFTP_IIS_SERVICE pService
  195. )
  196. /*++
  197. Routine Description:
  198. Read the instances from the registry
  199. Arguments:
  200. pService - Server instance added to.
  201. Return Value:
  202. Win32
  203. --*/
  204. {
  205. DWORD err = NO_ERROR;
  206. DWORD i;
  207. DWORD cInstances = 0;
  208. MB mb( (IMDCOM*) pService->QueryMDObject() );
  209. BUFFER buff;
  210. CHAR szKeyName[MAX_PATH+1];
  211. BOOL fMigrateRoots = FALSE;
  212. //
  213. // Open the metabase for write to get an atomic snapshot
  214. //
  215. if ( !mb.Open( "/LM/MSFTPSVC/",
  216. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ))
  217. {
  218. DBGPRINTF(( DBG_CONTEXT,
  219. "InitializeInstances: Cannot open path %s, error %lu\n",
  220. "/LM/MSFTPSVC/", GetLastError() ));
  221. #if 1 // Temporary until setup is modified to create the instances in the metabase
  222. if ( !mb.Open( METADATA_MASTER_ROOT_HANDLE,
  223. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ) ||
  224. !mb.AddObject( "/LM/MSFTPSVC/" ) )
  225. {
  226. DBGPRINTF(( DBG_CONTEXT,
  227. "Unable to create service, error %d\n",
  228. GetLastError() ));
  229. return GetLastError();
  230. }
  231. #else
  232. return GetLastError();
  233. #endif
  234. }
  235. TryAgain:
  236. i = 0;
  237. while ( mb.EnumObjects( "",
  238. szKeyName,
  239. i++ ))
  240. {
  241. BOOL fRet;
  242. DWORD dwInstance;
  243. CHAR szRegKey[MAX_PATH+1];
  244. //
  245. // Get the instance id
  246. //
  247. dwInstance = atoi( szKeyName );
  248. if ( dwInstance == 0 ) {
  249. continue;
  250. }
  251. if ( buff.QuerySize() < (cInstances + 1) * sizeof(DWORD) )
  252. {
  253. if ( !buff.Resize( (cInstances + 10) * sizeof(DWORD)) )
  254. {
  255. return GetLastError();
  256. }
  257. }
  258. ((DWORD *) buff.QueryPtr())[cInstances++] = dwInstance;
  259. }
  260. if ( cInstances == 0 )
  261. {
  262. DBGPRINTF(( DBG_CONTEXT,
  263. "No defined instances\n" ));
  264. if ( !mb.AddObject( "1" ))
  265. {
  266. DBGPRINTF(( DBG_CONTEXT,
  267. "Unable to create first instance, error %d\n",
  268. GetLastError() ));
  269. return GetLastError();
  270. }
  271. fMigrateRoots = TRUE; // Force reg->metabase migration of virtual directories
  272. goto TryAgain;
  273. }
  274. DBG_REQUIRE( mb.Close() );
  275. for ( i = 0; i < cInstances; i++ )
  276. {
  277. DWORD dwInstance = ((DWORD *)buff.QueryPtr())[i];
  278. if( !g_pInetSvc->AddInstanceInfo( dwInstance, fMigrateRoots ) ) {
  279. err = GetLastError();
  280. DBGPRINTF((
  281. DBG_CONTEXT,
  282. "InitializeInstances: cannot create instance %lu, error %lu\n",
  283. dwInstance,
  284. err
  285. ));
  286. break;
  287. }
  288. }
  289. return err;
  290. } // InitializeInstances
  291. APIERR
  292. InitializeService(
  293. LPVOID lpContext
  294. )
  295. /*++
  296. Routine:
  297. This function initializes the various FTPD Service components.
  298. Arguments:
  299. lpContext - Pointer to the service object
  300. Returns:
  301. NO_ERROR if successful, otherwise a Win32
  302. status code.
  303. --*/
  304. {
  305. APIERR err = NO_ERROR;
  306. PFTP_IIS_SERVICE pInetSvc = (PFTP_IIS_SERVICE)lpContext;
  307. PFTP_SERVER_INSTANCE pServer;
  308. DBG_ASSERT( lpContext == g_pInetSvc);
  309. IF_DEBUG( SERVICE_CTRL ) {
  310. DBGPRINTF(( DBG_CONTEXT,"Initializing ftp service\n" ));
  311. }
  312. //
  313. // Initialize various components. The ordering of the
  314. // components is somewhat limited.
  315. // We should initialize connections as the last item,
  316. // since it kicks off the connection thread.
  317. //
  318. err = PRINT_CURRENT_TIME_TO_DBG();
  319. if(( err = InitializeGlobals() ) != NO_ERROR ||
  320. ( err = PRINT_CURRENT_TIME_TO_DBG()) != NO_ERROR ||
  321. ( err = pInetSvc->InitializeSockets()) != NO_ERROR ||
  322. ( err = PRINT_CURRENT_TIME_TO_DBG()) != NO_ERROR ||
  323. ( err = pInetSvc->InitializeDiscovery( )) != NO_ERROR ||
  324. ( err = PRINT_CURRENT_TIME_TO_DBG()) != NO_ERROR ) {
  325. DBGPRINTF(( DBG_CONTEXT,
  326. "cannot initialize ftp service, error %lu\n",err ));
  327. goto exit;
  328. } else {
  329. //
  330. // Success!
  331. //
  332. DBG_ASSERT( err == NO_ERROR);
  333. //
  334. // From discusssions with KeithMo, we decided to punt on the
  335. // default buffer size for now. Later on if performance is
  336. // critical, we will try to improve on this by proper values
  337. // for listen socket.
  338. //
  339. g_SocketBufferSize = DEFAULT_RECV_BUFFER_SIZE;
  340. IF_DEBUG( SERVICE_CTRL ) {
  341. DBGPRINTF(( DBG_CONTEXT, " %s service initialized\n",
  342. pInetSvc->QueryServiceName())
  343. );
  344. }
  345. }
  346. //
  347. // Initialize all instances
  348. //
  349. InitializeInstances(pInetSvc);
  350. g_pFTPStats->UpdateStartTime();
  351. exit:
  352. PRINT_CURRENT_TIME_TO_DBG();
  353. return ( err);
  354. } // InitializeService()
  355. APIERR
  356. TerminateService(
  357. LPVOID lpContext
  358. )
  359. /*++
  360. Routine:
  361. This function cleans up the various FTPD Service components.
  362. Arguments:
  363. lpContext - Pointer to the service object
  364. Returns:
  365. NO_ERROR if successful, otherwise a Win32
  366. status code.
  367. --*/
  368. {
  369. APIERR err = NO_ERROR;
  370. PFTP_IIS_SERVICE pInetSvc = (PFTP_IIS_SERVICE)lpContext;
  371. DBG_ASSERT( lpContext == g_pInetSvc);
  372. IF_DEBUG( SERVICE_CTRL ) {
  373. DBGPRINTF(( DBG_CONTEXT, "terminating service\n" ));
  374. }
  375. PRINT_CURRENT_TIME_TO_DBG();
  376. g_pFTPStats->UpdateStopTime();
  377. //
  378. // Components should be terminated in reverse
  379. // initialization order.
  380. //
  381. g_pInetSvc->ShutdownService( );
  382. PRINT_CURRENT_TIME_TO_DBG();
  383. IF_DEBUG( SERVICE_CTRL ) {
  384. DBGPRINTF(( DBG_CONTEXT, "Ftp service terminated\n" ));
  385. }
  386. PRINT_CURRENT_TIME_TO_DBG();
  387. err = pInetSvc->TerminateDiscovery();
  388. if ( err != NO_ERROR) {
  389. DBGPRINTF( ( DBG_CONTEXT,
  390. "CleanupService( %s):"
  391. " TerminateDiscovery failed, err=%lu\n",
  392. pInetSvc->QueryServiceName(),
  393. err));
  394. }
  395. PRINT_CURRENT_TIME_TO_DBG();
  396. pInetSvc->CleanupSockets();
  397. PRINT_CURRENT_TIME_TO_DBG();
  398. TsCacheFlush( INET_FTP_SVC_ID );
  399. TsFlushMetaCache(METACACHE_FTP_SERVER_ID, TRUE);
  400. TerminateGlobals();
  401. return ( err);
  402. } // TerminateService()
  403. # ifdef CHECK_DBG
  404. DWORD PrintOutCurrentTime(IN CHAR * pszFile, IN int lineNum)
  405. /*++
  406. This function generates the current time and prints it out to debugger
  407. for tracing out the path traversed, if need be.
  408. Arguments:
  409. pszFile pointer to string containing the name of the file
  410. lineNum line number within the file where this function is called.
  411. Returns:
  412. NO_ERROR always.
  413. --*/
  414. {
  415. CHAR szBuffer[1000];
  416. sprintf( szBuffer, "[%u]( %40s, %10d) TickCount = %u\n",
  417. GetCurrentThreadId(),
  418. pszFile,
  419. lineNum,
  420. GetTickCount()
  421. );
  422. OutputDebugString( szBuffer);
  423. return ( NO_ERROR);
  424. } // PrintOutCurrentTime()
  425. # endif // CHECK_DBG
  426. extern "C" {
  427. BOOL
  428. WINAPI
  429. DLLEntry(
  430. HINSTANCE hDll,
  431. DWORD dwReason,
  432. LPVOID lpvReserved
  433. )
  434. {
  435. switch ( dwReason ) {
  436. case DLL_PROCESS_ATTACH:
  437. #ifdef _NO_TRACING_
  438. CREATE_DEBUG_PRINT_OBJECT( FTPD_SERVICE_NAME);
  439. #else
  440. CREATE_DEBUG_PRINT_OBJECT( FTPD_SERVICE_NAME, IisFtpGuid);
  441. #endif
  442. if ( !VALID_DEBUG_PRINT_OBJECT()) {
  443. return FALSE; // Nothing can be done. Debug Print object failed!
  444. }
  445. DBG_REQUIRE( DisableThreadLibraryCalls( hDll ) );
  446. INITIALIZE_CRITICAL_SECTION( &g_csServiceEntryLock );
  447. break;
  448. case DLL_PROCESS_DETACH:
  449. DELETE_DEBUG_PRINT_OBJECT();
  450. DeleteCriticalSection( &g_csServiceEntryLock );
  451. break;
  452. }
  453. return TRUE;
  454. } // DLLEntry
  455. } // extern "C"
  456. /************************ End Of File ************************/