ftpsrvr.cxx
上传用户:hzhsqp
上传日期:2007-01-06
资源大小:1600k
文件大小:16k
- /*
- * ftpsrvr.cxx
- *
- * FTP server class.
- *
- * Portable Windows Library
- *
- * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.0 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * The Original Code is Portable Windows Library.
- *
- * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
- *
- * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
- * All Rights Reserved.
- *
- * Contributor(s): ______________________________________.
- *
- * $Log: ftpsrvr.cxx,v $
- * Revision 1.8 2000/06/21 01:10:18 robertj
- * AIX port, thanks Wolfgang Platzer (wolfgang.platzer@infonova.at).
- *
- * Revision 1.7 2000/06/21 01:01:22 robertj
- * AIX port, thanks Wolfgang Platzer (wolfgang.platzer@infonova.at).
- *
- * Revision 1.6 1999/02/16 06:04:41 robertj
- * Fixed bug in FTP server for PASV mode, may return incorrect IP address.
- *
- * Revision 1.5 1998/11/30 04:50:48 robertj
- * New directory structure
- *
- * Revision 1.4 1998/10/13 14:06:21 robertj
- * Complete rewrite of memory leak detection code.
- *
- * Revision 1.3 1998/09/23 06:22:02 robertj
- * Added open source copyright license.
- *
- * Revision 1.2 1996/10/26 01:39:49 robertj
- * Added check for security breach using 3 way FTP transfer or use of privileged PORT.
- *
- * Revision 1.1 1996/09/14 13:02:35 robertj
- * Initial revision
- *
- */
- #include <ptlib.h>
- #include <ptlib/sockets.h>
- #include <ptclib/ftp.h>
- #define new PNEW
- #define READY_STRING "PWLib FTP Server v1.0 ready"
- #define GOOBYE_STRING "Goodbye"
- /////////////////////////////////////////////////////////
- // FTPServer
- PFTPServer::PFTPServer()
- : readyString(PIPSocket::GetHostName() & READY_STRING)
- {
- Construct();
- }
- PFTPServer::PFTPServer(const PString & readyStr)
- : readyString(readyStr)
- {
- Construct();
- }
- void PFTPServer::Construct()
- {
- thirdPartyPort = FALSE;
- illegalPasswordCount = 0;
- state = NotConnected;
- type = 'A';
- structure = 'F';
- mode = 'S';
- passiveSocket = NULL;
- }
- PFTPServer::~PFTPServer()
- {
- delete passiveSocket;
- }
- BOOL PFTPServer::OnOpen()
- {
- // the default data port for a client is the same port
- PIPSocket * socket = GetSocket();
- if (socket == NULL)
- return FALSE;
- state = NeedUser;
- if (!WriteResponse(220, readyString))
- return FALSE;
- socket->GetPeerAddress(remoteHost, remotePort);
- return TRUE;
- }
- PString PFTPServer::GetHelloString(const PString & user) const
- {
- return PString("User") & user & "logged in.";
- }
- PString PFTPServer::GetGoodbyeString(const PString &) const
- {
- return PString(GOOBYE_STRING);
- }
- PString PFTPServer::GetSystemTypeString() const
- {
- return PProcess::GetOSClass() + " " + PProcess::GetOSName() + " " + PProcess::GetOSVersion();
- }
- BOOL PFTPServer::AuthoriseUser(const PString &, const PString &, BOOL &)
- {
- return TRUE;
- }
- BOOL PFTPServer::ProcessCommand()
- {
- PString args;
- PINDEX code;
- if (!ReadCommand(code, args))
- return FALSE;
- if (code == P_MAX_INDEX)
- return OnUnknown(args);
- // handle commands that require login
- if (state == Connected || !CheckLoginRequired(code))
- return DispatchCommand(code, args);
-
- // otherwise enforce login
- WriteResponse(530, "Please login with USER and PASS.");
- return TRUE;
- }
- BOOL PFTPServer::DispatchCommand(PINDEX code, const PString & args)
- {
- switch (code) {
- // mandatory commands
- case USER:
- return OnUSER(args);
- case PASS:
- return OnPASS(args);
- case QUIT:
- return OnQUIT(args);
- case PORT:
- return OnPORT(args);
- case STRU:
- return OnSTRU(args);
- case MODE:
- return OnMODE(args);
- case NOOP:
- return OnNOOP(args);
- case TYPE:
- return OnTYPE(args);
- case RETR:
- return OnRETR(args);
- case STOR:
- return OnSTOR(args);
- case SYST:
- return OnSYST(args);
- case STATcmd:
- return OnSTAT(args);
- case ACCT:
- return OnACCT(args);
- case CWD:
- return OnCWD(args);
- case CDUP:
- return OnCDUP(args);
- case PASV:
- return OnPASV(args);
- case APPE:
- return OnAPPE(args);
- case RNFR:
- return OnRNFR(args);
- case RNTO:
- return OnRNTO(args);
- case DELE:
- return OnDELE(args);
- case RMD:
- return OnRMD(args);
- case MKD:
- return OnMKD(args);
- case PWD:
- return OnPWD(args);
- case LIST:
- return OnLIST(args);
- case NLST:
- return OnNLST(args);
- // optional commands
- case HELP:
- return OnHELP(args);
- case SITE:
- return OnSITE(args);
- case ABOR:
- return OnABOR(args);
- case SMNT:
- return OnSMNT(args);
- case REIN:
- return OnREIN(args);
- case STOU:
- return OnSTOU(args);
- case ALLO:
- return OnALLO(args);
- case REST:
- return OnREST(args);
- default:
- PAssertAlways("Registered FTP command not handled");
- return FALSE;
- }
- return TRUE;
- }
- BOOL PFTPServer::CheckLoginRequired(PINDEX cmd)
- {
- static const BYTE RequiresLogin[NumCommands] = {
- 1, // USER
- 1, // PASS
- 0, // ACCT
- 0, // CWD
- 0, // CDUP
- 0, // SMNT
- 1, // QUIT
- 0, // REIN
- 1, // PORT
- 0, // PASV
- 1, // TYPE
- 1, // STRU
- 1, // MODE
- 0, // RETR
- 0, // STOR
- 0, // STOU
- 0, // APPE
- 0, // ALLO
- 0, // REST
- 0, // RNFR
- 0, // RNTO
- 1, // ABOR
- 0, // DELE
- 0, // RMD
- 0, // MKD
- 0, // PWD
- 0, // LIST
- 0, // NLST
- 1, // SITE
- 1, // SYST
- 1, // STAT
- 1, // HELP
- 1, // NOOP
- };
- if (cmd < NumCommands)
- return RequiresLogin[cmd] == 0;
- else
- return TRUE;
- }
- BOOL PFTPServer::OnUnknown(const PCaselessString & command)
- {
- WriteResponse(500, """ + command + "" command unrecognised.");
- return TRUE;
- }
- void PFTPServer::OnError(PINDEX errorCode, PINDEX cmdNum, const char * msg)
- {
- if (cmdNum < commandNames.GetSize())
- WriteResponse(errorCode, "Command "" + commandNames[cmdNum] + "":" + msg);
- else
- WriteResponse(errorCode, msg);
- }
- void PFTPServer::OnNotImplemented(PINDEX cmdNum)
- {
- OnError(502, cmdNum, "not implemented");
- }
- void PFTPServer::OnSyntaxError(PINDEX cmdNum)
- {
- OnError(501, cmdNum, "syntax error in parameters or arguments.");
- }
- void PFTPServer::OnCommandSuccessful(PINDEX cmdNum)
- {
- if (cmdNum < commandNames.GetSize())
- WriteResponse(200, """ + commandNames[cmdNum] + "" command successful.");
- }
- // mandatory commands that can be performed without loggin in
- BOOL PFTPServer::OnUSER(const PCaselessString & args)
- {
- userName = args;
- state = NeedPassword;
- WriteResponse(331, "Password required for " + args + ".");
- return TRUE;
- }
- BOOL PFTPServer::OnPASS(const PCaselessString & args)
- {
- BOOL replied = FALSE;
- if (state != NeedPassword)
- WriteResponse(503, "Login with USER first.");
- else if (!AuthoriseUser(userName, args, replied)) {
- if (!replied)
- WriteResponse(530, "Login incorrect.");
- if (illegalPasswordCount++ == MaxIllegalPasswords)
- return FALSE;
- } else {
- if (!replied)
- WriteResponse(230, GetHelloString(userName));
- illegalPasswordCount = 0;
- state = Connected;
- }
- return TRUE;
- }
- BOOL PFTPServer::OnQUIT(const PCaselessString & userName)
- {
- WriteResponse(221, GetGoodbyeString(userName));
- return FALSE;
- }
- BOOL PFTPServer::OnPORT(const PCaselessString & args)
- {
- PStringArray tokens = args.Tokenise(",");
- long values[6];
- PINDEX len = PMIN(args.GetSize(), 6);
- PINDEX i;
- for (i = 0; i < len; i++) {
- values[i] = tokens[i].AsInteger();
- if (values[i] < 0 || values[i] > 255)
- break;
- }
- if (i < 6)
- OnSyntaxError(PORT);
- else {
- PIPSocket * socket = GetSocket();
- if (socket == NULL)
- OnError(590, PORT, "not available on non-TCP transport.");
- else {
- remoteHost = PIPSocket::Address((BYTE)values[0],
- (BYTE)values[1], (BYTE)values[2], (BYTE)values[3]);
- remotePort = (WORD)(values[4]*256 + values[5]);
- if (remotePort < 1024 && remotePort != socket->GetPort()-1)
- OnError(590, PORT, "cannot access privileged port number.");
- else {
- PIPSocket::Address controlHost;
- GetSocket()->GetPeerAddress(controlHost);
- if (thirdPartyPort || remoteHost == controlHost)
- OnCommandSuccessful(PORT);
- else
- OnError(591, PORT, "three way transfer not allowed.");
- }
- }
- }
- return TRUE;
- }
- BOOL PFTPServer::OnPASV(const PCaselessString &)
- {
- if (passiveSocket != NULL)
- delete passiveSocket;
- passiveSocket = new PTCPSocket;
- passiveSocket->Listen();
- WORD portNo = passiveSocket->GetPort();
- PIPSocket::Address ourAddr;
- PIPSocket * socket = GetSocket();
- if (socket != NULL)
- socket->GetLocalAddress(ourAddr);
- PString str(PString::Printf,
- "Entering Passive Mode (%i,%i,%i,%i,%i,%i)",
- ourAddr.Byte1(),
- ourAddr.Byte2(),
- ourAddr.Byte3(),
- ourAddr.Byte4(),
- portNo/256, portNo%256);
- return WriteResponse(227, str);
- }
- BOOL PFTPServer::OnTYPE(const PCaselessString & args)
- {
- if (args.IsEmpty())
- OnSyntaxError(TYPE);
- else {
- switch (toupper(args[0])) {
- case 'A':
- type = 'A';
- break;
- case 'I':
- type = 'I';
- break;
- case 'E':
- case 'L':
- WriteResponse(504, PString("TYPE not implemented for parameter ") + args);
- return TRUE;
- default:
- OnSyntaxError(TYPE);
- return TRUE;
- }
- }
- OnCommandSuccessful(TYPE);
- return TRUE;
- }
- BOOL PFTPServer::OnMODE(const PCaselessString & args)
- {
- if (args.IsEmpty())
- OnSyntaxError(MODE);
- else {
- switch (toupper(args[0])) {
- case 'S':
- structure = 'S';
- break;
- case 'B':
- case 'C':
- WriteResponse(504, PString("MODE not implemented for parameter ") + args);
- return TRUE;
- default:
- OnSyntaxError(MODE);
- return TRUE;
- }
- }
- OnCommandSuccessful(MODE);
- return TRUE;
- }
- BOOL PFTPServer::OnSTRU(const PCaselessString & args)
- {
- if (args.IsEmpty())
- OnSyntaxError(STRU);
- else {
- switch (toupper(args[0])) {
- case 'F':
- structure = 'F';
- break;
- case 'R':
- case 'P':
- WriteResponse(504, PString("STRU not implemented for parameter ") + args);
- return TRUE;
- default:
- OnSyntaxError(STRU);
- return TRUE;
- }
- }
- OnCommandSuccessful(STRU);
- return TRUE;
- }
- BOOL PFTPServer::OnNOOP(const PCaselessString &)
- {
- OnCommandSuccessful(NOOP);
- return TRUE;
- }
- // mandatory commands that cannot be performed without logging in
- BOOL PFTPServer::OnRETR(const PCaselessString &)
- {
- OnNotImplemented(RETR);
- return TRUE;
- }
- BOOL PFTPServer::OnSTOR(const PCaselessString &)
- {
- OnNotImplemented(STOR);
- return TRUE;
- }
- BOOL PFTPServer::OnACCT(const PCaselessString &)
- {
- WriteResponse(532, "Need account for storing files");
- return TRUE;
- }
- BOOL PFTPServer::OnCWD(const PCaselessString &)
- {
- OnNotImplemented(CWD);
- return TRUE;
- }
- BOOL PFTPServer::OnCDUP(const PCaselessString &)
- {
- OnNotImplemented(CDUP);
- return TRUE;
- }
- BOOL PFTPServer::OnSMNT(const PCaselessString &)
- {
- OnNotImplemented(SMNT);
- return TRUE;
- }
- BOOL PFTPServer::OnREIN(const PCaselessString &)
- {
- OnNotImplemented(REIN);
- return TRUE;
- }
- BOOL PFTPServer::OnSTOU(const PCaselessString &)
- {
- OnNotImplemented(STOU);
- return TRUE;
- }
- BOOL PFTPServer::OnAPPE(const PCaselessString &)
- {
- OnNotImplemented(APPE);
- return TRUE;
- }
- BOOL PFTPServer::OnALLO(const PCaselessString &)
- {
- OnNotImplemented(ALLO);
- return TRUE;
- }
- BOOL PFTPServer::OnREST(const PCaselessString &)
- {
- OnNotImplemented(REST);
- return TRUE;
- }
- BOOL PFTPServer::OnRNFR(const PCaselessString &)
- {
- OnNotImplemented(RNFR);
- return TRUE;
- }
- BOOL PFTPServer::OnRNTO(const PCaselessString &)
- {
- OnNotImplemented(RNTO);
- return TRUE;
- }
- BOOL PFTPServer::OnABOR(const PCaselessString &)
- {
- OnNotImplemented(ABOR);
- return TRUE;
- }
- BOOL PFTPServer::OnDELE(const PCaselessString &)
- {
- OnNotImplemented(DELE);
- return TRUE;
- }
- BOOL PFTPServer::OnRMD(const PCaselessString &)
- {
- OnNotImplemented(RMD);
- return TRUE;
- }
- BOOL PFTPServer::OnMKD(const PCaselessString &)
- {
- OnNotImplemented(MKD);
- return TRUE;
- }
- BOOL PFTPServer::OnPWD(const PCaselessString &)
- {
- OnNotImplemented(PWD);
- return TRUE;
- }
- BOOL PFTPServer::OnLIST(const PCaselessString &)
- {
- OnNotImplemented(LIST);
- return TRUE;
- }
- BOOL PFTPServer::OnNLST(const PCaselessString &)
- {
- OnNotImplemented(NLST);
- return TRUE;
- }
- BOOL PFTPServer::OnSITE(const PCaselessString &)
- {
- OnNotImplemented(SITE);
- return TRUE;
- }
- BOOL PFTPServer::OnSYST(const PCaselessString &)
- {
- WriteResponse(215, GetSystemTypeString());
- return TRUE;
- }
- BOOL PFTPServer::OnSTAT(const PCaselessString &)
- {
- OnNotImplemented(STATcmd);
- return TRUE;
- }
- BOOL PFTPServer::OnHELP(const PCaselessString &)
- {
- OnNotImplemented(HELP);
- return TRUE;
- }
- void PFTPServer::SendToClient(const PFilePath & filename)
- {
- if (!PFile::Exists(filename))
- WriteResponse(450, filename + ": file not found");
- else {
- PTCPSocket * dataSocket;
- if (passiveSocket != NULL) {
- dataSocket = new PTCPSocket(*passiveSocket);
- delete passiveSocket;
- passiveSocket = NULL;
- } else
- dataSocket = new PTCPSocket(remoteHost, remotePort);
- if (!dataSocket->IsOpen())
- WriteResponse(425, "Cannot open data connection");
- else {
- if (type == 'A') {
- PTextFile file(filename, PFile::ReadOnly);
- if (!file.IsOpen())
- WriteResponse(450, filename + ": cannot open file");
- else {
- PString fileSize(PString::Unsigned, file.GetLength());
- WriteResponse(150, PString("Opening ASCII data connection for " + filename.GetFileName() + "(" + fileSize + " bytes)"));
- PString line;
- BOOL ok = TRUE;
- while (ok && file.ReadLine(line)) {
- if (!dataSocket->Write((const char *)line, line.GetLength())) {
- WriteResponse(426, "Connection closed - transfer aborted");
- ok = FALSE;
- }
- }
- file.Close();
- }
- } else {
- PFile file(filename, PFile::ReadOnly);
- if (!file.IsOpen())
- WriteResponse(450, filename + ": cannot open file");
- else {
- PString fileSize(PString::Unsigned, file.GetLength());
- WriteResponse(150, PString("Opening BINARY data connection for " + filename.GetFileName() + "(" + fileSize + " bytes)"));
- BYTE buffer[2048];
- BOOL ok = TRUE;
- while (ok && file.Read(buffer, 2048)) {
- if (!dataSocket->Write(buffer, file.GetLastReadCount())) {
- WriteResponse(426, "Connection closed - transfer aborted");
- ok = FALSE;
- }
- }
- file.Close();
- }
- }
- delete dataSocket;
- WriteResponse(226, "Transfer complete");
- }
- }
- }
- // End of File ///////////////////////////////////////////////////////////////