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.

1620 lines
38 KiB

  1. //
  2. // Copyright (C) 2001 Microsoft Corp
  3. //
  4. // FtpControl.cpp : Implementation
  5. //
  6. // JPDup
  7. // Sanjiv
  8. //
  9. #include "precomp.h"
  10. #include "MyAlg.h"
  11. //
  12. // Default constructor
  13. //
  14. CFtpControlConnection::CFtpControlConnection()
  15. {
  16. MYTRACE_ENTER_NOSHOWEXIT("CFtpControlConnection::CFtpControlConnection()");
  17. m_ClientConnectedSocket = INVALID_SOCKET;
  18. m_AlgConnectedSocket = INVALID_SOCKET;
  19. m_ControlState.m_nAddressNew = 0;
  20. m_ControlState.m_nPortNew = 0;
  21. m_nSourcePortReplacement = 0;
  22. m_RefCount = 0;
  23. m_pPendingProxy = NULL;
  24. }
  25. //
  26. // Destructor
  27. //
  28. CFtpControlConnection::~CFtpControlConnection()
  29. {
  30. MYTRACE_ENTER_NOSHOWEXIT("CFtpControlConnection::~CFtpControlConnection()");
  31. }
  32. //
  33. // Find a unique source port for the public client address given
  34. //
  35. USHORT
  36. PickNewSourcePort(
  37. ULONG nPublicSourceAddress,
  38. USHORT nPublicSourcePort
  39. )
  40. {
  41. MYTRACE_ENTER("CFtpControlConnection::PickNewSourcePort()");
  42. USHORT nNewSourcePort = 45000-nPublicSourcePort; // example 45000 - 3000
  43. bool bPortAvailable;
  44. do
  45. {
  46. nNewSourcePort--;
  47. bPortAvailable = g_ControlObjectList.IsSourcePortAvailable(nPublicSourceAddress, nNewSourcePort);
  48. MYTRACE("Port %d is %s", nNewSourcePort, bPortAvailable ? "Available" : "Inuse" );
  49. } while ( (false == bPortAvailable) && (nNewSourcePort > 6001) );
  50. return nNewSourcePort;
  51. }
  52. //
  53. // Initialize
  54. //
  55. HRESULT
  56. CFtpControlConnection::Init(
  57. SOCKET AcceptedSocket,
  58. ULONG nToAddr,
  59. USHORT nToPort,
  60. CONNECTION_TYPE ConnType
  61. )
  62. {
  63. MYTRACE_ENTER("CFtpControlConnection::Init");
  64. //
  65. // Figure what address to use
  66. //
  67. ULONG BestAddress;
  68. HRESULT hr = g_pIAlgServicesAlgFTP->GetBestSourceAddressForDestinationAddress(
  69. nToAddr,
  70. TRUE,
  71. &BestAddress
  72. );
  73. if ( FAILED(hr) )
  74. {
  75. MYTRACE_ERROR("Could not get best source address", hr);
  76. return hr;
  77. }
  78. ULONG Err = 0;
  79. m_ClientConnectedSocket = AcceptedSocket;
  80. m_ConnectionType = ConnType;
  81. IncReference();
  82. m_AlgConnectedSocket = INVALID_SOCKET;
  83. Err = MyHelperCreateStreamSocket(BestAddress,0,&m_AlgConnectedSocket);
  84. if ( Err == 0 )
  85. {
  86. if ( m_ConnectionType == OUTGOING )
  87. {
  88. MYTRACE("OUTGOING FTP");
  89. ULONG icsAddr;
  90. USHORT icsPort;
  91. Err = MyHelperQueryLocalEndpointSocket(m_AlgConnectedSocket,&icsAddr,&icsPort);
  92. MYTRACE("AlgConnectedSocket Local %s:%d",MYTRACE_IP(icsAddr), ntohs(icsPort) );
  93. if ( Err == 0 )
  94. {
  95. hr = g_pIAlgServicesAlgFTP->PrepareProxyConnection(
  96. eALG_TCP,
  97. icsAddr,
  98. icsPort,
  99. nToAddr,
  100. nToPort,
  101. FALSE,
  102. &m_pPendingProxy
  103. );
  104. }
  105. }
  106. else if (m_ConnectionType == INCOMING)
  107. {
  108. MYTRACE("INCOMING FTP");
  109. ULONG icsAddr,pubAddr;
  110. USHORT icsPort,pubPort;
  111. Err = MyHelperQueryLocalEndpointSocket(m_AlgConnectedSocket,&icsAddr,&icsPort);
  112. MYTRACE("AlgConnectedSocket Local %s:%d",MYTRACE_IP(icsAddr), ntohs(icsPort) );
  113. if (Err == 0)
  114. {
  115. Err = MyHelperQueryRemoteEndpointSocket(m_ClientConnectedSocket,&pubAddr,&pubPort);
  116. if ( Err == 0 )
  117. {
  118. if ( icsAddr == nToAddr )
  119. {
  120. //
  121. // Special case it the FTP server is hosted on the EDGE box
  122. // we would create a loop the incoming public client address/port
  123. // this new modified connection would look exacly like
  124. // the original one example:
  125. //
  126. // 1.1.1.2:3000 connects to 1.1.1.1:21
  127. // we accept this connection
  128. // and in return we connect to the FTP server destination 1.1.1.1:21
  129. // asking the NAT to source mofify and replace the source with 1.1.1.2:3000
  130. // that does not work
  131. // in order to go arround this we pick another source port example 45000
  132. //
  133. // Cache this info in order to pick a unique one next time
  134. m_nSourcePortReplacement = PickNewSourcePort(pubAddr, pubPort);
  135. pubPort = m_nSourcePortReplacement; // This is the new bogus port to use now
  136. }
  137. hr = g_pIAlgServicesAlgFTP->PrepareSourceModifiedProxyConnection(
  138. eALG_TCP,
  139. icsAddr,
  140. icsPort,
  141. nToAddr,
  142. nToPort,
  143. pubAddr,
  144. pubPort,
  145. &m_pPendingProxy
  146. );
  147. if ( FAILED(hr) )
  148. {
  149. MYTRACE_ERROR("PrepareSourceModifiedProxyConnection",hr);
  150. }
  151. }
  152. else
  153. {
  154. MYTRACE_ERROR("MyHelperQueryRemoteEndpointSocket",Err);
  155. }
  156. }
  157. else
  158. {
  159. MYTRACE_ERROR("LocalEndpointSocket", Err);
  160. }
  161. }
  162. }
  163. else
  164. {
  165. MYTRACE_ERROR("MyHelperCreateStreamSocket",Err);
  166. }
  167. if ( SUCCEEDED(hr) && Err == 0 )
  168. {
  169. Err = MyHelperConnectStreamSocket(
  170. NULL,
  171. m_AlgConnectedSocket,
  172. nToAddr,
  173. nToPort,
  174. NULL,
  175. MyConnectCompletion,
  176. (void *)this,
  177. NULL
  178. );
  179. if ( Err != 0 )
  180. {
  181. MYTRACE_ERROR("From MyHelperConnectStreamSocket", Err);
  182. m_pPendingProxy->Cancel();
  183. }
  184. }
  185. if ( FAILED(hr) || Err )
  186. {
  187. MYTRACE_ERROR("We can't init this Connection", hr);
  188. ULONG ref;
  189. ref = DecReference();
  190. _ASSERT(ref == 0);
  191. if ( SUCCEEDED(hr) )
  192. hr = HRESULT_FROM_WIN32(Err);
  193. }
  194. return hr;
  195. }
  196. #define MAKE_ADDRESS(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24))
  197. #define MAKE_PORT(a,b) ((a) | ((b) << 8))
  198. //
  199. //
  200. //
  201. ULONG
  202. GetNumFromString(UCHAR *String,ULONG *pNum)
  203. {
  204. ULONG retval = 0;
  205. int i = 0;
  206. while (String[i] != ',')
  207. {
  208. retval = retval*10 + (String[i]-'0');
  209. i++;
  210. }
  211. *pNum = i;
  212. return retval;
  213. }
  214. //
  215. // Needs to return in Network address order
  216. //
  217. USHORT
  218. GetUSHORTFromString(UCHAR *String,ULONG *pNum)
  219. {
  220. MYTRACE_ENTER("GetUSHORTFromString");
  221. ULONG Num;
  222. UCHAR Numbers[2];
  223. *pNum = 0;
  224. Numbers[0] = (UCHAR)GetNumFromString(String,&Num);
  225. *pNum += Num+1;
  226. Numbers[1] = (UCHAR)GetNumFromString(String+*pNum,&Num);
  227. *pNum += Num;
  228. USHORT retval = (USHORT)MAKE_PORT((USHORT)Numbers[0], (USHORT)Numbers[1]);
  229. return retval;
  230. }
  231. //
  232. // return the String IP Address as 192,168,0,0, in a ULONG in HOST format
  233. //
  234. ULONG
  235. GetULONGFromString(
  236. UCHAR* String,
  237. ULONG* pNum
  238. )
  239. {
  240. UCHAR Numbers[4];
  241. ULONG retval = 0;
  242. ULONG Num;
  243. *pNum = 0;
  244. Numbers[0] = (UCHAR)GetNumFromString(String,&Num);
  245. *pNum += Num+1;
  246. Numbers[1] = (UCHAR)GetNumFromString(String+*pNum,&Num);
  247. *pNum += Num+1;
  248. Numbers[2] = (UCHAR)GetNumFromString(String+*pNum,&Num);
  249. *pNum += Num+1;
  250. Numbers[3] = (UCHAR)GetNumFromString(String+*pNum,&Num);
  251. *pNum += Num;
  252. retval = MAKE_ADDRESS(Numbers[0], Numbers[1], Numbers[2], Numbers[3]);
  253. return retval;
  254. }
  255. //
  256. //
  257. //
  258. void
  259. CFtpControlConnection::ConnectCompletionRoutine(
  260. ULONG ErrCode,
  261. ULONG BytesTransferred
  262. )
  263. {
  264. MYTRACE_ENTER("CFtpControlConnection::ConnectCompletionRoutine");
  265. ULONG Err;
  266. if ( ErrCode )
  267. {
  268. MYTRACE_ERROR("ConnectCompletionRoutine", ErrCode);
  269. if ( m_pPendingProxy )
  270. {
  271. MYTRACE("PendingProxy still active CANCEL");
  272. m_pPendingProxy->Cancel();
  273. }
  274. ULONG ref;
  275. ref = DecReference();
  276. _ASSERT(ref == 0);
  277. return;
  278. }
  279. Err = MyHelperReadStreamSocket(
  280. NULL,
  281. m_ClientConnectedSocket,
  282. NULL,
  283. FTP_MAX_MSG_SIZE,
  284. 0,
  285. MyReadCompletion,
  286. (void *)this,
  287. (void *)CLIENT_READ
  288. );
  289. if ( Err )
  290. {
  291. MYTRACE_ERROR("From MyHelperReadStreamSocket CLIENT_READ",Err);
  292. ULONG ref;
  293. ref = DecReference();
  294. _ASSERT(ref == 0);
  295. return;
  296. }
  297. IncReference();
  298. Err = MyHelperReadStreamSocket(
  299. NULL,
  300. m_AlgConnectedSocket,
  301. NULL,
  302. FTP_MAX_MSG_SIZE,0,
  303. MyReadCompletion,
  304. (void *)this,
  305. (void *)SERVER_READ
  306. );
  307. if ( Err )
  308. {
  309. MYTRACE("MyHelperReadStreamSocket SERVER_READ",Err);
  310. ULONG ref;
  311. ref = DecReference();
  312. _ASSERT(ref == 1);
  313. if (ref)
  314. Shutdown();
  315. return;
  316. }
  317. return;
  318. }
  319. //
  320. //
  321. //
  322. ULONG
  323. CFtpControlConnection::IncReference(void)
  324. {
  325. MYTRACE_ENTER("CFtpControlConnection::IncReference()");
  326. ULONG nRef = InterlockedIncrement((LPLONG)&m_RefCount);
  327. MYTRACE("REFCOUNT for 0x%X is now %d", this, nRef);
  328. return nRef;
  329. }
  330. //
  331. //
  332. //
  333. ULONG
  334. CFtpControlConnection::DecReference(void)
  335. {
  336. MYTRACE_ENTER("CFtpControlConnection::DecReference()");
  337. ULONG tmp = InterlockedDecrement((LPLONG)&m_RefCount);
  338. MYTRACE("REFCOUNT for 0x%X is now %d", this, tmp);
  339. if ( tmp > 0 )
  340. return tmp;
  341. MYTRACE("HIT ZERO refcount cleanup the CFtpControlConnection");
  342. if ( m_AlgConnectedSocket == INVALID_SOCKET )
  343. {
  344. MYTRACE("SOCKET SERVER ALREADY CLOSED!");
  345. }
  346. else
  347. {
  348. MYTRACE("CLOSING SOCKET ALGCONNECTED!");
  349. shutdown(m_AlgConnectedSocket, SD_BOTH);
  350. closesocket(m_AlgConnectedSocket);
  351. m_AlgConnectedSocket = INVALID_SOCKET;
  352. }
  353. if ( m_ClientConnectedSocket == INVALID_SOCKET )
  354. {
  355. MYTRACE("SOCKET CLIENT ALREADY CLOSED!");
  356. }
  357. else
  358. {
  359. MYTRACE("CLOSING SOCKET CLIENT CONNECTED!");
  360. shutdown(m_ClientConnectedSocket, SD_BOTH);
  361. closesocket(m_ClientConnectedSocket);
  362. m_ClientConnectedSocket = INVALID_SOCKET;
  363. }
  364. if ( m_pPendingProxy )
  365. {
  366. //
  367. // At this point NAT already cancel this redirect, so no need to call cancel
  368. // m_pPendingProxy->Cancel();
  369. // this was causing a ERROR on a multi-client scenario
  370. //
  371. m_pPendingProxy->Release();
  372. m_pPendingProxy = NULL;
  373. }
  374. if ( m_ControlState.m_nPortNew )
  375. {
  376. MYTRACE("ReleaseReservedPort-A %d", ntohs(m_ControlState.m_nPortNew));
  377. g_pIAlgServicesAlgFTP->ReleaseReservedPort(m_ControlState.m_nPortNew,1);
  378. m_ControlState.m_nPortNew = 0;
  379. }
  380. //
  381. // CleanUp the collection of DataChannel
  382. //
  383. IDataChannel* pData;
  384. USHORT Port;
  385. HANDLE CreationHandle,DeletionHandle;
  386. MYTRACE("Empty CDataChannelList");
  387. while ( m_DataChannelList.Remove(&pData,&Port,&CreationHandle,&DeletionHandle) )
  388. {
  389. //
  390. // Creation and Deletion events are not used for now
  391. // NhUnRegisterEvent(CreationHandle); // Hopefully nothing bad will happen ! May have been called before
  392. // NhUnRegisterEvent(DeletionHandle); // if delete has been called it would mean that Remove has been called.
  393. //
  394. pData->Cancel();
  395. pData->Release();
  396. MYTRACE("ReleaseReservedPort-B %d", ntohs(Port));
  397. g_pIAlgServicesAlgFTP->ReleaseReservedPort(Port,1);
  398. }
  399. if ( g_ControlObjectList.Remove(this) )
  400. {
  401. // happens when this was called from within ChannelDeletion or some DecReferece after that.
  402. }
  403. else
  404. {
  405. // would happen if this was called from shutdown. not otherwise.
  406. }
  407. delete this;
  408. return 0;
  409. }
  410. //
  411. // The last one to call DecReference would take it off control list.
  412. // The first one to call DecReference because of fatal error would call Shutdown to start off
  413. // the DecReference for all the connected stuff.
  414. //
  415. void
  416. CFtpControlConnection::Shutdown()
  417. {
  418. MYTRACE_ENTER("CFtpControlConnection::Shutdown()");
  419. if ( m_AlgConnectedSocket != INVALID_SOCKET )
  420. {
  421. MYTRACE("CLOSING SOCKET ALG CONNECTED! %d", m_AlgConnectedSocket);
  422. shutdown(m_AlgConnectedSocket, SD_BOTH);
  423. closesocket(m_AlgConnectedSocket);
  424. m_AlgConnectedSocket = INVALID_SOCKET;
  425. }
  426. if ( m_ClientConnectedSocket != INVALID_SOCKET )
  427. {
  428. MYTRACE("CLOSING SOCKET CLIENT CONNECTED! %d", m_ClientConnectedSocket);
  429. shutdown(m_ClientConnectedSocket, SD_BOTH);
  430. closesocket(m_ClientConnectedSocket);
  431. m_ClientConnectedSocket = INVALID_SOCKET;
  432. }
  433. return;
  434. }
  435. //
  436. //
  437. //
  438. void
  439. CFtpControlConnection::ReadCompletionRoutine(
  440. ULONG ErrCode,
  441. ULONG BytesTransferred,
  442. PNH_BUFFER Bufferp
  443. )
  444. {
  445. MYTRACE_ENTER( "CFtpControlConnection::ReadCompletionRoutine" );
  446. if ( ErrCode || BytesTransferred == 0 )
  447. {
  448. if ( ErrCode )
  449. {
  450. MYTRACE("Shutdown because of read ERROR 0x%x", ErrCode);
  451. }
  452. else
  453. {
  454. MYTRACE("Shutdown because of read 0 bytes");
  455. }
  456. MyHelperReleaseBuffer(Bufferp);
  457. if (DecReference())
  458. Shutdown();
  459. return;
  460. }
  461. ULONG_PTR ReadType = (ULONG_PTR)Bufferp->Context2;
  462. ULONG_PTR WriteType;
  463. SOCKET ReadSocket;
  464. SOCKET WriteSocket;
  465. ULONG Err;
  466. if ( ReadType == CLIENT_READ )
  467. {
  468. WriteType = SERVER_READ;
  469. ReadSocket = m_ClientConnectedSocket;
  470. WriteSocket = m_AlgConnectedSocket;
  471. }
  472. else
  473. {
  474. WriteType = CLIENT_READ;
  475. ReadSocket = m_AlgConnectedSocket;
  476. WriteSocket = m_ClientConnectedSocket;
  477. }
  478. #if defined(DBG) || defined(_DEBUG)
  479. ULONG TraceAddr = 0;
  480. USHORT TracePort = 0;
  481. if ( ReadSocket != INVALID_SOCKET )
  482. Err = MyHelperQueryRemoteEndpointSocket(ReadSocket ,&TraceAddr,&TracePort);
  483. MYTRACE("from %s (%s:%d)",
  484. ReadType == CLIENT_READ ? "CLIENT":"SERVER",
  485. MYTRACE_IP(TraceAddr),
  486. ntohs(TracePort)
  487. );
  488. MYTRACE("EC(0x%x) Buffer size(%d)='%s'", ErrCode, BytesTransferred, MYTRACE_BUFFER2STR((char*)Bufferp->Buffer, BytesTransferred));
  489. #endif
  490. if ( (ReadType == CLIENT_READ && m_ConnectionType == OUTGOING) || (ReadType == SERVER_READ && m_ConnectionType == INCOMING) )
  491. {
  492. // the number of bytes transferred can change.
  493. // because the ProcessFtpMessage may have to
  494. // buffer the Address,Port string from PORT or PASV response command.
  495. ProcessFtpMessage(Bufferp->Buffer,&BytesTransferred);
  496. }
  497. if ( BytesTransferred != 0 && WriteSocket != INVALID_SOCKET )
  498. {
  499. IncReference();
  500. MYTRACE(
  501. "Write to %s size(%d)='%s'",
  502. WriteType == SERVER_READ ? "SERVER" : "CLIENT",
  503. BytesTransferred,
  504. MYTRACE_BUFFER2STR((char*)Bufferp->Buffer, BytesTransferred)
  505. );
  506. Err = MyHelperWriteStreamSocket(
  507. NULL,
  508. WriteSocket,
  509. Bufferp,BytesTransferred,
  510. 0,
  511. MyWriteCompletion,
  512. (void *)this,(PVOID)WriteType
  513. );
  514. if (Err)
  515. {
  516. MYTRACE_ERROR("from MyHelperWriteStreamSocket", Err);
  517. DecReference();
  518. if (DecReference())
  519. Shutdown(); // I am not going to call the Read again so one more DecReference is needed.
  520. MyHelperReleaseBuffer(Bufferp);
  521. return;
  522. }
  523. }
  524. if ( INVALID_SOCKET == ReadSocket )
  525. {
  526. if (DecReference())
  527. Shutdown();
  528. }
  529. else
  530. {
  531. Err = MyHelperReadStreamSocket(
  532. NULL,
  533. ReadSocket,
  534. NULL,
  535. FTP_MAX_MSG_SIZE,
  536. 0,
  537. MyReadCompletion,
  538. (void *)this,
  539. (void *)ReadType
  540. );
  541. if (Err)
  542. {
  543. MYTRACE_ERROR("from MyHelperReadStreamSocket",Err);
  544. if (DecReference())
  545. Shutdown();
  546. }
  547. }
  548. return;
  549. }
  550. //
  551. //
  552. //
  553. void
  554. CFtpControlConnection::WriteCompletionRoutine(
  555. ULONG ErrCode,
  556. ULONG BytesTransferred,
  557. PNH_BUFFER Bufferp
  558. )
  559. {
  560. MYTRACE_ENTER("CFtpControlConnection::WriteCompletionRoutine");
  561. if (BytesTransferred == 0)
  562. ErrCode = ERROR_IO_CANCELLED;
  563. if (ErrCode)
  564. {
  565. if (MyHelperIsFatalSocketError(ErrCode) || ErrCode == ERROR_IO_CANCELLED)
  566. {
  567. MYTRACE_ERROR("FATAL ERROR", ErrCode);
  568. MyHelperReleaseBuffer(Bufferp);
  569. if (DecReference())
  570. Shutdown();
  571. }
  572. else
  573. {
  574. MYTRACE_ERROR("ANOTHER MyHelperWriteStreamSocket", ErrCode);
  575. ULONG_PTR Type = (ULONG_PTR)Bufferp->Context2;
  576. ULONG Err = MyHelperWriteStreamSocket(
  577. NULL,
  578. Bufferp->Socket,
  579. Bufferp,Bufferp->BytesToTransfer,
  580. 0,
  581. MyWriteCompletion,
  582. (void *)this,
  583. (PVOID)Type
  584. );
  585. if (Err)
  586. {
  587. MYTRACE_ERROR("From MyHelperWriteStreamSocket", Err);
  588. MyHelperReleaseBuffer(Bufferp);
  589. if (DecReference())
  590. Shutdown();
  591. }
  592. }
  593. }
  594. else
  595. {
  596. ULONG_PTR Type = (ULONG_PTR)Bufferp->Context2;
  597. MYTRACE(Type == CLIENT_READ ? "to CLIENT" : "to SERVER" );
  598. MYTRACE("EC(0x%x) Buffer size(%d)='%s'", ErrCode, BytesTransferred, MYTRACE_BUFFER2STR((char*)Bufferp->Buffer, BytesTransferred));
  599. MYTRACE("Write Succeeded now cleanup");
  600. MyHelperReleaseBuffer(Bufferp);
  601. DecReference();
  602. }
  603. return;
  604. }
  605. bool
  606. FtpExtractOctet(
  607. UCHAR** Buffer,
  608. UCHAR* BufferEnd,
  609. UCHAR* Octet
  610. )
  611. /*++
  612. Routine Description:
  613. This routine is called to extract an octet from a string.
  614. Arguments:
  615. Buffer - points to a pointer to a string where conversion starts; on
  616. return it points to the pointer to the string where conversion ends
  617. BufferEnd - points to the end of the string
  618. Octet - points to a caller-suplied storage to store converted octet
  619. Return Value:
  620. BOOLEAN - TRUE if successfuly converted, FALSE otherwise.
  621. --*/
  622. {
  623. bool bSuccess;
  624. ULONG nDigitFound = 0;
  625. ULONG Value = 0;
  626. while (
  627. *Buffer <= BufferEnd
  628. && nDigitFound < 3
  629. && **Buffer >= '0'
  630. && **Buffer <= '9'
  631. )
  632. {
  633. Value *= 10;
  634. Value += **Buffer - '0';
  635. (*Buffer)++;
  636. nDigitFound++;
  637. }
  638. bSuccess = nDigitFound > 0 && Value < 256;
  639. if ( bSuccess )
  640. {
  641. *Octet = (UCHAR)Value;
  642. }
  643. return bSuccess;
  644. }
  645. //
  646. // Extract host and port numbers.
  647. // example 192,168,0,2,100,200
  648. //
  649. bool
  650. ExtractAddressAndPortCommandValue(
  651. UCHAR* pCommandBuffer,
  652. UCHAR* pEndOfBuffer,
  653. UCHAR* Numbers,
  654. ULONG* nTotalLen
  655. )
  656. {
  657. UCHAR* pStartingPosition = pCommandBuffer;
  658. bool bSuccess = FtpExtractOctet(
  659. &pCommandBuffer,
  660. pEndOfBuffer,
  661. &Numbers[0]
  662. );
  663. int i = 1;
  664. while ( i < 6 && bSuccess && *pCommandBuffer == ',' )
  665. {
  666. pCommandBuffer++;
  667. bSuccess = FtpExtractOctet(
  668. &pCommandBuffer,
  669. pEndOfBuffer,
  670. &Numbers[i]
  671. );
  672. i++;
  673. }
  674. if ( bSuccess && i == 6 )
  675. {
  676. *nTotalLen = (ULONG)(pCommandBuffer - pStartingPosition);
  677. return true;
  678. }
  679. return false;
  680. }
  681. #define TOUPPER(c) ((c) > 'z' ? (c) : ((c) < 'a' ? (c) : (c) ^ 0x20))
  682. //
  683. // Look for the "PORT" or "227" command and remap the private address associated with these command
  684. // to a public address
  685. //
  686. void
  687. CFtpControlConnection::ProcessFtpMessage(
  688. UCHAR* Buffer,
  689. ULONG* pBytes
  690. )
  691. {
  692. MYTRACE_ENTER("CFtpControlConnection::ProcessFtpMessage");
  693. MYTRACE("Buffer size(%d)='%s'", *pBytes, MYTRACE_BUFFER2STR((char*)Buffer, *pBytes));
  694. ULONG Bytes = *pBytes;
  695. UCHAR* pCommandBuffer = reinterpret_cast<UCHAR*>(Buffer);
  696. UCHAR* EndOfBufferp = reinterpret_cast<UCHAR*>(Buffer + *pBytes);
  697. HRESULT hr;
  698. char *String;
  699. UCHAR* pBeginAddressAndPortOld=NULL;
  700. UCHAR* pEndAddressAndPortOld=NULL;
  701. ULONG nOldAddressLen=0;
  702. CONST CHAR *pCommandToFind;
  703. // for now lets keep the OUTGOING and INCOMING seperate.
  704. // can be put together since most of the code is the same.
  705. // differences in the first few bytes to scan for.
  706. if ( m_ConnectionType == OUTGOING )
  707. {
  708. MYTRACE("OUTGOING - Look for 'PORT ' command");
  709. pCommandToFind = (PCHAR)"PORT ";
  710. }
  711. else
  712. {
  713. MYTRACE("INCOMING - Look for '227 ' command ");
  714. pCommandToFind = (PCHAR)"227 ";
  715. }
  716. while ( *pCommandToFind != '\0' && *pCommandToFind == TOUPPER(*pCommandBuffer))
  717. {
  718. pCommandToFind++;
  719. pCommandBuffer++;
  720. }
  721. if ( *pCommandToFind == '\0' )
  722. {
  723. MYTRACE("COMMAND found");
  724. //
  725. // Skip non digit char
  726. //
  727. if ( m_ConnectionType == OUTGOING )
  728. {
  729. //
  730. // Skip white space. example -> PORT 10,12,13,14,1,2
  731. //
  732. while (*pCommandBuffer == ' ')
  733. pCommandBuffer++;
  734. }
  735. else
  736. {
  737. //
  738. // Skip non digit char example 227 Entering passive mode (10,12,13,14,1,2)
  739. //
  740. while ( pCommandBuffer < EndOfBufferp && !isdigit(*pCommandBuffer) )
  741. pCommandBuffer++;
  742. }
  743. //
  744. // so next stuff should be the addr,port combination.
  745. //
  746. UCHAR Numbers[6];
  747. if ( ExtractAddressAndPortCommandValue(pCommandBuffer, EndOfBufferp, Numbers, &nOldAddressLen) )
  748. {
  749. pBeginAddressAndPortOld = pCommandBuffer;
  750. pEndAddressAndPortOld = pCommandBuffer + nOldAddressLen;
  751. m_ControlState.m_nAddressOld = MAKE_ADDRESS(Numbers[0], Numbers[1], Numbers[2], Numbers[3]);
  752. m_ControlState.m_nPortOld = MAKE_PORT(Numbers[4], Numbers[5]);
  753. MYTRACE("***** PRIVATE PORT is %d %d", m_ControlState.m_nPortOld, ntohs(m_ControlState.m_nPortOld));
  754. if ( ntohs(m_ControlState.m_nPortOld) <= 1025 )
  755. {
  756. //
  757. // For security reason we will disallow any redirection to ports lower then 1025
  758. // this port range is reserver for standard port Like 139/Netbios
  759. // if this port range was requested it probably is the source of hacker attacking this FTP proxy
  760. //
  761. MYTRACE("***** Port to redirect is lower then 1025 so rejected");
  762. m_ControlState.m_nAddressNew = htonl(0);
  763. m_ControlState.m_nPortNew = htons(0);
  764. m_ControlState.m_nAddressLenNew = 11;
  765. strcpy((char*)m_ControlState.m_szAddressPortNew, "0,0,0,0,0,0");
  766. // pretend that a Redirection got created
  767. // This way we send out a PORT command with the Public addapter address and a new reserver PORT
  768. // but when the public hacker comes back it wil not be redirect but simply droped
  769. }
  770. else
  771. {
  772. //
  773. // Get best public address to use and reserver a port
  774. // This will be the Address/Port expose on the public side.
  775. //
  776. hr = CreateNewAddress();
  777. if ( FAILED(hr) )
  778. {
  779. MYTRACE_ERROR("CreateNewAddress failed",hr);
  780. // We screwed up. cant make redirects now. so for now lets just act
  781. // as if nothing happened and carry on with the stuff.
  782. }
  783. }
  784. }
  785. else
  786. {
  787. MYTRACE_ERROR("NOT a valid PORT command syntax", E_INVALIDARG);
  788. }
  789. }
  790. //
  791. // Rebuild the string command with the new address port
  792. //
  793. if ( pBeginAddressAndPortOld )
  794. {
  795. if ( ntohs(m_ControlState.m_nPortOld) <= 1025 )
  796. {
  797. // No need to setup a redirection
  798. hr = S_OK;
  799. }
  800. else
  801. {
  802. hr = SetupDataRedirect();
  803. }
  804. if ( FAILED(hr) )
  805. {
  806. // we got screwed badly here. we wont set up redirect and act as if nothing happened.
  807. MYTRACE_ERROR("Could not setup a redirect", hr);
  808. }
  809. else
  810. {
  811. //
  812. // Move trailing buffer
  813. // Left if new address is smaller then old address
  814. // Right if new address is bigger then old address
  815. //
  816. // This is the right side reminder of the buffer just after the last digit of the ascii port value
  817. int nReminerSize = (int)(Bytes - (pEndAddressAndPortOld - Buffer));
  818. if ( *pBytes + nReminerSize < FTP_MAX_MSG_SIZE )
  819. {
  820. int nOffset = m_ControlState.m_nAddressLenNew - nOldAddressLen; // What is the delta size between the old and new address
  821. MoveMemory(
  822. pEndAddressAndPortOld + nOffset, // Destination
  823. pEndAddressAndPortOld, // Source
  824. nReminerSize // Size
  825. );
  826. //
  827. // Insert the new address and port
  828. //
  829. memcpy(
  830. pBeginAddressAndPortOld, // Destination
  831. m_ControlState.m_szAddressPortNew, // Source
  832. m_ControlState.m_nAddressLenNew // Size
  833. );
  834. MYTRACE("OLD Address size(%d) %s:%d", nOldAddressLen, MYTRACE_IP(m_ControlState.m_nAddressOld), ntohs(m_ControlState.m_nPortOld));
  835. MYTRACE("New Address size(%d) %s:%d", m_ControlState.m_nAddressLenNew, MYTRACE_IP(m_ControlState.m_nAddressNew), ntohs(m_ControlState.m_nPortNew));
  836. *pBytes = Bytes - nOldAddressLen + m_ControlState.m_nAddressLenNew;
  837. MYTRACE("Edited COMMAND is '%s' size(%d)", MYTRACE_BUFFER2STR((char*)Buffer, *pBytes), *pBytes);
  838. // Now we are sure to have a DataChannel created and in the list of DataChanel
  839. // on the last DecRefer the ResertPort was deleted twice
  840. // now by setting m_nPortNew to zero only the DataChannel code will release the port
  841. //
  842. m_ControlState.m_nPortNew = 0;
  843. }
  844. else
  845. {
  846. MYTRACE_ERROR("Could not alter the command the new address size does not fit in the the current buffer ", E_ABORT);
  847. }
  848. }
  849. }
  850. return;
  851. }
  852. //
  853. //
  854. //
  855. int
  856. CreateStringFromNumber(UCHAR *String,ULONG Num)
  857. {
  858. int retval = 0;
  859. UCHAR ch1,ch2,ch3;
  860. ch3 = (UCHAR)(Num%10) + '0';
  861. Num = Num/10;
  862. ch2 = (UCHAR)(Num%10) + '0';
  863. Num = Num/10;
  864. ch1 = (UCHAR)(Num%10) + '0';
  865. _ASSERT(Num == 0);
  866. if (ch1 != '0') {
  867. String[retval++] = ch1;
  868. String[retval++] = ch2;
  869. String[retval++] = ch3;
  870. }
  871. else if (ch2 != '0') {
  872. String[retval++] = ch2;
  873. String[retval++] = ch3;
  874. }
  875. else {
  876. String[retval++] = ch3;
  877. }
  878. return retval;
  879. }
  880. //
  881. //
  882. //
  883. int
  884. CreateULONGString(UCHAR *String,ULONG Num)
  885. {
  886. int retval = 0;
  887. retval += CreateStringFromNumber(String,Num&0xff);
  888. String[retval++] = ',';
  889. retval += CreateStringFromNumber(String+retval,(Num>>8)&0xff);
  890. String[retval++] = ',';
  891. retval += CreateStringFromNumber(String+retval,(Num>>16)&0xff);
  892. String[retval++] = ',';
  893. retval += CreateStringFromNumber(String+retval,(Num>>24)&0xff);
  894. return retval;
  895. }
  896. //
  897. //
  898. //
  899. int
  900. CreateUSHORTString(UCHAR *String,USHORT Num)
  901. {
  902. int retval = 0;
  903. retval += CreateStringFromNumber(String,Num&0xff);
  904. String[retval++] = ',';
  905. retval += CreateStringFromNumber(String+retval,(Num>>8)&0xff);
  906. return retval;
  907. }
  908. //
  909. //
  910. //
  911. HRESULT
  912. CFtpControlConnection::CreateNewAddress(void)
  913. {
  914. MYTRACE_ENTER("CFtpControlConnection::CreateNewAddress");
  915. SOCKET sd;
  916. HRESULT hr = S_OK;
  917. ULONG Err = 0;
  918. sd = (m_ConnectionType == OUTGOING ? m_AlgConnectedSocket : m_ClientConnectedSocket);
  919. ULONG OtherAddr,PublicAddr;
  920. USHORT OtherPort,PublicPort;
  921. Err = MyHelperQueryRemoteEndpointSocket(sd,&OtherAddr,&OtherPort);
  922. if (Err == 0)
  923. {
  924. hr = g_pIAlgServicesAlgFTP->GetBestSourceAddressForDestinationAddress(OtherAddr,FALSE,&PublicAddr);
  925. if ( SUCCEEDED(hr) )
  926. {
  927. hr = g_pIAlgServicesAlgFTP->ReservePort(1,&PublicPort);
  928. }
  929. else
  930. {
  931. MYTRACE_ERROR("Could not GetBestSourceAddressForDestinationAddress", hr);
  932. PublicAddr = 0; // Try with this
  933. }
  934. MYTRACE("ICS Reserved Address %s:%d", MYTRACE_IP(PublicAddr), ntohs(PublicPort));
  935. m_ControlState.m_nAddressNew = PublicAddr;
  936. m_ControlState.m_nPortNew = PublicPort;
  937. ULONG StrLen = CreateULONGString(m_ControlState.m_szAddressPortNew,PublicAddr);
  938. m_ControlState.m_szAddressPortNew[StrLen++] = ',';
  939. StrLen += CreateUSHORTString(m_ControlState.m_szAddressPortNew+StrLen,PublicPort);
  940. m_ControlState.m_nAddressLenNew = StrLen;
  941. MYTRACE("NEW AddressPort String %s Len(%d)", MYTRACE_BUFFER2STR((char*)m_ControlState.m_szAddressPortNew, StrLen), StrLen);
  942. }
  943. return hr;
  944. }
  945. //
  946. //
  947. //
  948. HRESULT
  949. CFtpControlConnection::SetupDataRedirect(void)
  950. {
  951. MYTRACE_ENTER("CFtpControlConnection::SetupDataRedirect");
  952. ULONG pubAddr,prvAddr,icsAddr;
  953. USHORT pubPort,prvPort,icsPort;
  954. ULONG Err = 0;
  955. switch ( m_ConnectionType )
  956. {
  957. case OUTGOING:
  958. MYTRACE("OUTGOING");
  959. Err = MyHelperQueryRemoteEndpointSocket(m_AlgConnectedSocket,&pubAddr,&pubPort);
  960. pubPort = 0;
  961. icsAddr = m_ControlState.m_nAddressNew;
  962. icsPort = m_ControlState.m_nPortNew;
  963. prvAddr = m_ControlState.m_nAddressOld;
  964. prvPort = m_ControlState.m_nPortOld;
  965. break;
  966. case INCOMING:
  967. MYTRACE("INCOMING");
  968. Err = MyHelperQueryRemoteEndpointSocket(m_ClientConnectedSocket,&pubAddr,&pubPort);
  969. pubPort = 0;
  970. pubAddr = 0;
  971. icsAddr = m_ControlState.m_nAddressNew;
  972. icsPort = m_ControlState.m_nPortNew;
  973. prvAddr = m_ControlState.m_nAddressOld;
  974. prvPort = m_ControlState.m_nPortOld;
  975. break;
  976. default:
  977. // m_ConnectionType is corrupt
  978. _ASSERT( FALSE );
  979. break;
  980. }
  981. if ( Err != 0 )
  982. {
  983. MYTRACE_ERROR("MyHelperQueryRemoteEndpointSocket", Err);
  984. return E_FAIL;
  985. }
  986. HRESULT hr = S_OK;
  987. IDataChannel* pDataChannel = NULL;
  988. hr = g_pIAlgServicesAlgFTP->CreateDataChannel(
  989. eALG_TCP,
  990. prvAddr,
  991. prvPort,
  992. icsAddr,
  993. icsPort,
  994. pubAddr,
  995. pubPort,
  996. eALG_INBOUND, //| eALG_OUTBOUND, not needed i suppose since we
  997. // are not bothered if client tries to open connection.
  998. (ALG_NOTIFICATION)0,// (eALG_SESSION_CREATION | eALG_SESSION_DELETION),
  999. FALSE,
  1000. &pDataChannel
  1001. );
  1002. if ( FAILED(hr) )
  1003. {
  1004. MYTRACE_ERROR("g_pIAlgServicesAlgFTP->CreateDataChannel", hr);
  1005. return hr;
  1006. }
  1007. m_DataChannelList.Insert(
  1008. pDataChannel,
  1009. icsPort,
  1010. 0,
  1011. 0
  1012. );
  1013. return S_OK;
  1014. //
  1015. // Don't use creation and deletion events for now
  1016. //
  1017. #if 0
  1018. HANDLE HandleDataChannelCreation = NULL;
  1019. HANDLE HandleDataChannelDeletion = NULL;
  1020. HANDLE MyHandleRegisteredCreation = NULL;
  1021. HANDLE MyHandleRegisteredDeletion = NULL;
  1022. //
  1023. // Get the CREATION handle
  1024. //
  1025. hr = pDataChannel->GetSessionCreationEventHandle((HANDLE_PTR *)&HandleDataChannelCreation);
  1026. if ( SUCCEEDED(hr) )
  1027. {
  1028. MYTRACE("Creation Handle is %d", HandleDataChannelCreation);
  1029. MyHandleRegisteredCreation = NhRegisterEvent(
  1030. HandleDataChannelCreation,
  1031. DataChannelCreationCallback,
  1032. (PVOID)this,
  1033. (PVOID)pDataChannel,
  1034. DATA_CREATION_TIMEO
  1035. );
  1036. if ( MyHandleRegisteredCreation )
  1037. {
  1038. //
  1039. // Get the DELETION handle
  1040. //
  1041. hr = pDataChannel->GetSessionDeletionEventHandle((HANDLE_PTR *)&HandleDataChannelDeletion);
  1042. if ( SUCCEEDED(hr) )
  1043. {
  1044. MYTRACE("Deletion Handle is %d", HandleDataChannelDeletion);
  1045. MyHandleRegisteredDeletion = NhRegisterEvent(
  1046. HandleDataChannelDeletion,
  1047. DataChannelDeletionCallback,
  1048. (PVOID)this,
  1049. (PVOID)pDataChannel,
  1050. INFINITE
  1051. );
  1052. if ( MyHandleRegisteredDeletion )
  1053. {
  1054. //
  1055. // We have a valid DataChannel
  1056. //
  1057. MYTRACE ("Inserting into DataChannelList");
  1058. m_DataChannelList.Insert(
  1059. pDataChannel,
  1060. icsPort,
  1061. MyHandleRegisteredCreation,
  1062. MyHandleRegisteredDeletion
  1063. );
  1064. return S_OK;
  1065. }
  1066. else
  1067. {
  1068. MYTRACE_ERROR("NhRegisterEven(HandleDataChannelDeletion)", 0);
  1069. }
  1070. }
  1071. else
  1072. {
  1073. MYTRACE_ERROR("GetSessionDeletionEventHandle",hr);
  1074. }
  1075. }
  1076. else
  1077. {
  1078. MYTRACE_ERROR("NhRegisterEvent(HandleDataChannelCreation)", 0);
  1079. }
  1080. }
  1081. else
  1082. {
  1083. MYTRACE_ERROR("GetSessionCreationEventHandle",hr);
  1084. }
  1085. //
  1086. // ERROR if we got here, rollback
  1087. //
  1088. pDataChannel->Cancel();
  1089. pDataChannel->Release();
  1090. if ( MyHandleRegisteredCreation )
  1091. NhUnRegisterEvent(MyHandleRegisteredCreation);
  1092. if ( MyHandleRegisteredDeletion )
  1093. NhUnRegisterEvent(MyHandleRegisteredDeletion);
  1094. return hr; // return the last error
  1095. #endif
  1096. }
  1097. //
  1098. //
  1099. //
  1100. void
  1101. CFtpControlConnection::DataChannelDeletion(
  1102. BOOLEAN TimerOrWait,
  1103. PVOID Context
  1104. )
  1105. {
  1106. MYTRACE_ENTER("CFtpControlConnection::DataChannelDeletion");
  1107. USHORT port;
  1108. IDataChannel *pDataChannel = (IDataChannel *)Context;
  1109. /*
  1110. if (m_DataChannelList.Remove(pDataChannel,&port))
  1111. {
  1112. MYTRACE("Releasing Port");
  1113. pDataChannel->Release();
  1114. g_pIAlgServicesAlgFTP->ReleaseReservedPort(port,1);
  1115. ULONG ref;
  1116. ref = DecReference();
  1117. }
  1118. */
  1119. return;
  1120. }
  1121. //
  1122. //
  1123. //
  1124. void
  1125. CFtpControlConnection::DataChannelCreation(
  1126. BOOLEAN TimerOrWait,
  1127. PVOID Context
  1128. )
  1129. {
  1130. MYTRACE_ENTER("CFtpControlConnection::DataChannelCreation");
  1131. MYTRACE("TimerOrWait: %d", TimerOrWait);
  1132. USHORT port;
  1133. if (TimerOrWait==0)
  1134. {
  1135. /*
  1136. IDataChannel *pDataChannel = (IDataChannel *)Context;
  1137. HANDLE DeletionHandle;
  1138. if ( m_DataChannelList.Remove(pDataChannel,&port,&DeletionHandle))
  1139. {
  1140. MYTRACE("Cancelling DataChannel");
  1141. pDataChannel->Cancel();
  1142. pDataChannel->Release();
  1143. MYTRACE("Releasing Port");
  1144. g_pIAlgServicesAlgFTP->ReleaseReservedPort(port,1);
  1145. NhUnRegisterEvent(DeletionHandle);
  1146. DecReference();
  1147. }
  1148. */
  1149. }
  1150. return;
  1151. }
  1152. CComAutoCriticalSection m_AutoCS_FtpIO;
  1153. //
  1154. //
  1155. //
  1156. void
  1157. DataChannelCreationCallback(
  1158. BOOLEAN TimerOrWait,
  1159. PVOID Context,
  1160. PVOID Context2
  1161. )
  1162. {
  1163. MYTRACE_ENTER("DataChannelCreationCallback");
  1164. CFtpControlConnection *pFtpControl = (CFtpControlConnection *)Context;
  1165. pFtpControl->DataChannelCreation(TimerOrWait,Context2);
  1166. }
  1167. //
  1168. //
  1169. //
  1170. void
  1171. DataChannelDeletionCallback(
  1172. BOOLEAN TimerOrWait,
  1173. PVOID Context,
  1174. PVOID Context2
  1175. )
  1176. {
  1177. MYTRACE_ENTER("DataChannelDeletionCallback");
  1178. CFtpControlConnection *pFtpControl = (CFtpControlConnection *)Context;
  1179. pFtpControl->DataChannelDeletion(TimerOrWait,Context2);
  1180. }
  1181. //
  1182. //
  1183. //
  1184. void
  1185. MyAcceptCompletion(
  1186. ULONG ErrCode,
  1187. ULONG BytesTransferred,
  1188. PNH_BUFFER Bufferp
  1189. )
  1190. {
  1191. m_AutoCS_FtpIO.Lock();
  1192. MYTRACE_ENTER("MyAcceptCompletion");
  1193. CAlgFTP* pMainObj = (CAlgFTP*)Bufferp->Context;
  1194. if ( pMainObj )
  1195. pMainObj->AcceptCompletionRoutine(ErrCode,BytesTransferred,Bufferp);
  1196. m_AutoCS_FtpIO.Unlock();
  1197. }
  1198. //
  1199. //
  1200. //
  1201. void
  1202. MyConnectCompletion(
  1203. ULONG ErrCode,
  1204. ULONG BytesTransferred,
  1205. PNH_BUFFER pContext
  1206. )
  1207. {
  1208. m_AutoCS_FtpIO.Lock();
  1209. MYTRACE_ENTER("MyConnectCompletion");
  1210. CFtpControlConnection* pControl = (CFtpControlConnection *)pContext; // Special case here see socket.cpp MyHelperpConnectOrCloseCallbackRoutine
  1211. if ( pControl )
  1212. pControl->ConnectCompletionRoutine(ErrCode,BytesTransferred);
  1213. m_AutoCS_FtpIO.Unlock();
  1214. }
  1215. //
  1216. //
  1217. //
  1218. void
  1219. MyReadCompletion(
  1220. ULONG ErrCode,
  1221. ULONG BytesTransferred,
  1222. PNH_BUFFER Bufferp
  1223. )
  1224. {
  1225. m_AutoCS_FtpIO.Lock();
  1226. MYTRACE_ENTER("");
  1227. CFtpControlConnection *pControl = (CFtpControlConnection *)Bufferp->Context;
  1228. if ( pControl )
  1229. pControl->ReadCompletionRoutine(ErrCode,BytesTransferred,Bufferp);
  1230. else
  1231. {
  1232. MYTRACE_ENTER("ERROR ERROR ERROR MyReadCompletion");
  1233. }
  1234. m_AutoCS_FtpIO.Unlock();
  1235. }
  1236. //
  1237. //
  1238. //
  1239. void
  1240. MyWriteCompletion(
  1241. ULONG ErrCode,
  1242. ULONG BytesTransferred,
  1243. PNH_BUFFER Bufferp
  1244. )
  1245. {
  1246. m_AutoCS_FtpIO.Lock();
  1247. MYTRACE_ENTER("");
  1248. CFtpControlConnection *pControl = (CFtpControlConnection *)Bufferp->Context;
  1249. if ( pControl )
  1250. pControl->WriteCompletionRoutine(ErrCode,BytesTransferred,Bufferp);
  1251. else
  1252. {
  1253. MYTRACE_ENTER("ERROR ERROR ERROR MyWriteCompletion");
  1254. }
  1255. m_AutoCS_FtpIO.Unlock();
  1256. }