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.

702 lines
16 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. rpcex.cxx
  5. Abstract:
  6. This module defines K2 rpc support.
  7. Author:
  8. Johnson Apacible (JohnsonA) June-19-1996
  9. --*/
  10. #include "ftpdp.hxx"
  11. #include "time.h"
  12. #include "timer.h"
  13. # define ASSUMED_AVERAGE_USER_NAME_LEN ( 40)
  14. # define CONN_LEEWAY ( 3)
  15. //
  16. // Private functions.
  17. //
  18. BOOL
  19. GenDoubleNullStringFromMultiLine( IN LPCWSTR lpsz,
  20. IN OUT LPWSTR * ppszz,
  21. IN OUT LPDWORD pcchLen)
  22. {
  23. DWORD cchLen;
  24. DWORD nLines;
  25. LPWSTR pszNext;
  26. LPCWSTR pszSrc;
  27. DBG_ASSERT( lpsz != NULL && ppszz != NULL && pcchLen != NULL);
  28. // Initialize
  29. *ppszz = NULL;
  30. *pcchLen = 0;
  31. //
  32. // 1. Find the length of the the complete message including new lines
  33. // For each new line we may potentially need an extra blank char
  34. // So allocate space = nLines + length + 2 terminating null chars.
  35. //
  36. cchLen = lstrlenW( lpsz);
  37. for ( pszSrc = lpsz, nLines = 0; *pszSrc != L'\0'; pszSrc++) {
  38. if ( *pszSrc == L'\n') { nLines++; }
  39. } // for
  40. // Allocate sufficient space for the string.
  41. *ppszz = (LPWSTR ) TCP_ALLOC( (cchLen + nLines + 3) * sizeof(WCHAR));
  42. if ( *ppszz == NULL) {
  43. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  44. return (FALSE);
  45. }
  46. //
  47. // walk down the local copy and convert all the line feed characters to
  48. // be null char
  49. //
  50. //
  51. // Since the MULTI_SZ string cannot contain empty strings
  52. // we convert empty lines (ones with just \n into " \0"
  53. // i.e. with a blank character.
  54. //
  55. pszSrc = lpsz;
  56. LPWSTR pszDst = *ppszz;
  57. if ( *pszSrc == L'\n') {
  58. // first line is a linefeed. insert a blank and proceed to next line.
  59. *pszDst = L' ';
  60. *(pszDst + 1) = L'\0';
  61. // move forward
  62. pszDst += 2;
  63. pszSrc++;
  64. }
  65. for( ; *pszSrc != L'\0'; pszSrc++, pszDst++) {
  66. if ( *pszSrc == L'\n') {
  67. // we are at boundary of new line.
  68. if ( pszSrc > lpsz && *(pszSrc - 1) == L'\n') {
  69. // we detected an empty line. Store an additional blank.
  70. *pszDst++ = L' ';
  71. }
  72. *pszDst = L'\0'; // put null char in place of line feed.
  73. } else {
  74. *pszDst = *pszSrc;
  75. }
  76. } // for
  77. *pszDst++ = L'\0'; // terminate with 1st null chars.
  78. *pszDst++ = L'\0'; // terminate with 2nd null chars.
  79. *pcchLen = DIFF(pszDst - *ppszz);
  80. DBG_ASSERT( *pcchLen <= cchLen + nLines + 3);
  81. return ( TRUE);
  82. } // GenDoubleNullStringFromMultiline()
  83. BOOL
  84. FTP_SERVER_INSTANCE::WriteParamsToRegistry(
  85. LPFTP_CONFIG_INFO pConfig
  86. )
  87. /*++
  88. This function writes parameters to the registry
  89. Arguments:
  90. hkey HKEY for registry entry of parameters of FTP server.
  91. pConfig pointer to configuration information.
  92. Returns:
  93. TRUE on success and FALSE if there is any failure.
  94. --*/
  95. {
  96. DWORD err = NO_ERROR;
  97. BOOL fRet = TRUE;
  98. HKEY hkey = NULL;
  99. err = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  100. QueryRegParamKey(),
  101. 0,
  102. KEY_ALL_ACCESS,
  103. &hkey );
  104. if( hkey == NULL )
  105. {
  106. err = ERROR_INVALID_HANDLE;
  107. SetLastError( err);
  108. DBGPRINTF(( DBG_CONTEXT,
  109. "Invalid Registry key given. error %lu\n",
  110. err ));
  111. return FALSE;
  112. }
  113. //
  114. // Write the registry data.
  115. //
  116. if( !err && IsFieldSet( pConfig->FieldControl, FC_FTP_ALLOW_ANONYMOUS ) )
  117. {
  118. err = WriteRegistryDword( hkey,
  119. FTPD_ALLOW_ANONYMOUS,
  120. pConfig->fAllowAnonymous );
  121. }
  122. if( !err && IsFieldSet( pConfig->FieldControl, FC_FTP_ALLOW_GUEST_ACCESS ) )
  123. {
  124. err = WriteRegistryDword( hkey,
  125. FTPD_ALLOW_GUEST_ACCESS,
  126. pConfig->fAllowGuestAccess );
  127. }
  128. if( !err && IsFieldSet( pConfig->FieldControl, FC_FTP_ANNOTATE_DIRECTORIES ) )
  129. {
  130. err = WriteRegistryDword( hkey,
  131. FTPD_ANNOTATE_DIRS,
  132. pConfig->fAnnotateDirectories );
  133. }
  134. if( !err && IsFieldSet( pConfig->FieldControl, FC_FTP_ANONYMOUS_ONLY ) )
  135. {
  136. err = WriteRegistryDword( hkey,
  137. FTPD_ANONYMOUS_ONLY,
  138. pConfig->fAnonymousOnly );
  139. }
  140. if( !err && IsFieldSet( pConfig->FieldControl, FC_FTP_LISTEN_BACKLOG ) )
  141. {
  142. err = WriteRegistryDword( hkey,
  143. FTPD_LISTEN_BACKLOG,
  144. pConfig->dwListenBacklog );
  145. }
  146. if( !err && IsFieldSet( pConfig->FieldControl, FC_FTP_LOWERCASE_FILES ) )
  147. {
  148. err = WriteRegistryDword( hkey,
  149. FTPD_LOWERCASE_FILES,
  150. pConfig->fLowercaseFiles );
  151. }
  152. if( !err && IsFieldSet( pConfig->FieldControl, FC_FTP_MSDOS_DIR_OUTPUT ) )
  153. {
  154. err = WriteRegistryDword( hkey,
  155. FTPD_MSDOS_DIR_OUTPUT,
  156. pConfig->fMsdosDirOutput );
  157. }
  158. if( !err && IsFieldSet( pConfig->FieldControl, FC_FTP_SHOW_4_DIGIT_YEAR ) )
  159. {
  160. err = WriteRegistryDword( hkey,
  161. FTPD_SHOW_4_DIGIT_YEAR,
  162. pConfig->fFourDigitYear );
  163. }
  164. if( !err && IsFieldSet( pConfig->FieldControl, FC_FTP_EXIT_MESSAGE ) )
  165. {
  166. err = RegSetValueExW( hkey,
  167. FTPD_EXIT_MESSAGE_W,
  168. 0,
  169. REG_SZ,
  170. (BYTE *)pConfig->lpszExitMessage,
  171. ( wcslen( pConfig->lpszExitMessage ) + 1 ) *
  172. sizeof(WCHAR) );
  173. }
  174. if( !err && IsFieldSet( pConfig->FieldControl, FC_FTP_GREETING_MESSAGE ) )
  175. {
  176. LPWSTR pszzGreetingMessage = NULL;
  177. DWORD cchLen = 0;
  178. if (GenDoubleNullStringFromMultiLine( pConfig->lpszGreetingMessage,
  179. &pszzGreetingMessage,
  180. &cchLen)
  181. ) {
  182. DBG_ASSERT( pszzGreetingMessage != NULL);
  183. err = RegSetValueExW( hkey,
  184. FTPD_GREETING_MESSAGE_W,
  185. 0,
  186. REG_MULTI_SZ,
  187. (BYTE *) pszzGreetingMessage,
  188. cchLen * sizeof(WCHAR));
  189. TCP_FREE( pszzGreetingMessage);
  190. } else {
  191. err = ERROR_NOT_ENOUGH_MEMORY;
  192. }
  193. }
  194. if( !err && IsFieldSet( pConfig->FieldControl, FC_FTP_BANNER_MESSAGE ) )
  195. {
  196. LPWSTR pszzBannerMessage = NULL;
  197. DWORD cchLen = 0;
  198. if (GenDoubleNullStringFromMultiLine( pConfig->lpszBannerMessage,
  199. &pszzBannerMessage,
  200. &cchLen)
  201. ) {
  202. DBG_ASSERT( pszzBannerMessage != NULL);
  203. err = RegSetValueExW( hkey,
  204. FTPD_BANNER_MESSAGE_W,
  205. 0,
  206. REG_MULTI_SZ,
  207. (BYTE *) pszzBannerMessage,
  208. cchLen * sizeof(WCHAR));
  209. TCP_FREE( pszzBannerMessage);
  210. } else {
  211. err = ERROR_NOT_ENOUGH_MEMORY;
  212. }
  213. }
  214. if( !err && IsFieldSet( pConfig->FieldControl, FC_FTP_MAX_CLIENTS_MESSAGE ) )
  215. {
  216. err = RegSetValueExW( hkey,
  217. FTPD_MAX_CLIENTS_MSG_W,
  218. 0,
  219. REG_SZ,
  220. (BYTE *)pConfig->lpszMaxClientsMessage,
  221. ( wcslen( pConfig->lpszMaxClientsMessage ) + 1 ) *
  222. sizeof(WCHAR) );
  223. }
  224. if( err )
  225. {
  226. SetLastError( err );
  227. return FALSE;
  228. }
  229. return TRUE;
  230. } // WriteParamsToRegistry
  231. DWORD
  232. FTP_IIS_SERVICE::GetServiceConfigInfoSize(
  233. IN DWORD dwLevel
  234. )
  235. {
  236. switch (dwLevel) {
  237. case 1:
  238. return sizeof(FTP_CONFIG_INFO);
  239. }
  240. return 0;
  241. } // FTP_IIS_SERVICE::GetServerConfigInfoSize
  242. BOOL
  243. FTP_SERVER_INSTANCE::SetServiceConfig(
  244. IN PCHAR pBuffer
  245. )
  246. /*++
  247. Description
  248. Sets the common service admin information for the servers specified
  249. in dwServerMask.
  250. Arguments:
  251. pConfig - Admin information to set
  252. Note:
  253. --*/
  254. {
  255. LPFTP_CONFIG_INFO pConfig = (LPFTP_CONFIG_INFO)pBuffer;
  256. DWORD err = NO_ERROR;
  257. HKEY hKey;
  258. err = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  259. QueryRegParamKey(),
  260. 0,
  261. KEY_ALL_ACCESS,
  262. &hKey );
  263. if ( err != NO_ERROR )
  264. {
  265. return(TRUE);
  266. }
  267. //
  268. // If success, then Write the new info to the registry, then read it back.
  269. //
  270. if( WriteParamsToRegistry( pConfig )) {
  271. err = InitFromRegistry( pConfig->FieldControl);
  272. } else {
  273. err = GetLastError();
  274. }
  275. IF_DEBUG( RPC ) {
  276. DBGPRINTF(( DBG_CONTEXT,
  277. "FtpSetServiceConfig returns with %d %lu\n",
  278. err ));
  279. }
  280. return(err == NO_ERROR);
  281. } // FTP_SERVER_INSTANCE::SetServiceConfig
  282. BOOL
  283. FTP_SERVER_INSTANCE::GetServiceConfig(
  284. IN PCHAR pBuffer,
  285. IN DWORD dwLevel
  286. )
  287. /*++
  288. Description
  289. Retrieves the admin information
  290. Arguments:
  291. pBuffer - Buffer to fill up.
  292. dwLevel - info level of information to return.
  293. Note:
  294. --*/
  295. {
  296. LPFTP_CONFIG_INFO pConfig = (LPFTP_CONFIG_INFO)pBuffer;
  297. DWORD err = NO_ERROR;
  298. ZeroMemory( pConfig, sizeof(FTP_CONFIG_INFO) );
  299. //
  300. // Obtain and Return the admin information.
  301. //
  302. err = GetConfigInformation( pConfig);
  303. IF_DEBUG( RPC) {
  304. DBGPRINTF(( DBG_CONTEXT,
  305. "FtprGetAdminInformation() returns Error=%u\n",
  306. err));
  307. }
  308. return (err == NO_ERROR);
  309. } // FTP_SERVER_INSTANCE::GetServiceConfig
  310. BOOL
  311. FTP_SERVER_INSTANCE::EnumerateUsers(
  312. OUT PCHAR * pBuffer,
  313. OUT PDWORD nRead
  314. )
  315. /*++
  316. Description
  317. Enumerates the connected users.
  318. Arguments:
  319. pBuffer - Buffer to fill up.
  320. nRead - number of entries filled
  321. --*/
  322. {
  323. DWORD err;
  324. DWORD cbBuffer;
  325. LPIIS_USER_INFO_1 pInfo;
  326. IF_DEBUG( RPC ) {
  327. DBGPRINTF(( DBG_CONTEXT,"Entering FtpEnumerateUsers\n"));
  328. }
  329. //
  330. // Determine the necessary buffer size.
  331. //
  332. cbBuffer = (GetCurrentConnectionsCount() + CONN_LEEWAY)
  333. * sizeof( IIS_USER_INFO_1 );
  334. *nRead = 0;
  335. pInfo = (LPIIS_USER_INFO_1)MIDL_user_allocate( cbBuffer);
  336. if (pInfo == NULL) {
  337. err = ERROR_NOT_ENOUGH_MEMORY;
  338. } else {
  339. //
  340. // Make a first attempt at enumerating the user info
  341. //
  342. err = NO_ERROR;
  343. if ( !::EnumerateUsers( (PCHAR)pInfo, &cbBuffer, nRead, this )) {
  344. //
  345. // Free up old buffer and allocate big one now.
  346. // We will try once more to get the data again
  347. // with a larger buffer.
  348. //
  349. if ( cbBuffer > 0) {
  350. MIDL_user_free( pInfo );
  351. pInfo = (LPIIS_USER_INFO_1)MIDL_user_allocate(cbBuffer);
  352. if( pInfo == NULL ) {
  353. err = ERROR_NOT_ENOUGH_MEMORY;
  354. } else {
  355. //
  356. // Since we do not lock the active connections list
  357. // it is possible some one came in now and hence the
  358. // buffer is insufficient to hold all people.
  359. // Ignore this case, as we are never
  360. // going to be accurate
  361. //
  362. ::EnumerateUsers( (PCHAR)pInfo, &cbBuffer, nRead, this );
  363. if ( *nRead == 0 ) {
  364. MIDL_user_free(pInfo);
  365. pInfo = NULL;
  366. }
  367. }
  368. } // cbBuffer > 0
  369. } // if unsuccessful at first attempt
  370. }
  371. if( err != NO_ERROR ) {
  372. IF_DEBUG( RPC ) {
  373. DBGPRINTF(( DBG_CONTEXT,
  374. "I_FtprEnumerateUsers failed. Error = %lu\n",
  375. err ));
  376. }
  377. SetLastError(err);
  378. return(FALSE);
  379. }
  380. *pBuffer = (PCHAR)pInfo;
  381. IF_DEBUG( RPC ) {
  382. DBGPRINTF(( DBG_CONTEXT,
  383. "FtpEnumerateUsers returns %d entries, buffer [%x]\n",
  384. *nRead, *pBuffer ));
  385. }
  386. return TRUE;
  387. } // EnumerateUsers
  388. BOOL
  389. FTP_SERVER_INSTANCE::DisconnectUser(
  390. IN DWORD dwIdUser
  391. )
  392. /*++
  393. Description
  394. Disconnect the user
  395. Arguments:
  396. dwIdUser - Identifies the user to disconnect. If 0,
  397. then disconnect ALL users.
  398. --*/
  399. {
  400. IF_DEBUG( RPC ) {
  401. DBGPRINTF(( DBG_CONTEXT,
  402. "Entering FtpDisconnectUsers with id[%d]\n", dwIdUser));
  403. }
  404. if ( !::DisconnectUser( dwIdUser, this ) ) {
  405. IF_DEBUG( RPC ) {
  406. DBGPRINTF(( DBG_CONTEXT,
  407. "DisconnectUser failed with %d\n", GetLastError()));
  408. }
  409. SetLastError(NERR_UserNotFound);
  410. return(FALSE);
  411. }
  412. return(TRUE);
  413. } // DisconnectUser
  414. BOOL
  415. FTP_SERVER_INSTANCE::GetStatistics(
  416. IN DWORD dwLevel,
  417. OUT PCHAR* pBuffer
  418. )
  419. /*++
  420. Description
  421. Disconnect Queries the server statistics
  422. Arguments:
  423. dwLevel - Info level. Currently only level 0 is
  424. supported.
  425. pBuffer - Will receive a pointer to the statistics
  426. structure.
  427. --*/
  428. {
  429. APIERR err = NO_ERROR;
  430. IF_DEBUG( RPC ) {
  431. DBGPRINTF(( DBG_CONTEXT,
  432. "FtpQueryStatistics2, level %lu\n", dwLevel ));
  433. }
  434. //
  435. // Return the proper statistics based on the infolevel.
  436. //
  437. switch( dwLevel ) {
  438. case 0 : {
  439. LPFTP_STATISTICS_0 pstats0;
  440. pstats0 = (LPFTP_STATISTICS_0)
  441. MIDL_user_allocate(sizeof(FTP_STATISTICS_0));
  442. if( pstats0 == NULL ) {
  443. err = ERROR_NOT_ENOUGH_MEMORY;
  444. } else {
  445. ATQ_STATISTICS atqStat;
  446. ZeroMemory( pstats0, sizeof( FTP_STATISTICS_0 ) );
  447. QueryStatsObj()->CopyToStatsBuffer( pstats0 );
  448. //
  449. // Get instance's bandwidth throttling statistics
  450. //
  451. if ( QueryBandwidthInfo() )
  452. {
  453. if ( AtqBandwidthGetInfo( QueryBandwidthInfo(),
  454. ATQ_BW_STATISTICS,
  455. (ULONG_PTR *) &atqStat ) )
  456. {
  457. pstats0->TotalBlockedRequests = atqStat.cBlockedRequests;
  458. pstats0->TotalRejectedRequests = atqStat.cRejectedRequests;
  459. pstats0->TotalAllowedRequests = atqStat.cAllowedRequests;
  460. pstats0->CurrentBlockedRequests = atqStat.cCurrentBlockedRequests;
  461. pstats0->MeasuredBandwidth = atqStat.MeasuredBandwidth;
  462. }
  463. }
  464. pstats0->TimeOfLastClear = GetCurrentTimeInSeconds() -
  465. pstats0->TimeOfLastClear;
  466. //
  467. // Copy Global statistics counter values
  468. //
  469. pstats0->ConnectionAttempts =
  470. g_pFTPStats->QueryStatsObj()->ConnectionAttempts;
  471. *pBuffer = (PCHAR)pstats0;
  472. }
  473. }
  474. break;
  475. default :
  476. err = ERROR_INVALID_LEVEL;
  477. break;
  478. }
  479. IF_DEBUG( RPC ) {
  480. DBGPRINTF(( DBG_CONTEXT,
  481. "FtpQueryStatistics2 returns Error = %lu\n",
  482. err ));
  483. }
  484. SetLastError(err);
  485. return(err == NO_ERROR);
  486. } // QueryStatistics
  487. BOOL
  488. FTP_SERVER_INSTANCE::ClearStatistics(
  489. VOID
  490. )
  491. /*++
  492. Description
  493. Clears the server statistics
  494. Arguments:
  495. None.
  496. --*/
  497. {
  498. IF_DEBUG( RPC ) {
  499. DBGPRINTF(( DBG_CONTEXT, "Entering FtpClearStatistics2\n"));
  500. }
  501. QueryStatsObj()->ClearStatistics();
  502. return TRUE;
  503. } // ClearStatistics