1 /*
2  * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 /* DEBUG: section 09    File Transfer Protocol (FTP) */
10 
11 #ifndef SQUID_FTP_CLIENT_H
12 #define SQUID_FTP_CLIENT_H
13 
14 #include "clients/Client.h"
15 
16 class String;
17 namespace Ftp
18 {
19 
20 extern const char *const crlf;
21 
22 /// Common code for FTP server control and data channels.
23 /// Does not own the channel descriptor, which is managed by Ftp::Client.
24 class Channel
25 {
26 public:
27     /// called after the socket is opened, sets up close handler
28     void opened(const Comm::ConnectionPointer &conn, const AsyncCall::Pointer &aCloser);
29 
30     /** Handles all operations needed to properly close the active channel FD.
31      * clearing the close handler, clearing the listen socket properly, and calling comm_close
32      */
33     void close();
34 
35     void forget(); /// remove the close handler, leave connection open
36 
37     void clear(); ///< just drops conn and close handler. does not close active connections.
38 
39     Comm::ConnectionPointer conn; ///< channel descriptor
40 
41     /** A temporary handle to the connection being listened on.
42      * Closing this will also close the waiting Data channel acceptor.
43      * If a data connection has already been accepted but is still waiting in the event queue
44      * the callback will still happen and needs to be handled (usually dropped).
45      */
46     Comm::ConnectionPointer listenConn;
47 
48     AsyncCall::Pointer opener; ///< Comm opener handler callback.
49 private:
50     AsyncCall::Pointer closer; ///< Comm close handler callback
51 };
52 
53 /// FTP channel for control commands.
54 /// This channel is opened once per transaction.
55 class CtrlChannel: public Ftp::Channel
56 {
57 public:
58     CtrlChannel();
59     ~CtrlChannel();
60 
61     char *buf;
62     size_t size;
63     size_t offset;
64     wordlist *message;
65     char *last_command;
66     char *last_reply;
67     int replycode;
68 
69 private:
70     CtrlChannel(const CtrlChannel &); // not implemented
71     CtrlChannel &operator =(const CtrlChannel &); // not implemented
72 };
73 
74 /// FTP channel for data exchanges.
75 /// This channel may be opened/closed a few times.
76 class DataChannel: public Ftp::Channel
77 {
78 public:
79     DataChannel();
80     ~DataChannel();
81 
82     void addr(const Ip::Address &addr); ///< import host and port
83 
84 public:
85     MemBuf *readBuf;
86     char *host;
87     unsigned short port;
88     bool read_pending;
89 };
90 
91 /// FTP client functionality shared among FTP Gateway and Relay clients.
92 class Client: public ::Client
93 {
94     CBDATA_CLASS(Client);
95 
96 public:
97     explicit Client(FwdState *fwdState);
98     virtual ~Client();
99 
100     /// handle a fatal transaction error, closing the control connection
101     virtual void failed(err_type error = ERR_NONE, int xerrno = 0,
102                         ErrorState *ftperr = nullptr);
103 
104     /// read timeout handler
105     virtual void timeout(const CommTimeoutCbParams &io);
106 
107     /* Client API */
108     virtual void maybeReadVirginBody();
109 
110     void writeCommand(const char *buf);
111 
112     /// extracts remoteAddr from PASV response, validates it,
113     /// sets data address details, and returns true on success
114     bool handlePasvReply(Ip::Address &remoteAddr);
115     bool handleEpsvReply(Ip::Address &remoteAddr);
116 
117     bool sendEprt();
118     bool sendPort();
119     bool sendPassive();
120     void connectDataChannel();
121     bool openListenSocket();
122     void switchTimeoutToDataChannel();
123 
124     CtrlChannel ctrl; ///< FTP control channel state
125     DataChannel data; ///< FTP data channel state
126 
127     enum {
128         BEGIN,
129         SENT_USER,
130         SENT_PASS,
131         SENT_TYPE,
132         SENT_MDTM,
133         SENT_SIZE,
134         SENT_EPRT,
135         SENT_PORT,
136         SENT_EPSV_ALL,
137         SENT_EPSV_1,
138         SENT_EPSV_2,
139         SENT_PASV,
140         SENT_CWD,
141         SENT_LIST,
142         SENT_NLST,
143         SENT_REST,
144         SENT_RETR,
145         SENT_STOR,
146         SENT_QUIT,
147         READING_DATA,
148         WRITING_DATA,
149         SENT_MKDIR,
150         SENT_FEAT,
151         SENT_PWD,
152         SENT_CDUP,
153         SENT_DATA_REQUEST, // LIST, NLST or RETR requests..
154         SENT_COMMAND, // General command
155         END
156     } ftp_state_t;
157 
158     int state;
159     char *old_request;
160     char *old_reply;
161 
162 protected:
163     /* AsyncJob API */
164     virtual void start();
165 
166     /* Client API */
167     virtual void closeServer();
168     virtual bool doneWithServer() const;
169     virtual const Comm::ConnectionPointer & dataConnection() const;
170     virtual void abortAll(const char *reason);
171 
172     virtual Http::StatusCode failedHttpStatus(err_type &error);
173     void ctrlClosed(const CommCloseCbParams &io);
174     void scheduleReadControlReply(int buffered_ok);
175     void readControlReply(const CommIoCbParams &io);
176     virtual void handleControlReply();
177     void writeCommandCallback(const CommIoCbParams &io);
178     virtual void dataChannelConnected(const CommConnectCbParams &io) = 0;
179     void dataRead(const CommIoCbParams &io);
180     void dataComplete();
181     AsyncCall::Pointer dataCloser();
182     virtual void dataClosed(const CommCloseCbParams &io);
183     void initReadBuf();
184 
185     // sending of the request body to the server
186     virtual void sentRequestBody(const CommIoCbParams &io);
187     virtual void doneSendingRequestBody();
188 
189 private:
190     bool parseControlReply(size_t &bytesUsed);
191 
192     /// XXX: An old hack for FTP servers like ftp.netscape.com that may not
193     /// respond to PASV. Use faster connect timeout instead of read timeout.
194     bool shortenReadTimeout;
195 };
196 
197 } // namespace Ftp
198 
199 #endif /* SQUID_FTP_CLIENT_H */
200 
201