1 /*
2  * Copyright (C) 2004-2020 ZNC, see the NOTICE file for details.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef ZNC_CLIENT_H
18 #define ZNC_CLIENT_H
19 
20 #include <znc/zncconfig.h>
21 #include <znc/Socket.h>
22 #include <znc/Utils.h>
23 #include <znc/Message.h>
24 #include <znc/main.h>
25 #include <memory>
26 #include <functional>
27 
28 // Forward Declarations
29 class CZNC;
30 class CUser;
31 class CIRCNetwork;
32 class CIRCSock;
33 class CClient;
34 class CMessage;
35 class CChan;
36 // !Forward Declarations
37 
38 class CAuthBase : private CCoreTranslationMixin {
39   public:
CAuthBase(const CString & sUsername,const CString & sPassword,CZNCSock * pSock)40     CAuthBase(const CString& sUsername, const CString& sPassword,
41               CZNCSock* pSock)
42         : m_sUsername(sUsername), m_sPassword(sPassword), m_pSock(pSock) {}
43 
~CAuthBase()44     virtual ~CAuthBase() {}
45 
46     CAuthBase(const CAuthBase&) = delete;
47     CAuthBase& operator=(const CAuthBase&) = delete;
48 
SetLoginInfo(const CString & sUsername,const CString & sPassword,CZNCSock * pSock)49     virtual void SetLoginInfo(const CString& sUsername,
50                               const CString& sPassword, CZNCSock* pSock) {
51         m_sUsername = sUsername;
52         m_sPassword = sPassword;
53         m_pSock = pSock;
54     }
55 
56     void AcceptLogin(CUser& User);
57     void RefuseLogin(const CString& sReason);
58 
GetUsername()59     const CString& GetUsername() const { return m_sUsername; }
GetPassword()60     const CString& GetPassword() const { return m_sPassword; }
GetSocket()61     Csock* GetSocket() const { return m_pSock; }
62     CString GetRemoteIP() const;
63 
64     // Invalidate this CAuthBase instance which means it will no longer use
65     // m_pSock and AcceptLogin() or RefusedLogin() will have no effect.
66     virtual void Invalidate();
67 
68   protected:
69     virtual void AcceptedLogin(CUser& User) = 0;
70     virtual void RefusedLogin(const CString& sReason) = 0;
71 
72   private:
73     CString m_sUsername;
74     CString m_sPassword;
75     CZNCSock* m_pSock;
76 };
77 
78 class CClientAuth : public CAuthBase {
79   public:
80     CClientAuth(CClient* pClient, const CString& sUsername,
81                 const CString& sPassword);
~CClientAuth()82     virtual ~CClientAuth() {}
83 
84     CClientAuth(const CClientAuth&) = delete;
85     CClientAuth& operator=(const CClientAuth&) = delete;
86 
Invalidate()87     void Invalidate() override {
88         m_pClient = nullptr;
89         CAuthBase::Invalidate();
90     }
91     void AcceptedLogin(CUser& User) override;
92     void RefusedLogin(const CString& sReason) override;
93 
94   private:
95   protected:
96     CClient* m_pClient;
97 };
98 
99 class CClient : public CIRCSocket {
100   public:
CClient()101     CClient()
102         : CIRCSocket(),
103           m_bGotPass(false),
104           m_bGotNick(false),
105           m_bGotUser(false),
106           m_bInCap(false),
107           m_bCapNotify(false),
108           m_bAwayNotify(false),
109           m_bAccountNotify(false),
110           m_bExtendedJoin(false),
111           m_bNamesx(false),
112           m_bUHNames(false),
113           m_bAway(false),
114           m_bServerTime(false),
115           m_bBatch(false),
116           m_bEchoMessage(false),
117           m_bSelfMessage(false),
118           m_bPlaybackActive(false),
119           m_pUser(nullptr),
120           m_pNetwork(nullptr),
121           m_sNick("unknown-nick"),
122           m_sPass(""),
123           m_sUser(""),
124           m_sNetwork(""),
125           m_sIdentifier(""),
126           m_spAuth(),
127           m_ssAcceptedCaps(),
128           m_ssSupportedTags(),
129           m_mCoreCaps({
130               {"multi-prefix",
131                {false, [this](bool bVal) { m_bNamesx = bVal; }}},
132               {"userhost-in-names",
133                {false, [this](bool bVal) { m_bUHNames = bVal; }}},
134               {"echo-message",
135                {false, [this](bool bVal) { m_bEchoMessage = bVal; }}},
136               {"server-time",
137                {false, [this](bool bVal) {
138                 m_bServerTime = bVal;
139                 SetTagSupport("time", bVal);
140                }}},
141               {"batch", {false, [this](bool bVal) {
142                 m_bBatch = bVal;
143                 SetTagSupport("batch", bVal);
144               }}},
145               {"cap-notify",
146                {false, [this](bool bVal) { m_bCapNotify = bVal; }}},
147               {"away-notify",
148                {true, [this](bool bVal) { m_bAwayNotify = bVal; }}},
149               {"account-notify",
150                {true, [this](bool bVal) { m_bAccountNotify = bVal; }}},
151               {"extended-join",
152                {true, [this](bool bVal) { m_bExtendedJoin = bVal; }}},
153           }) {
154         EnableReadLine();
155         // RFC says a line can have 512 chars max, but we are
156         // a little more gentle ;)
157         SetMaxBufferThreshold(1024);
158 
159         // For compatibility with older clients
160         m_mCoreCaps["znc.in/server-time-iso"] = m_mCoreCaps["server-time"];
161         m_mCoreCaps["znc.in/batch"] = m_mCoreCaps["batch"];
162         m_mCoreCaps["znc.in/self-message"] = {
163             false, [this](bool bVal) { m_bSelfMessage = bVal; }};
164     }
165 
166     virtual ~CClient();
167 
168     CClient(const CClient&) = delete;
169     CClient& operator=(const CClient&) = delete;
170 
171     void SendRequiredPasswordNotice();
172     void AcceptLogin(CUser& User);
173     void RefuseLogin(const CString& sReason);
174 
175     CString GetNick(bool bAllowIRCNick = true) const;
176     CString GetNickMask() const;
GetIdentifier()177     CString GetIdentifier() const { return m_sIdentifier; }
HasCapNotify()178     bool HasCapNotify() const { return m_bCapNotify; }
HasAwayNotify()179     bool HasAwayNotify() const { return m_bAwayNotify; }
HasAccountNotify()180     bool HasAccountNotify() const { return m_bAccountNotify; }
HasExtendedJoin()181     bool HasExtendedJoin() const { return m_bExtendedJoin; }
HasNamesx()182     bool HasNamesx() const { return m_bNamesx; }
HasUHNames()183     bool HasUHNames() const { return m_bUHNames; }
IsAway()184     bool IsAway() const { return m_bAway; }
HasServerTime()185     bool HasServerTime() const { return m_bServerTime; }
HasBatch()186     bool HasBatch() const { return m_bBatch; }
HasEchoMessage()187     bool HasEchoMessage() const { return m_bEchoMessage; }
HasSelfMessage()188     bool HasSelfMessage() const { return m_bSelfMessage; }
189 
190     static bool IsValidIdentifier(const CString& sIdentifier);
191 
192     void UserCommand(CString& sLine);
193     void UserPortCommand(CString& sLine);
194     void StatusCTCP(const CString& sCommand);
195     void BouncedOff();
IsAttached()196     bool IsAttached() const { return m_pUser != nullptr; }
197 
IsPlaybackActive()198     bool IsPlaybackActive() const { return m_bPlaybackActive; }
SetPlaybackActive(bool bActive)199     void SetPlaybackActive(bool bActive) { m_bPlaybackActive = bActive; }
200 
201     void PutIRC(const CString& sLine);
202     /** Sends a raw data line to the client.
203      *  @param sLine The line to be sent.
204      *
205      *  The line is first passed \e unmodified to the \ref
206      *  CModule::OnSendToClient() module hook. If no module halts the process,
207      *  the line is then sent to the client.
208      *
209      *  These lines appear in the debug output in the following syntax:
210      *  \code [time] (user/network) ZNC -> CLI [line] \endcode
211      *
212      *  Prefer \l PutClient() instead.
213      */
214     bool PutClientRaw(const CString& sLine);
215     /** Sends a message to the client.
216      *  See \l PutClient(const CMessage&) for details.
217      */
218     void PutClient(const CString& sLine);
219     /** Sends a message to the client.
220      *  @param  Message The message to be sent.
221      *  @note   Only known and compatible messages and tags are sent.
222      *  @return \c true if the message was sent, or \c false if it was ignored.
223      *
224      *  This method ensures that only messages and tags, that the client has
225      *  explicitly requested, are sent. Not all IRC clients are capable of
226      *  handling all messages and tags. For example, some older versions of
227      *  popular clients were prepared to parse just one interesting tag,
228      *  \c time, and would break if multiple tags were included. Furthermore,
229      *  messages that are specific to a certain capability, should not be sent
230      *  to a client that has not requested the respective capability. Thus, in
231      *  order to stay compatible with a variety of IRC clients, ZNC has to
232      *  filter out messages and tags that the client has not explicitly
233      *  requested.
234      *
235      *  ### Message types
236      *
237      *  The following table documents which capabilities the client is required
238      *  to have requested in order to receive certain types of messages.
239      *
240      *  Message type | Capability
241      *  ------------ | ----------
242      *  \c ACCOUNT   | \l CClient::HasAccountNotify() (<a href="http://ircv3.net/specs/extensions/account-notify-3.1.html">account-notify</a>)
243      *  \c AWAY      | \l CClient::HasAwayNotify() (<a href="http://ircv3.net/specs/extensions/away-notify-3.1.html">away-notify</a>)
244      *
245      *  ### Message tags
246      *
247      *  The following table documents currently supported message tags, and
248      *  which capabilities the client is required to have requested to receive
249      *  the respective message tags.
250      *
251      *  Message tag | Capability
252      *  ----------- | ----------
253      *  \c time     | \l CClient::HasServerTime() (<a href="http://ircv3.net/specs/extensions/server-time-3.2.html">server-time</a>)
254      *  \c batch    | \l CClient::HasBatch() (<a href="http://ircv3.net/specs/extensions/batch-3.2.html">batch</a>)
255      *
256      *  Additional tags can be added via \l CClient::SetTagSupport().
257      *
258      *  @warning Bypassing the filter may cause troubles to some older IRC
259      *  clients.
260      *
261      *  It is possible to bypass the filter by converting a message to a string
262      *  using \l CMessage::ToString(), and passing the resulting raw line to the
263      *  \l CClient::PutClientRaw(const CString& sLine):
264      *  \code
265      *  pClient->PutClientRaw(Message.ToString());
266      *  \endcode
267      */
268     bool PutClient(const CMessage& Message);
269     unsigned int PutStatus(const CTable& table);
270     void PutStatus(const CString& sLine);
271     void PutStatusNotice(const CString& sLine);
272     void PutModule(const CString& sModule, const CString& sLine);
273     void PutModNotice(const CString& sModule, const CString& sLine);
274 
IsCapEnabled(const CString & sCap)275     bool IsCapEnabled(const CString& sCap) const {
276         return 1 == m_ssAcceptedCaps.count(sCap);
277     }
278 
IsTagEnabled(const CString & sTag)279     bool IsTagEnabled(const CString& sTag) const {
280         return 1 == m_ssSupportedTags.count(sTag);
281     }
282     /** Registers a tag as being supported or unsupported by the client.
283      *  This doesn't affect tags which the client sends.
284      *  @param sTag The tag to register.
285      *  @param bState Whether the client supports the tag.
286      */
287     void SetTagSupport(const CString& sTag, bool bState);
288 
289     void NotifyServerDependentCaps(const SCString& ssCaps);
290     void ClearServerDependentCaps();
291 
292     void ReadLine(const CString& sData) override;
293     bool SendMotd();
294     void HelpUser(const CString& sFilter = "");
295     void AuthUser();
296     void Connected() override;
297     void Timeout() override;
298     void Disconnected() override;
299     void ConnectionRefused() override;
300     void ReachedMaxBuffer() override;
301 
302     void SetNick(const CString& s);
SetAway(bool bAway)303     void SetAway(bool bAway) { m_bAway = bAway; }
GetUser()304     CUser* GetUser() const { return m_pUser; }
305     void SetNetwork(CIRCNetwork* pNetwork, bool bDisconnect = true,
306                     bool bReconnect = true);
GetNetwork()307     CIRCNetwork* GetNetwork() const { return m_pNetwork; }
308     const std::vector<CClient*>& GetClients() const;
309     const CIRCSock* GetIRCSock() const;
310     CIRCSock* GetIRCSock();
311     CString GetFullName() const;
312 
313   private:
314     void HandleCap(const CMessage& Message);
315     void RespondCap(const CString& sResponse);
316     void ParsePass(const CString& sAuthLine);
317     void ParseUser(const CString& sAuthLine);
318     void ParseIdentifier(const CString& sAuthLine);
319 
320     template <typename T>
321     void AddBuffer(const T& Message);
322     void EchoMessage(const CMessage& Message);
323 
324     std::set<CChan*> MatchChans(const CString& sPatterns) const;
325     unsigned int AttachChans(const std::set<CChan*>& sChans);
326     unsigned int DetachChans(const std::set<CChan*>& sChans);
327 
328     bool OnActionMessage(CActionMessage& Message);
329     bool OnCTCPMessage(CCTCPMessage& Message);
330     bool OnJoinMessage(CJoinMessage& Message);
331     bool OnModeMessage(CModeMessage& Message);
332     bool OnNoticeMessage(CNoticeMessage& Message);
333     bool OnPartMessage(CPartMessage& Message);
334     bool OnPingMessage(CMessage& Message);
335     bool OnPongMessage(CMessage& Message);
336     bool OnQuitMessage(CQuitMessage& Message);
337     bool OnTextMessage(CTextMessage& Message);
338     bool OnTopicMessage(CTopicMessage& Message);
339     bool OnOtherMessage(CMessage& Message);
340 
341   protected:
342     bool m_bGotPass;
343     bool m_bGotNick;
344     bool m_bGotUser;
345     bool m_bInCap;
346     bool m_bCapNotify;
347     bool m_bAwayNotify;
348     bool m_bAccountNotify;
349     bool m_bExtendedJoin;
350     bool m_bNamesx;
351     bool m_bUHNames;
352     bool m_bAway;
353     bool m_bServerTime;
354     bool m_bBatch;
355     bool m_bEchoMessage;
356     bool m_bSelfMessage;
357     bool m_bPlaybackActive;
358     CUser* m_pUser;
359     CIRCNetwork* m_pNetwork;
360     CString m_sNick;
361     CString m_sPass;
362     CString m_sUser;
363     CString m_sNetwork;
364     CString m_sIdentifier;
365     std::shared_ptr<CAuthBase> m_spAuth;
366     SCString m_ssAcceptedCaps;
367     SCString m_ssSupportedTags;
368     // The capabilities supported by the ZNC core - capability names mapped
369     // to a pair which contains a bool describing whether the capability is
370     // server-dependent, and a capability value change handler.
371     std::map<CString, std::pair<bool, std::function<void(bool bVal)>>>
372         m_mCoreCaps;
373     // A subset of CIRCSock::GetAcceptedCaps(), the caps that can be listed
374     // in CAP LS and may be notified to the client with CAP NEW (cap-notify).
375     SCString m_ssServerDependentCaps;
376 
377     friend class ClientTest;
378 };
379 
380 #endif  // !ZNC_CLIENT_H
381