]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_redirect.cpp
Prevent using invalid UIDs and enforce UID/SID matching
[user/henk/code/inspircd.git] / src / modules / m_redirect.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2010 InspIRCd Development Team
6  * See: http://wiki.inspircd.org/Credits
7  *
8  * This program is free but copyrighted software; see
9  *            the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 #include "inspircd.h"
15
16 /* $ModDesc: Provides channel mode +L (limit redirection) */
17
18 /** Handle channel mode +L
19  */
20 class Redirect : public ModeHandler
21 {
22  public:
23         Redirect(Module* Creator) : ModeHandler(Creator, "redirect", 'L', PARAM_SETONLY, MODETYPE_CHANNEL) { }
24
25         ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
26         {
27                 if (adding)
28                 {
29                         if (IS_LOCAL(source))
30                         {
31                                 if (!ServerInstance->IsChannel(parameter.c_str(), ServerInstance->Config->Limits.ChanMax))
32                                 {
33                                         source->WriteNumeric(403, "%s %s :Invalid channel name", source->nick.c_str(), parameter.c_str());
34                                         parameter.clear();
35                                         return MODEACTION_DENY;
36                                 }
37                         }
38
39                         if (IS_LOCAL(source) && !IS_OPER(source))
40                         {
41                                 Channel* c = ServerInstance->FindChan(parameter);
42                                 if (!c)
43                                 {
44                                         source->WriteNumeric(690, "%s :Target channel %s must exist to be set as a redirect.",source->nick.c_str(),parameter.c_str());
45                                         parameter.clear();
46                                         return MODEACTION_DENY;
47                                 }
48                                 else if (c->GetPrefixValue(source) < OP_VALUE)
49                                 {
50                                         source->WriteNumeric(690, "%s :You must be opped on %s to set it as a redirect.",source->nick.c_str(),parameter.c_str());
51                                         parameter.clear();
52                                         return MODEACTION_DENY;
53                                 }
54                         }
55
56                         if (channel->GetModeParameter('L') == parameter)
57                                 return MODEACTION_DENY;
58                         /*
59                          * We used to do some checking for circular +L here, but there is no real need for this any more especially as we
60                          * now catch +L looping in PreJoin. Remove it, since O(n) logic makes me sad, and we catch it anyway. :) -- w00t
61                          */
62                         channel->SetModeParam('L', parameter);
63                         return MODEACTION_ALLOW;
64                 }
65                 else
66                 {
67                         if (channel->IsModeSet('L'))
68                         {
69                                 channel->SetModeParam('L', "");
70                                 return MODEACTION_ALLOW;
71                         }
72                 }
73
74                 return MODEACTION_DENY;
75
76         }
77 };
78
79 class ModuleRedirect : public Module
80 {
81
82         Redirect re;
83
84  public:
85
86         ModuleRedirect()
87                 : re(this)
88         {
89
90                 if (!ServerInstance->Modes->AddMode(&re))
91                         throw ModuleException("Could not add new modes!");
92                 Implementation eventlist[] = { I_OnUserPreJoin };
93                 ServerInstance->Modules->Attach(eventlist, this, 1);
94         }
95
96
97         virtual ModResult OnUserPreJoin(User* user, Channel* chan, const char* cname, std::string &privs, const std::string &keygiven)
98         {
99                 if (chan)
100                 {
101                         if (chan->IsModeSet('L') && chan->IsModeSet('l'))
102                         {
103                                 if (chan->GetUserCounter() >= atoi(chan->GetModeParameter('l').c_str()))
104                                 {
105                                         std::string channel = chan->GetModeParameter('L');
106
107                                         /* sometimes broken ulines can make circular or chained +L, avoid this */
108                                         Channel* destchan = NULL;
109                                         destchan = ServerInstance->FindChan(channel);
110                                         if (destchan && destchan->IsModeSet('L'))
111                                         {
112                                                 user->WriteNumeric(470, "%s %s * :You may not join this channel. A redirect is set, but you may not be redirected as it is a circular loop.", user->nick.c_str(), cname);
113                                                 return MOD_RES_DENY;
114                                         }
115
116                                         user->WriteNumeric(470, "%s %s %s :You may not join this channel, so you are automatically being transferred to the redirect channel.", user->nick.c_str(), cname, channel.c_str());
117                                         Channel::JoinUser(user, channel.c_str(), false, "", false, ServerInstance->Time());
118                                         return MOD_RES_DENY;
119                                 }
120                         }
121                 }
122                 return MOD_RES_PASSTHRU;
123         }
124
125         virtual ~ModuleRedirect()
126         {
127         }
128
129         virtual Version GetVersion()
130         {
131                 return Version("Provides channel mode +L (limit redirection)", VF_VENDOR);
132         }
133 };
134
135 MODULE_INIT(ModuleRedirect)