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.

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