ftpsrvr.cxx
上传用户:hzhsqp
上传日期:2007-01-06
资源大小:1600k
文件大小:16k
源码类别:

IP电话/视频会议

开发平台:

Visual C++

  1. /*
  2.  * ftpsrvr.cxx
  3.  *
  4.  * FTP server class.
  5.  *
  6.  * Portable Windows Library
  7.  *
  8.  * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
  9.  *
  10.  * The contents of this file are subject to the Mozilla Public License
  11.  * Version 1.0 (the "License"); you may not use this file except in
  12.  * compliance with the License. You may obtain a copy of the License at
  13.  * http://www.mozilla.org/MPL/
  14.  *
  15.  * Software distributed under the License is distributed on an "AS IS"
  16.  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  17.  * the License for the specific language governing rights and limitations
  18.  * under the License.
  19.  *
  20.  * The Original Code is Portable Windows Library.
  21.  *
  22.  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
  23.  *
  24.  * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
  25.  * All Rights Reserved.
  26.  *
  27.  * Contributor(s): ______________________________________.
  28.  *
  29.  * $Log: ftpsrvr.cxx,v $
  30.  * Revision 1.8  2000/06/21 01:10:18  robertj
  31.  * AIX port, thanks Wolfgang Platzer (wolfgang.platzer@infonova.at).
  32.  *
  33.  * Revision 1.7  2000/06/21 01:01:22  robertj
  34.  * AIX port, thanks Wolfgang Platzer (wolfgang.platzer@infonova.at).
  35.  *
  36.  * Revision 1.6  1999/02/16 06:04:41  robertj
  37.  * Fixed bug in FTP server for PASV mode, may return incorrect IP address.
  38.  *
  39.  * Revision 1.5  1998/11/30 04:50:48  robertj
  40.  * New directory structure
  41.  *
  42.  * Revision 1.4  1998/10/13 14:06:21  robertj
  43.  * Complete rewrite of memory leak detection code.
  44.  *
  45.  * Revision 1.3  1998/09/23 06:22:02  robertj
  46.  * Added open source copyright license.
  47.  *
  48.  * Revision 1.2  1996/10/26 01:39:49  robertj
  49.  * Added check for security breach using 3 way FTP transfer or use of privileged PORT.
  50.  *
  51.  * Revision 1.1  1996/09/14 13:02:35  robertj
  52.  * Initial revision
  53.  *
  54.  */
  55. #include <ptlib.h>
  56. #include <ptlib/sockets.h>
  57. #include <ptclib/ftp.h>
  58. #define new PNEW
  59. #define READY_STRING  "PWLib FTP Server v1.0 ready"
  60. #define GOOBYE_STRING "Goodbye"
  61. /////////////////////////////////////////////////////////
  62. //  FTPServer
  63. PFTPServer::PFTPServer()
  64.   : readyString(PIPSocket::GetHostName() & READY_STRING)
  65. {
  66.   Construct();
  67. }
  68. PFTPServer::PFTPServer(const PString & readyStr)
  69.   : readyString(readyStr)
  70. {
  71.   Construct();
  72. }
  73. void PFTPServer::Construct()
  74. {
  75.   thirdPartyPort = FALSE;
  76.   illegalPasswordCount = 0;
  77.   state     = NotConnected;
  78.   type      = 'A';
  79.   structure = 'F';
  80.   mode      = 'S';
  81.   passiveSocket = NULL;
  82. }
  83. PFTPServer::~PFTPServer()
  84. {
  85.   delete passiveSocket;
  86. }
  87. BOOL PFTPServer::OnOpen()
  88. {
  89.   // the default data port for a client is the same port
  90.   PIPSocket * socket = GetSocket();
  91.   if (socket == NULL)
  92.     return FALSE;
  93.   state = NeedUser;
  94.   if (!WriteResponse(220, readyString))
  95.     return FALSE;
  96.   socket->GetPeerAddress(remoteHost, remotePort);
  97.   return TRUE;
  98. }
  99. PString PFTPServer::GetHelloString(const PString & user) const
  100. {
  101.   return PString("User") & user & "logged in.";
  102. }
  103. PString PFTPServer::GetGoodbyeString(const PString &) const
  104. {
  105.   return PString(GOOBYE_STRING);
  106. }
  107. PString PFTPServer::GetSystemTypeString() const
  108. {
  109.   return PProcess::GetOSClass() + " " + PProcess::GetOSName() + " " + PProcess::GetOSVersion();
  110. }
  111. BOOL PFTPServer::AuthoriseUser(const PString &, const PString &, BOOL &)
  112. {
  113.   return TRUE;
  114. }
  115. BOOL PFTPServer::ProcessCommand()
  116. {
  117.   PString args;
  118.   PINDEX code;
  119.   if (!ReadCommand(code, args))
  120.     return FALSE;
  121.   if (code == P_MAX_INDEX)
  122.     return OnUnknown(args);
  123.   //  handle commands that require login
  124.   if (state == Connected || !CheckLoginRequired(code)) 
  125.     return DispatchCommand(code, args);
  126.   
  127.   // otherwise enforce login
  128.   WriteResponse(530, "Please login with USER and PASS.");
  129.   return TRUE;
  130. }
  131. BOOL PFTPServer::DispatchCommand(PINDEX code, const PString & args)
  132. {
  133.   switch (code) {
  134.     // mandatory commands
  135.     case USER:
  136.       return OnUSER(args);
  137.     case PASS:
  138.       return OnPASS(args);
  139.     case QUIT:
  140.       return OnQUIT(args);
  141.     case PORT:
  142.       return OnPORT(args);
  143.     case STRU:
  144.       return OnSTRU(args);
  145.     case MODE:
  146.       return OnMODE(args);
  147.     case NOOP:
  148.       return OnNOOP(args);
  149.     case TYPE:
  150.       return OnTYPE(args);
  151.     case RETR:
  152.       return OnRETR(args);
  153.     case STOR:
  154.       return OnSTOR(args);
  155.     case SYST:
  156.       return OnSYST(args);
  157.     case STATcmd:
  158.       return OnSTAT(args);
  159.     case ACCT:
  160.       return OnACCT(args);
  161.     case CWD:
  162.       return OnCWD(args);
  163.     case CDUP:
  164.       return OnCDUP(args);
  165.     case PASV:
  166.       return OnPASV(args);
  167.     case APPE:
  168.       return OnAPPE(args);
  169.     case RNFR:
  170.       return OnRNFR(args);
  171.     case RNTO:
  172.       return OnRNTO(args);
  173.     case DELE:
  174.       return OnDELE(args);
  175.     case RMD:
  176.       return OnRMD(args);
  177.     case MKD:
  178.       return OnMKD(args);
  179.     case PWD:
  180.       return OnPWD(args);
  181.     case LIST:
  182.       return OnLIST(args);
  183.     case NLST:
  184.       return OnNLST(args);
  185.     // optional commands
  186.     case HELP:
  187.       return OnHELP(args);
  188.     case SITE:
  189.       return OnSITE(args);
  190.     case ABOR:
  191.       return OnABOR(args);
  192.     case SMNT:
  193.       return OnSMNT(args);
  194.     case REIN:
  195.       return OnREIN(args);
  196.     case STOU:
  197.       return OnSTOU(args);
  198.     case ALLO:
  199.       return OnALLO(args);
  200.     case REST:
  201.       return OnREST(args);
  202.     default:
  203.       PAssertAlways("Registered FTP command not handled");
  204.       return FALSE;
  205.   }
  206.   return TRUE;
  207. }
  208. BOOL PFTPServer::CheckLoginRequired(PINDEX cmd)
  209. {
  210.   static const BYTE RequiresLogin[NumCommands] = {
  211.     1, // USER
  212.     1, // PASS
  213.     0, // ACCT
  214.     0, // CWD
  215.     0, // CDUP
  216.     0, // SMNT
  217.     1, // QUIT
  218.     0, // REIN
  219.     1, // PORT
  220.     0, // PASV
  221.     1, // TYPE
  222.     1, // STRU
  223.     1, // MODE
  224.     0, // RETR
  225.     0, // STOR
  226.     0, // STOU
  227.     0, // APPE
  228.     0, // ALLO
  229.     0, // REST
  230.     0, // RNFR
  231.     0, // RNTO
  232.     1, // ABOR
  233.     0, // DELE
  234.     0, // RMD
  235.     0, // MKD
  236.     0, // PWD
  237.     0, // LIST
  238.     0, // NLST
  239.     1, // SITE
  240.     1, // SYST
  241.     1, // STAT
  242.     1, // HELP
  243.     1, // NOOP
  244.   };
  245.   if (cmd < NumCommands)
  246.     return RequiresLogin[cmd] == 0;
  247.   else
  248.     return TRUE;
  249. }
  250. BOOL PFTPServer::OnUnknown(const PCaselessString & command)
  251. {
  252.   WriteResponse(500, """ + command + "" command unrecognised.");
  253.   return TRUE;
  254. }
  255. void PFTPServer::OnError(PINDEX errorCode, PINDEX cmdNum, const char * msg)
  256. {
  257.   if (cmdNum < commandNames.GetSize())
  258.     WriteResponse(errorCode, "Command "" + commandNames[cmdNum] + "":" + msg);
  259.   else
  260.     WriteResponse(errorCode, msg);
  261. }
  262. void PFTPServer::OnNotImplemented(PINDEX cmdNum)
  263. {
  264.   OnError(502, cmdNum, "not implemented");
  265. }
  266. void PFTPServer::OnSyntaxError(PINDEX cmdNum)
  267. {
  268.   OnError(501, cmdNum, "syntax error in parameters or arguments.");
  269. }
  270. void PFTPServer::OnCommandSuccessful(PINDEX cmdNum)
  271. {
  272.   if (cmdNum < commandNames.GetSize())
  273.     WriteResponse(200, """ + commandNames[cmdNum] + "" command successful.");
  274. }
  275. // mandatory commands that can be performed without loggin in
  276. BOOL PFTPServer::OnUSER(const PCaselessString & args)
  277. {
  278.   userName = args;
  279.   state    = NeedPassword;
  280.   WriteResponse(331, "Password required for " + args + ".");
  281.   return TRUE;
  282. }
  283. BOOL PFTPServer::OnPASS(const PCaselessString & args)
  284. {
  285.   BOOL replied = FALSE;
  286.   if (state != NeedPassword) 
  287.     WriteResponse(503, "Login with USER first.");
  288.   else if (!AuthoriseUser(userName, args, replied)) {
  289.     if (!replied)
  290.       WriteResponse(530, "Login incorrect.");
  291.     if (illegalPasswordCount++ == MaxIllegalPasswords)
  292.       return FALSE;
  293.   } else {
  294.     if (!replied)
  295.       WriteResponse(230, GetHelloString(userName));
  296.     illegalPasswordCount = 0;
  297.     state = Connected;
  298.   }
  299.   return TRUE;
  300. }
  301. BOOL PFTPServer::OnQUIT(const PCaselessString & userName)
  302. {
  303.   WriteResponse(221, GetGoodbyeString(userName));
  304.   return FALSE;
  305. }
  306. BOOL PFTPServer::OnPORT(const PCaselessString & args)
  307. {
  308.   PStringArray tokens = args.Tokenise(",");
  309.   long values[6];
  310.   PINDEX len = PMIN(args.GetSize(), 6);
  311.   PINDEX i;
  312.   for (i = 0; i < len; i++) {
  313.     values[i] = tokens[i].AsInteger();
  314.     if (values[i] < 0 || values[i] > 255)
  315.       break;
  316.   }
  317.   if (i < 6) 
  318.     OnSyntaxError(PORT);
  319.   else {
  320.     PIPSocket * socket = GetSocket();
  321.     if (socket == NULL)
  322.       OnError(590, PORT, "not available on non-TCP transport.");
  323.     else {
  324.       remoteHost = PIPSocket::Address((BYTE)values[0],
  325.                               (BYTE)values[1], (BYTE)values[2], (BYTE)values[3]);
  326.       remotePort = (WORD)(values[4]*256 + values[5]);
  327.       if (remotePort < 1024 && remotePort != socket->GetPort()-1)
  328.         OnError(590, PORT, "cannot access privileged port number.");
  329.       else {
  330.         PIPSocket::Address controlHost;
  331.         GetSocket()->GetPeerAddress(controlHost);
  332.         if (thirdPartyPort || remoteHost == controlHost)
  333.           OnCommandSuccessful(PORT);
  334.         else
  335.           OnError(591, PORT, "three way transfer not allowed.");
  336.       }
  337.     }
  338.   }
  339.   return TRUE;
  340. }
  341. BOOL PFTPServer::OnPASV(const PCaselessString &)
  342. {
  343.   if (passiveSocket != NULL)
  344.     delete passiveSocket;
  345.   passiveSocket = new PTCPSocket;
  346.   passiveSocket->Listen();
  347.   WORD portNo = passiveSocket->GetPort();
  348.   PIPSocket::Address ourAddr;
  349.   PIPSocket * socket = GetSocket();
  350.   if (socket != NULL)
  351.     socket->GetLocalAddress(ourAddr);
  352.   PString str(PString::Printf,
  353.               "Entering Passive Mode (%i,%i,%i,%i,%i,%i)",
  354.               ourAddr.Byte1(),
  355.               ourAddr.Byte2(),
  356.               ourAddr.Byte3(),
  357.               ourAddr.Byte4(),
  358.               portNo/256, portNo%256);
  359.   return WriteResponse(227, str);
  360. }
  361. BOOL PFTPServer::OnTYPE(const PCaselessString & args)
  362. {
  363.   if (args.IsEmpty())
  364.     OnSyntaxError(TYPE);
  365.   else {
  366.     switch (toupper(args[0])) {
  367.       case 'A':
  368.         type = 'A';
  369.         break;
  370.       case 'I':
  371.         type = 'I';
  372.         break;
  373.       case 'E':
  374.       case 'L':
  375.         WriteResponse(504, PString("TYPE not implemented for parameter ") + args);
  376.         return TRUE;
  377.       default:
  378.         OnSyntaxError(TYPE);
  379.         return TRUE;
  380.     }
  381.   }
  382.   OnCommandSuccessful(TYPE);
  383.   return TRUE;
  384. }
  385. BOOL PFTPServer::OnMODE(const PCaselessString & args)
  386. {
  387.   if (args.IsEmpty())
  388.     OnSyntaxError(MODE);
  389.   else {
  390.     switch (toupper(args[0])) {
  391.       case 'S':
  392.         structure = 'S';
  393.         break;
  394.       case 'B':
  395.       case 'C':
  396.         WriteResponse(504, PString("MODE not implemented for parameter ") + args);
  397.         return TRUE;
  398.       default:
  399.         OnSyntaxError(MODE);
  400.         return TRUE;
  401.     }
  402.   }
  403.   OnCommandSuccessful(MODE);
  404.   return TRUE;
  405. }
  406. BOOL PFTPServer::OnSTRU(const PCaselessString & args)
  407. {
  408.   if (args.IsEmpty())
  409.     OnSyntaxError(STRU);
  410.   else {
  411.     switch (toupper(args[0])) {
  412.       case 'F':
  413.         structure = 'F';
  414.         break;
  415.       case 'R':
  416.       case 'P':
  417.         WriteResponse(504, PString("STRU not implemented for parameter ") + args);
  418.         return TRUE;
  419.       default:
  420.         OnSyntaxError(STRU);
  421.         return TRUE;
  422.     }
  423.   }
  424.   OnCommandSuccessful(STRU);
  425.   return TRUE;
  426. }
  427. BOOL PFTPServer::OnNOOP(const PCaselessString &)
  428. {
  429.   OnCommandSuccessful(NOOP);
  430.   return TRUE;
  431. }
  432. // mandatory commands that cannot be performed without logging in
  433. BOOL PFTPServer::OnRETR(const PCaselessString &)
  434. {
  435.   OnNotImplemented(RETR);
  436.   return TRUE;
  437. }
  438. BOOL PFTPServer::OnSTOR(const PCaselessString &)
  439. {
  440.   OnNotImplemented(STOR);
  441.   return TRUE;
  442. }
  443. BOOL PFTPServer::OnACCT(const PCaselessString &)
  444. {
  445.   WriteResponse(532, "Need account for storing files");
  446.   return TRUE;
  447. }
  448. BOOL PFTPServer::OnCWD(const PCaselessString &)
  449. {
  450.   OnNotImplemented(CWD);
  451.   return TRUE;
  452. }
  453. BOOL PFTPServer::OnCDUP(const PCaselessString &)
  454. {
  455.   OnNotImplemented(CDUP);
  456.   return TRUE;
  457. }
  458. BOOL PFTPServer::OnSMNT(const PCaselessString &)
  459. {
  460.   OnNotImplemented(SMNT);
  461.   return TRUE;
  462. }
  463. BOOL PFTPServer::OnREIN(const PCaselessString &)
  464. {
  465.   OnNotImplemented(REIN);
  466.   return TRUE;
  467. }
  468. BOOL PFTPServer::OnSTOU(const PCaselessString &)
  469. {
  470.   OnNotImplemented(STOU);
  471.   return TRUE;
  472. }
  473. BOOL PFTPServer::OnAPPE(const PCaselessString &)
  474. {
  475.   OnNotImplemented(APPE);
  476.   return TRUE;
  477. }
  478. BOOL PFTPServer::OnALLO(const PCaselessString &)
  479. {
  480.   OnNotImplemented(ALLO);
  481.   return TRUE;
  482. }
  483. BOOL PFTPServer::OnREST(const PCaselessString &)
  484. {
  485.   OnNotImplemented(REST);
  486.   return TRUE;
  487. }
  488. BOOL PFTPServer::OnRNFR(const PCaselessString &)
  489. {
  490.   OnNotImplemented(RNFR);
  491.   return TRUE;
  492. }
  493. BOOL PFTPServer::OnRNTO(const PCaselessString &)
  494. {
  495.   OnNotImplemented(RNTO);
  496.   return TRUE;
  497. }
  498. BOOL PFTPServer::OnABOR(const PCaselessString &)
  499. {
  500.   OnNotImplemented(ABOR);
  501.   return TRUE;
  502. }
  503. BOOL PFTPServer::OnDELE(const PCaselessString &)
  504. {
  505.   OnNotImplemented(DELE);
  506.   return TRUE;
  507. }
  508. BOOL PFTPServer::OnRMD(const PCaselessString &)
  509. {
  510.   OnNotImplemented(RMD);
  511.   return TRUE;
  512. }
  513. BOOL PFTPServer::OnMKD(const PCaselessString &)
  514. {
  515.   OnNotImplemented(MKD);
  516.   return TRUE;
  517. }
  518. BOOL PFTPServer::OnPWD(const PCaselessString &)
  519. {
  520.   OnNotImplemented(PWD);
  521.   return TRUE;
  522. }
  523. BOOL PFTPServer::OnLIST(const PCaselessString &)
  524. {
  525.   OnNotImplemented(LIST);
  526.   return TRUE;
  527. }
  528. BOOL PFTPServer::OnNLST(const PCaselessString &)
  529. {
  530.   OnNotImplemented(NLST);
  531.   return TRUE;
  532. }
  533. BOOL PFTPServer::OnSITE(const PCaselessString &)
  534. {
  535.   OnNotImplemented(SITE);
  536.   return TRUE;
  537. }
  538. BOOL PFTPServer::OnSYST(const PCaselessString &)
  539. {
  540.   WriteResponse(215, GetSystemTypeString());
  541.   return TRUE;
  542. }
  543. BOOL PFTPServer::OnSTAT(const PCaselessString &)
  544. {
  545.   OnNotImplemented(STATcmd);
  546.   return TRUE;
  547. }
  548. BOOL PFTPServer::OnHELP(const PCaselessString &)
  549. {
  550.   OnNotImplemented(HELP);
  551.   return TRUE;
  552. }
  553. void PFTPServer::SendToClient(const PFilePath & filename)
  554. {
  555.   if (!PFile::Exists(filename)) 
  556.     WriteResponse(450, filename + ": file not found");
  557.   else {
  558.     PTCPSocket * dataSocket;
  559.     if (passiveSocket != NULL) {
  560.       dataSocket = new PTCPSocket(*passiveSocket);
  561.       delete passiveSocket;
  562.       passiveSocket = NULL;
  563.     } else
  564.       dataSocket = new PTCPSocket(remoteHost, remotePort);
  565.     if (!dataSocket->IsOpen())
  566.       WriteResponse(425, "Cannot open data connection");
  567.     else {
  568.       if (type == 'A') {
  569.         PTextFile file(filename, PFile::ReadOnly);
  570.         if (!file.IsOpen())
  571.           WriteResponse(450, filename + ": cannot open file");
  572.         else {
  573.           PString fileSize(PString::Unsigned, file.GetLength());
  574.           WriteResponse(150, PString("Opening ASCII data connection for " + filename.GetFileName() + "(" + fileSize + " bytes)"));
  575.           PString line;
  576.           BOOL ok = TRUE;
  577.           while (ok && file.ReadLine(line)) {
  578.             if (!dataSocket->Write((const char *)line, line.GetLength())) {
  579.               WriteResponse(426, "Connection closed - transfer aborted");
  580.               ok = FALSE;
  581.             }
  582.           }
  583.           file.Close();
  584.         }
  585.       } else {
  586.         PFile file(filename, PFile::ReadOnly);
  587.         if (!file.IsOpen())
  588.           WriteResponse(450, filename + ": cannot open file");
  589.         else {
  590.           PString fileSize(PString::Unsigned, file.GetLength());
  591.           WriteResponse(150, PString("Opening BINARY data connection for " + filename.GetFileName() + "(" + fileSize + " bytes)"));
  592.           BYTE buffer[2048];
  593.           BOOL ok = TRUE;
  594.           while (ok && file.Read(buffer, 2048)) {
  595.             if (!dataSocket->Write(buffer, file.GetLastReadCount())) {
  596.               WriteResponse(426, "Connection closed - transfer aborted");
  597.               ok = FALSE;
  598.             }
  599.           }
  600.           file.Close();
  601.         }
  602.       }
  603.       delete dataSocket;
  604.       WriteResponse(226, "Transfer complete");
  605.     }
  606.   }
  607. }
  608. // End of File ///////////////////////////////////////////////////////////////