Anope IRC Services  Version 2.0
os_forbid.cpp
Go to the documentation of this file.
1 /* OperServ core functions
2  *
3  * (C) 2003-2014 Anope Team
4  * Contact us at team@anope.org
5  *
6  * Please read COPYING and README for further details.
7  *
8  * Based on the original code of Epona by Lara.
9  * Based on the original code of Services by Andy Church.
10  */
11 
12 #include "module.h"
13 #include "modules/os_forbid.h"
14 
15 static ServiceReference<NickServService> nickserv("NickServService", "NickServ");
16 
18 {
19  ForbidDataImpl() : Serializable("ForbidData") { }
20  void Serialize(Serialize::Data &data) const anope_override;
22 };
23 
25 {
26  data["mask"] << this->mask;
27  data["creator"] << this->creator;
28  data["reason"] << this->reason;
29  data["created"] << this->created;
30  data["expires"] << this->expires;
31  data["type"] << this->type;
32 }
33 
35 {
36  if (!forbid_service)
37  return NULL;
38 
39  ForbidDataImpl *fb;
40  if (obj)
42  else
43  fb = new ForbidDataImpl();
44 
45  data["mask"] >> fb->mask;
46  data["creator"] >> fb->creator;
47  data["reason"] >> fb->reason;
48  data["created"] >> fb->created;
49  data["expires"] >> fb->expires;
50  unsigned int t;
51  data["type"] >> t;
52  fb->type = static_cast<ForbidType>(t);
53 
54  if (t > FT_SIZE - 1)
55  return NULL;
56 
57  if (!obj)
58  forbid_service->AddForbid(fb);
59  return fb;
60 }
61 
63 {
65 
66  inline std::vector<ForbidData *>& forbids(unsigned t) { return (*this->forbid_data)[t - 1]; }
67 
68  public:
69  MyForbidService(Module *m) : ForbidService(m), forbid_data("ForbidData") { }
70 
72  {
73  std::vector<ForbidData *> f = GetForbids();
74  for (unsigned i = 0; i < f.size(); ++i)
75  delete f[i];
76  }
77 
79  {
80  this->forbids(d->type).push_back(d);
81  }
82 
84  {
85  std::vector<ForbidData *>::iterator it = std::find(this->forbids(d->type).begin(), this->forbids(d->type).end(), d);
86  if (it != this->forbids(d->type).end())
87  this->forbids(d->type).erase(it);
88  delete d;
89  }
90 
92  {
93  return new ForbidDataImpl();
94  }
95 
97  {
98  for (unsigned i = this->forbids(ftype).size(); i > 0; --i)
99  {
100  ForbidData *d = this->forbids(ftype)[i - 1];
101 
102  if (Anope::Match(mask, d->mask, false, true))
103  return d;
104  }
105  return NULL;
106  }
107 
108  std::vector<ForbidData *> GetForbids() anope_override
109  {
110  std::vector<ForbidData *> f;
111  for (unsigned j = FT_NICK; j < FT_SIZE; ++j)
112  for (unsigned i = this->forbids(j).size(); i > 0; --i)
113  {
114  ForbidData *d = this->forbids(j).at(i - 1);
115 
116  if (d->expires && !Anope::NoExpire && Anope::CurTime >= d->expires)
117  {
118  Anope::string ftype = "none";
119  if (d->type == FT_NICK)
120  ftype = "nick";
121  else if (d->type == FT_CHAN)
122  ftype = "chan";
123  else if (d->type == FT_EMAIL)
124  ftype = "email";
125 
126  Log(LOG_NORMAL, "expire/forbid", Config->GetClient("OperServ")) << "Expiring forbid for " << d->mask << " type " << ftype;
127  this->forbids(j).erase(this->forbids(j).begin() + i - 1);
128  delete d;
129  }
130  else
131  f.push_back(d);
132  }
133 
134  return f;
135  }
136 };
137 
138 class CommandOSForbid : public Command
139 {
141  public:
142  CommandOSForbid(Module *creator) : Command(creator, "operserv/forbid", 1, 5), fs("ForbidService", "forbid")
143  {
144  this->SetDesc(_("Forbid usage of nicknames, channels, and emails"));
145  this->SetSyntax(_("ADD {NICK|CHAN|EMAIL|REGISTER} [+\037expiry\037] \037entry\037 \037reason\037"));
146  this->SetSyntax(_("DEL {NICK|CHAN|EMAIL|REGISTER} \037entry\037"));
147  this->SetSyntax("LIST [NICK|CHAN|EMAIL|REGISTER]");
148  }
149 
150  void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
151  {
152  if (!this->fs)
153  return;
154 
155  const Anope::string &command = params[0];
156  const Anope::string &subcommand = params.size() > 1 ? params[1] : "";
157 
158  ForbidType ftype = FT_SIZE;
159  if (subcommand.equals_ci("NICK"))
160  ftype = FT_NICK;
161  else if (subcommand.equals_ci("CHAN"))
162  ftype = FT_CHAN;
163  else if (subcommand.equals_ci("EMAIL"))
164  ftype = FT_EMAIL;
165  else if (subcommand.equals_ci("REGISTER"))
166  ftype = FT_REGISTER;
167 
168  if (command.equals_ci("ADD") && params.size() > 3 && ftype != FT_SIZE)
169  {
170  const Anope::string &expiry = params[2][0] == '+' ? params[2] : "";
171  const Anope::string &entry = !expiry.empty() ? params[3] : params[2];
172  Anope::string reason;
173  if (expiry.empty())
174  reason = params[3] + " ";
175  if (params.size() > 4)
176  reason += params[4];
177  reason.trim();
178 
179  if (entry.replace_all_cs("?*", "").empty())
180  {
181  source.Reply(_("The mask must contain at least one non wildcard character."));
182  return;
183  }
184 
185  time_t expiryt = 0;
186 
187  if (!expiry.empty())
188  {
189  expiryt = Anope::DoTime(expiry);
190  if (expiryt == -1)
191  {
192  source.Reply(BAD_EXPIRY_TIME);
193  return;
194  }
195  else if (expiryt)
196  expiryt += Anope::CurTime;
197  }
198 
199  NickAlias *target = NickAlias::Find(entry);
200  if (target != NULL && Config->GetModule("nickserv")->Get<bool>("secureadmins", "yes") && target->nc->IsServicesOper())
201  {
202  source.Reply(ACCESS_DENIED);
203  return;
204  }
205 
206  ForbidData *d = this->fs->FindForbid(entry, ftype);
207  bool created = false;
208  if (d == NULL)
209  {
210  d = new ForbidDataImpl();
211  created = true;
212  }
213 
214  d->mask = entry;
215  d->creator = source.GetNick();
216  d->reason = reason;
217  d->created = Anope::CurTime;
218  d->expires = expiryt;
219  d->type = ftype;
220  if (created)
221  this->fs->AddForbid(d);
222 
223  if (Anope::ReadOnly)
224  source.Reply(READ_ONLY_MODE);
225 
226  Log(LOG_ADMIN, source, this) << "to add a forbid on " << entry << " of type " << subcommand;
227  source.Reply(_("Added a forbid on %s of type %s to expire on %s."), entry.c_str(), subcommand.lower().c_str(), d->expires ? Anope::strftime(d->expires, source.GetAccount()).c_str() : "never");
228 
229  /* apply forbid */
230  switch (ftype)
231  {
232  case FT_NICK:
233  {
234  int na_matches = 0;
235 
236  for (user_map::const_iterator it = UserListByNick.begin(); it != UserListByNick.end(); ++it)
237  module->OnUserNickChange(it->second, "");
238 
239  for (nickalias_map::const_iterator it = NickAliasList->begin(), it_end = NickAliasList->end(); it != it_end;)
240  {
241  NickAlias *na = it->second;
242  ++it;
243 
244  d = this->fs->FindForbid(na->nick, FT_NICK);
245  if (d == NULL)
246  continue;
247 
248  ++na_matches;
249 
250  delete na;
251  }
252 
253  source.Reply(_("\002%d\002 nickname(s) dropped."), na_matches);
254  break;
255  }
256  case FT_CHAN:
257  {
258  int chan_matches = 0, ci_matches = 0;
259 
260  for (channel_map::const_iterator it = ChannelList.begin(), it_end = ChannelList.end(); it != it_end;)
261  {
262  Channel *c = it->second;
263  ++it;
264 
265  d = this->fs->FindForbid(c->name, FT_CHAN);
266  if (d == NULL)
267  continue;
268 
269  ServiceReference<ChanServService> chanserv("ChanServService", "ChanServ");
270  BotInfo *OperServ = Config->GetClient("OperServ");
271  if (IRCD->CanSQLineChannel && OperServ)
272  {
273  time_t inhabit = Config->GetModule("chanserv")->Get<time_t>("inhabit", "15s");
274  XLine x(c->name, OperServ->nick, Anope::CurTime + inhabit, d->reason);
275  IRCD->SendSQLine(NULL, &x);
276  }
277  else if (chanserv)
278  {
279  chanserv->Hold(c);
280  }
281 
282  ++chan_matches;
283 
284  for (Channel::ChanUserList::const_iterator cit = c->users.begin(), cit_end = c->users.end(); cit != cit_end;)
285  {
286  User *u = cit->first;
287  ++cit;
288 
289  if (u->server == Me || u->HasMode("OPER"))
290  continue;
291 
292  reason = Anope::printf(Language::Translate(u, _("This channel has been forbidden: %s")), d->reason.c_str());
293 
294  c->Kick(source.service, u, "%s", reason.c_str());
295  }
296  }
297 
298  for (registered_channel_map::const_iterator it = RegisteredChannelList->begin(); it != RegisteredChannelList->end();)
299  {
300  ChannelInfo *ci = it->second;
301  ++it;
302 
303  d = this->fs->FindForbid(ci->name, FT_CHAN);
304  if (d == NULL)
305  continue;
306 
307  ++ci_matches;
308 
309  delete ci;
310  }
311 
312  source.Reply(_("\002%d\002 channel(s) cleared, and \002%d\002 channel(s) dropped."), chan_matches, ci_matches);
313 
314  break;
315  }
316  default:
317  break;
318  }
319 
320  }
321  else if (command.equals_ci("DEL") && params.size() > 2 && ftype != FT_SIZE)
322  {
323  const Anope::string &entry = params[2];
324 
325  ForbidData *d = this->fs->FindForbid(entry, ftype);
326  if (d != NULL)
327  {
328  if (Anope::ReadOnly)
329  source.Reply(READ_ONLY_MODE);
330 
331  Log(LOG_ADMIN, source, this) << "to remove forbid on " << d->mask << " of type " << subcommand;
332  source.Reply(_("%s deleted from the %s forbid list."), d->mask.c_str(), subcommand.c_str());
333  this->fs->RemoveForbid(d);
334  }
335  else
336  source.Reply(_("Forbid on %s was not found."), entry.c_str());
337  }
338  else if (command.equals_ci("LIST"))
339  {
340  const std::vector<ForbidData *> &forbids = this->fs->GetForbids();
341  if (forbids.empty())
342  source.Reply(_("Forbid list is empty."));
343  else
344  {
345  ListFormatter list(source.GetAccount());
346  list.AddColumn(_("Mask")).AddColumn(_("Type")).AddColumn(_("Creator")).AddColumn(_("Expires")).AddColumn(_("Reason"));
347 
348  unsigned shown = 0;
349  for (unsigned i = 0; i < forbids.size(); ++i)
350  {
351  ForbidData *d = forbids[i];
352 
353  if (ftype != FT_SIZE && ftype != d->type)
354  continue;
355 
356  Anope::string stype;
357  if (d->type == FT_NICK)
358  stype = "NICK";
359  else if (d->type == FT_CHAN)
360  stype = "CHAN";
361  else if (d->type == FT_EMAIL)
362  stype = "EMAIL";
363  else if (d->type == FT_REGISTER)
364  stype = "REGISTER";
365  else
366  continue;
367 
369  entry["Mask"] = d->mask;
370  entry["Type"] = stype;
371  entry["Creator"] = d->creator;
372  entry["Expires"] = d->expires ? Anope::strftime(d->expires, NULL, true).c_str() : Language::Translate(source.GetAccount(), _("Never"));
373  entry["Reason"] = d->reason;
374  list.AddEntry(entry);
375  ++shown;
376  }
377 
378  if (!shown)
379  {
380  source.Reply(_("There are no forbids of type %s."), subcommand.upper().c_str());
381  }
382  else
383  {
384  source.Reply(_("Forbid list:"));
385 
386  std::vector<Anope::string> replies;
387  list.Process(replies);
388 
389  for (unsigned i = 0; i < replies.size(); ++i)
390  source.Reply(replies[i]);
391 
392  if (shown >= forbids.size())
393  source.Reply(_("End of forbid list."));
394  else
395  source.Reply(_("End of forbid list - %d/%d entries shown."), shown, forbids.size());
396  }
397  }
398  }
399  else
400  this->OnSyntaxError(source, command);
401 
402  return;
403  }
404 
405  bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
406  {
407  this->SendSyntax(source);
408  source.Reply(" ");
409  source.Reply(_("Forbid allows you to forbid usage of certain nicknames, channels,\n"
410  "and email addresses. Wildcards are accepted for all entries."));
411 
412  const Anope::string &regexengine = Config->GetBlock("options")->Get<const Anope::string>("regexengine");
413  if (!regexengine.empty())
414  {
415  source.Reply(" ");
416  source.Reply(_("Regex matches are also supported using the %s engine.\n"
417  "Enclose your pattern in // if this is desired."), regexengine.c_str());
418  }
419 
420  return true;
421  }
422 };
423 
424 class OSForbid : public Module
425 {
429 
430  public:
431  OSForbid(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
432  forbidService(this), forbiddata_type("ForbidData", ForbidDataImpl::Unserialize), commandosforbid(this)
433  {
434 
435  }
436 
437  void OnUserConnect(User *u, bool &exempt) anope_override
438  {
439  if (u->Quitting() || exempt)
440  return;
441 
442  this->OnUserNickChange(u, "");
443  }
444 
446  {
447  if (u->HasMode("OPER"))
448  return;
449 
450  ForbidData *d = this->forbidService.FindForbid(u->nick, FT_NICK);
451  if (d != NULL)
452  {
453  BotInfo *bi = Config->GetClient("NickServ");
454  if (!bi)
455  bi = Config->GetClient("OperServ");
456  if (bi)
457  u->SendMessage(bi, _("This nickname has been forbidden: %s"), d->reason.c_str());
458  if (nickserv)
459  nickserv->Collide(u, NULL);
460  }
461  }
462 
464  {
465  BotInfo *OperServ = Config->GetClient("OperServ");
466  if (u->HasMode("OPER") || !OperServ)
467  return EVENT_CONTINUE;
468 
469  ForbidData *d = this->forbidService.FindForbid(c->name, FT_CHAN);
470  if (d != NULL)
471  {
472  ServiceReference<ChanServService> chanserv("ChanServService", "ChanServ");
473  if (IRCD->CanSQLineChannel)
474  {
475  time_t inhabit = Config->GetModule("chanserv")->Get<time_t>("inhabit", "15s");
476  XLine x(c->name, OperServ->nick, Anope::CurTime + inhabit, d->reason);
477  IRCD->SendSQLine(NULL, &x);
478  }
479  else if (chanserv)
480  {
481  chanserv->Hold(c);
482  }
483 
484  reason = Anope::printf(Language::Translate(u, _("This channel has been forbidden: %s")), d->reason.c_str());
485 
486  return EVENT_STOP;
487  }
488 
489  return EVENT_CONTINUE;
490  }
491 
492  EventReturn OnPreCommand(CommandSource &source, Command *command, std::vector<Anope::string> &params) anope_override
493  {
494  if (command->name == "nickserv/info" && params.size() > 0)
495  {
496  ForbidData *d = this->forbidService.FindForbid(params[0], FT_NICK);
497  if (d != NULL)
498  {
499  if (source.IsOper())
500  source.Reply(_("Nick \002%s\002 is forbidden by %s: %s"), params[0].c_str(), d->creator.c_str(), d->reason.c_str());
501  else
502  source.Reply(_("Nick \002%s\002 is forbidden."), params[0].c_str());
503  return EVENT_STOP;
504  }
505  }
506  else if (command->name == "chanserv/info" && params.size() > 0)
507  {
508  ForbidData *d = this->forbidService.FindForbid(params[0], FT_CHAN);
509  if (d != NULL)
510  {
511  if (source.IsOper())
512  source.Reply(_("Channel \002%s\002 is forbidden by %s: %s"), params[0].c_str(), d->creator.c_str(), d->reason.c_str());
513  else
514  source.Reply(_("Channel \002%s\002 is forbidden."), params[0].c_str());
515  return EVENT_STOP;
516  }
517  }
518  else if (source.IsOper())
519  return EVENT_CONTINUE;
520  else if (command->name == "nickserv/register" && params.size() > 1)
521  {
522  ForbidData *d = this->forbidService.FindForbid(source.GetNick(), FT_REGISTER);
523  if (d != NULL)
524  {
525  source.Reply(NICK_CANNOT_BE_REGISTERED, source.GetNick().c_str());
526  return EVENT_STOP;
527  }
528 
529  d = this->forbidService.FindForbid(params[1], FT_EMAIL);
530  if (d != NULL)
531  {
532  source.Reply(_("Your email address is not allowed, choose a different one."));
533  return EVENT_STOP;
534  }
535  }
536  else if (command->name == "nickserv/set/email" && params.size() > 0)
537  {
538  ForbidData *d = this->forbidService.FindForbid(params[0], FT_EMAIL);
539  if (d != NULL)
540  {
541  source.Reply(_("Your email address is not allowed, choose a different one."));
542  return EVENT_STOP;
543  }
544  }
545  else if (command->name == "chanserv/register" && !params.empty())
546  {
547  ForbidData *d = this->forbidService.FindForbid(params[0], FT_REGISTER);
548  if (d != NULL)
549  {
550  source.Reply(CHAN_X_INVALID, params[0].c_str());
551  return EVENT_STOP;
552  }
553  }
554 
555  return EVENT_CONTINUE;
556  }
557 };
558 
Serialize::Reference< NickCore > nc
Definition: account.h:47
Definition: bots.h:24
bool HasMode(const Anope::string &name) const
Definition: users.cpp:513
#define CHAN_X_INVALID
Definition: language.h:102
CoreExport bool ReadOnly
Definition: main.cpp:28
static NickAlias * Find(const Anope::string &nick)
Definition: nickalias.cpp:121
EventReturn OnCheckKick(User *u, Channel *c, Anope::string &mask, Anope::string &reason) anope_override
Definition: os_forbid.cpp:463
ServiceReference< ForbidService > fs
Definition: os_forbid.cpp:140
bool CanSQLineChannel
Definition: protocol.h:59
Definition: hashcomp.h:84
Module * module
Definition: commands.h:108
Anope::string name
Definition: regchannel.h:63
time_t created
Definition: os_forbid.h:18
Anope::string nick
Definition: account.h:37
#define ACCESS_DENIED
Definition: language.h:73
CoreExport string printf(const char *fmt,...)
Definition: misc.cpp:536
ForbidType type
Definition: os_forbid.h:20
EventReturn OnPreCommand(CommandSource &source, Command *command, std::vector< Anope::string > &params) anope_override
Definition: os_forbid.cpp:492
Definition: users.h:34
string upper() const
Definition: anope.h:266
virtual void SendSQLine(User *, const XLine *x)
Definition: protocol.h:120
ForbidData * CreateForbid() anope_override
Definition: os_forbid.cpp:91
#define READ_ONLY_MODE
Definition: language.h:71
Anope::string mask
Definition: os_forbid.h:15
MyForbidService(Module *m)
Definition: os_forbid.cpp:69
void SetDesc(const Anope::string &d)
Definition: command.cpp:130
bool equals_ci(const char *_str) const
Definition: anope.h:78
Anope::string reason
Definition: os_forbid.h:17
void RemoveForbid(ForbidData *d) anope_override
Definition: os_forbid.cpp:83
Anope::string name
Definition: channels.h:44
CoreExport time_t CurTime
Definition: main.cpp:41
static ServiceReference< ForbidService > forbid_service("ForbidService","forbid")
iterator erase(const iterator &i)
Definition: anope.h:155
CoreExport Serialize::Checker< nickalias_map > NickAliasList
bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
Definition: os_forbid.cpp:405
Serialize::Type forbiddata_type
Definition: os_forbid.cpp:427
Serialize::Checker< std::vector< ForbidData * >[FT_SIZE-1]> forbid_data
Definition: os_forbid.cpp:64
std::map< Anope::string, Anope::string > ListEntry
Definition: lists.h:68
Definition: Config.cs:26
static Serializable * Unserialize(Serializable *obj, Serialize::Data &data)
Definition: os_forbid.cpp:34
CoreExport bool Match(const string &str, const string &mask, bool case_sensitive=false, bool use_regex=false)
Definition: misc.cpp:407
virtual void OnSyntaxError(CommandSource &source, const Anope::string &subcommand)
Definition: command.cpp:191
CoreExport time_t DoTime(const Anope::string &s)
Definition: misc.cpp:275
string replace_all_cs(const string &_orig, const string &_repl) const
Definition: anope.h:229
CoreExport Serialize::Checker< registered_channel_map > RegisteredChannelList
MyForbidService forbidService
Definition: os_forbid.cpp:426
CommandOSForbid(Module *creator)
Definition: os_forbid.cpp:142
string & trim(const Anope::string &what=" \t\r\n")
Definition: anope.h:177
#define anope_override
Definition: services.h:56
bool empty() const
Definition: anope.h:126
ForbidType
Definition: os_forbid.h:4
CommandOSForbid commandosforbid
Definition: os_forbid.cpp:428
void Serialize(Serialize::Data &data) const anope_override
Definition: os_forbid.cpp:24
CoreExport IRCDProto * IRCD
Definition: protocol.cpp:23
EventReturn
Definition: modules.h:129
#define MODULE_INIT(x)
Definition: modules.h:45
Server * server
Definition: users.h:77
CoreExport channel_map ChannelList
Definition: channels.cpp:29
CoreExport const char * Translate(const char *string)
Definition: language.cpp:59
ChanUserList users
Definition: channels.h:56
void OnUserNickChange(User *u, const Anope::string &) anope_override
Definition: os_forbid.cpp:445
void SetSyntax(const Anope::string &s)
Definition: command.cpp:140
std::vector< ForbidData * > & forbids(unsigned t)
Definition: os_forbid.cpp:66
Anope::string creator
Definition: os_forbid.h:16
virtual void Hold(Channel *c)=0
static ServiceReference< NickServService > nickserv("NickServService","NickServ")
virtual void OnUserNickChange(User *u, const Anope::string &oldnick)
Definition: modules.h:348
CoreExport bool NoExpire
Definition: main.cpp:28
Anope::string nick
Definition: users.h:62
void AddForbid(ForbidData *d) anope_override
Definition: os_forbid.cpp:78
ForbidData * FindForbid(const Anope::string &mask, ForbidType ftype) anope_override
Definition: os_forbid.cpp:96
bool Kick(BotInfo *bi, User *u, const char *reason=NULL,...)
Definition: channels.cpp:762
Definition: xline.h:18
T anope_dynamic_static_cast(O ptr)
Definition: anope.h:774
CoreExport Server * Me
Definition: servers.cpp:24
CoreExport user_map UserListByNick
Definition: users.cpp:28
time_t expires
Definition: os_forbid.h:19
void SendSyntax(CommandSource &)
Definition: command.cpp:145
OSForbid(const Anope::string &modname, const Anope::string &creator)
Definition: os_forbid.cpp:431
const char * c_str() const
Definition: anope.h:117
Definition: logger.h:53
#define BAD_EXPIRY_TIME
Definition: language.h:69
CoreExport Anope::string strftime(time_t t, const NickCore *nc=NULL, bool short_output=false)
Definition: misc.cpp:356
std::vector< ForbidData * > GetForbids() anope_override
Definition: os_forbid.cpp:108
void SendMessage(BotInfo *source, const char *fmt,...)
Definition: users.cpp:320
#define NICK_CANNOT_BE_REGISTERED
Definition: language.h:97
#define _(x)
Definition: services.h:50
ListFormatter & AddColumn(const Anope::string &name)
Definition: misc.cpp:128
void OnUserConnect(User *u, bool &exempt) anope_override
Definition: os_forbid.cpp:437
void Execute(CommandSource &source, const std::vector< Anope::string > &params) anope_override
Definition: os_forbid.cpp:150
Type(const Anope::string &n, unserialize_func f, Module *owner=NULL)