anope- supernets anope source code & configuration |
git clone git://git.acid.vegas/anope.git |
Log | Files | Refs | Archive | README |
unreal4.cpp (51888B)
1 /* Unreal IRCD 4 functions 2 * 3 * (C) 2003-2022 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/cs_mode.h" 14 #include "modules/sasl.h" 15 16 typedef Anope::map<Anope::string> ModData; 17 static Anope::string UplinkSID; 18 19 class UnrealIRCdProto : public IRCDProto 20 { 21 public: 22 PrimitiveExtensibleItem<ModData> ClientModData; 23 PrimitiveExtensibleItem<ModData> ChannelModData; 24 25 UnrealIRCdProto(Module *creator) : IRCDProto(creator, "UnrealIRCd 4+"), ClientModData(creator, "ClientModData"), ChannelModData(creator, "ChannelModData") 26 { 27 DefaultPseudoclientModes = "+BioqS"; 28 CanSVSNick = true; 29 CanSVSJoin = true; 30 CanSetVHost = true; 31 CanSetVIdent = true; 32 CanSNLine = true; 33 CanSQLine = true; 34 CanSZLine = true; 35 CanSVSHold = true; 36 CanCertFP = true; 37 RequiresID = true; 38 MaxModes = 12; 39 } 40 41 private: 42 /* SVSNOOP */ 43 void SendSVSNOOP(const Server *server, bool set) anope_override 44 { 45 UplinkSocket::Message() << "SVSNOOP " << server->GetSID() << " " << (set ? "+" : "-"); 46 } 47 48 void SendAkillDel(const XLine *x) anope_override 49 { 50 if (x->IsRegex() || x->HasNickOrReal()) 51 return; 52 53 /* ZLine if we can instead */ 54 if (x->GetUser() == "*") 55 { 56 cidr a(x->GetHost()); 57 if (a.valid()) 58 { 59 IRCD->SendSZLineDel(x); 60 return; 61 } 62 } 63 64 UplinkSocket::Message() << "TKL - G " << x->GetUser() << " " << x->GetHost() << " " << x->by; 65 } 66 67 void SendTopic(const MessageSource &source, Channel *c) anope_override 68 { 69 UplinkSocket::Message(source) << "TOPIC " << c->name << " " << c->topic_setter << " " << c->topic_ts << " :" << c->topic; 70 } 71 72 void SendGlobalNotice(BotInfo *bi, const Server *dest, const Anope::string &msg) anope_override 73 { 74 UplinkSocket::Message(bi) << "NOTICE $" << dest->GetName() << " :" << msg; 75 } 76 77 void SendGlobalPrivmsg(BotInfo *bi, const Server *dest, const Anope::string &msg) anope_override 78 { 79 UplinkSocket::Message(bi) << "PRIVMSG $" << dest->GetName() << " :" << msg; 80 } 81 82 void SendVhostDel(User *u) anope_override 83 { 84 BotInfo *HostServ = Config->GetClient("HostServ"); 85 u->RemoveMode(HostServ, "VHOST"); 86 } 87 88 void SendAkill(User *u, XLine *x) anope_override 89 { 90 if (x->IsRegex() || x->HasNickOrReal()) 91 { 92 if (!u) 93 { 94 /* No user (this akill was just added), and contains nick and/or realname. Find users that match and ban them */ 95 for (user_map::const_iterator it = UserListByNick.begin(); it != UserListByNick.end(); ++it) 96 if (x->manager->Check(it->second, x)) 97 this->SendAkill(it->second, x); 98 return; 99 } 100 101 const XLine *old = x; 102 103 if (old->manager->HasEntry("*@" + u->host)) 104 return; 105 106 /* We can't akill x as it has a nick and/or realname included, so create a new akill for *@host */ 107 XLine *xline = new XLine("*@" + u->host, old->by, old->expires, old->reason, old->id); 108 old->manager->AddXLine(xline); 109 x = xline; 110 111 Log(Config->GetClient("OperServ"), "akill") << "AKILL: Added an akill for " << x->mask << " because " << u->GetMask() << "#" << u->realname << " matches " << old->mask; 112 } 113 114 /* ZLine if we can instead */ 115 if (x->GetUser() == "*") 116 { 117 cidr a(x->GetHost()); 118 if (a.valid()) 119 { 120 IRCD->SendSZLine(u, x); 121 return; 122 } 123 } 124 125 // Calculate the time left before this would expire, capping it at 2 days 126 time_t timeleft = x->expires - Anope::CurTime; 127 if (timeleft > 172800 || !x->expires) 128 timeleft = 172800; 129 UplinkSocket::Message() << "TKL + G " << x->GetUser() << " " << x->GetHost() << " " << x->by << " " << Anope::CurTime + timeleft << " " << x->created << " :" << x->GetReason(); 130 } 131 132 void SendSVSKillInternal(const MessageSource &source, User *user, const Anope::string &buf) anope_override 133 { 134 UplinkSocket::Message(source) << "SVSKILL " << user->GetUID() << " :" << buf; 135 user->KillInternal(source, buf); 136 } 137 138 void SendModeInternal(const MessageSource &source, User *u, const Anope::string &buf) anope_override 139 { 140 UplinkSocket::Message(source) << "SVS2MODE " << u->GetUID() <<" " << buf; 141 } 142 143 void SendClientIntroduction(User *u) anope_override 144 { 145 Anope::string modes = "+" + u->GetModes(); 146 UplinkSocket::Message(u->server) << "UID " << u->nick << " 1 " << u->timestamp << " " << u->GetIdent() << " " << u->host << " " 147 << u->GetUID() << " * " << modes << " " << (!u->vhost.empty() ? u->vhost : "*") << " " 148 << (!u->chost.empty() ? u->chost : "*") << " " << "*" << " :" << u->realname; 149 } 150 151 void SendServer(const Server *server) anope_override 152 { 153 if (server == Me) 154 UplinkSocket::Message() << "SERVER " << server->GetName() << " " << server->GetHops() + 1 << " :" << server->GetDescription(); 155 else 156 UplinkSocket::Message(Me) << "SID " << server->GetName() << " " << server->GetHops() + 1 << " " << server->GetSID() << " :" << server->GetDescription(); 157 } 158 159 /* JOIN */ 160 void SendJoin(User *user, Channel *c, const ChannelStatus *status) anope_override 161 { 162 UplinkSocket::Message(Me) << "SJOIN " << c->creation_time << " " << c->name 163 << " +" << c->GetModes(true, true) << " :" << user->GetUID(); 164 if (status) 165 { 166 /* First save the channel status incase uc->Status == status */ 167 ChannelStatus cs = *status; 168 /* If the user is internally on the channel with flags, kill them so that 169 * the stacker will allow this. 170 */ 171 ChanUserContainer *uc = c->FindUser(user); 172 if (uc != NULL) 173 uc->status.Clear(); 174 175 BotInfo *setter = BotInfo::Find(user->GetUID()); 176 for (size_t i = 0; i < cs.Modes().length(); ++i) 177 c->SetMode(setter, ModeManager::FindChannelModeByChar(cs.Modes()[i]), user->GetUID(), false); 178 179 if (uc != NULL) 180 uc->status = cs; 181 } 182 } 183 184 /* unsqline 185 */ 186 void SendSQLineDel(const XLine *x) anope_override 187 { 188 UplinkSocket::Message() << "UNSQLINE " << x->mask; 189 } 190 191 /* SQLINE */ 192 /* 193 ** - Unreal will translate this to TKL for us 194 ** 195 */ 196 void SendSQLine(User *, const XLine *x) anope_override 197 { 198 UplinkSocket::Message() << "SQLINE " << x->mask << " :" << x->GetReason(); 199 } 200 201 /* Functions that use serval cmd functions */ 202 203 void SendVhost(User *u, const Anope::string &vIdent, const Anope::string &vhost) anope_override 204 { 205 if (!vIdent.empty()) 206 UplinkSocket::Message(Me) << "CHGIDENT " << u->GetUID() << " " << vIdent; 207 if (!vhost.empty()) 208 UplinkSocket::Message(Me) << "CHGHOST " << u->GetUID() << " " << vhost; 209 // Internally unreal sets +xt on chghost 210 BotInfo *bi = Config->GetClient("HostServ"); 211 u->SetMode(bi, "CLOAK"); 212 u->SetMode(bi, "VHOST"); 213 } 214 215 void SendConnect() anope_override 216 { 217 /* 218 NICKv2 = Nick Version 2 219 VHP = Sends hidden host 220 UMODE2 = sends UMODE2 on user modes 221 NICKIP = Sends IP on NICK 222 SJ3 = Supports SJOIN 223 NOQUIT = No Quit 224 TKLEXT = Extended TKL we don't use it but best to have it 225 MLOCK = Supports the MLOCK server command 226 VL = Version Info 227 SID = SID/UID mode 228 */ 229 UplinkSocket::Message() << "PASS :" << Config->Uplinks[Anope::CurrentUplink].password; 230 UplinkSocket::Message() << "PROTOCTL " << "NICKv2 VHP UMODE2 NICKIP SJOIN SJOIN2 SJ3 NOQUIT TKLEXT MLOCK SID MTAGS"; 231 UplinkSocket::Message() << "PROTOCTL " << "EAUTH=" << Me->GetName() << ",,,Anope-" << Anope::VersionShort(); 232 UplinkSocket::Message() << "PROTOCTL " << "SID=" << Me->GetSID(); 233 SendServer(Me); 234 } 235 236 void SendSASLMechanisms(std::vector<Anope::string> &mechanisms) anope_override 237 { 238 Anope::string mechlist; 239 for (unsigned i = 0; i < mechanisms.size(); ++i) 240 mechlist += "," + mechanisms[i]; 241 242 UplinkSocket::Message() << "MD client " << Me->GetName() << " saslmechlist :" << (mechanisms.empty() ? "" : mechlist.substr(1)); 243 } 244 245 /* SVSHOLD - set */ 246 void SendSVSHold(const Anope::string &nick, time_t t) anope_override 247 { 248 UplinkSocket::Message() << "TKL + Q H " << nick << " " << Me->GetName() << " " << Anope::CurTime + t << " " << Anope::CurTime << " :Being held for registered user"; 249 } 250 251 /* SVSHOLD - release */ 252 void SendSVSHoldDel(const Anope::string &nick) anope_override 253 { 254 UplinkSocket::Message() << "TKL - Q * " << nick << " " << Me->GetName(); 255 } 256 257 /* UNSGLINE */ 258 /* 259 * SVSNLINE - :realname mask 260 */ 261 void SendSGLineDel(const XLine *x) anope_override 262 { 263 UplinkSocket::Message() << "SVSNLINE - :" << x->mask; 264 } 265 266 /* UNSZLINE */ 267 void SendSZLineDel(const XLine *x) anope_override 268 { 269 UplinkSocket::Message() << "TKL - Z * " << x->GetHost() << " " << x->by; 270 } 271 272 /* SZLINE */ 273 void SendSZLine(User *, const XLine *x) anope_override 274 { 275 // Calculate the time left before this would expire, capping it at 2 days 276 time_t timeleft = x->expires - Anope::CurTime; 277 if (timeleft > 172800 || !x->expires) 278 timeleft = 172800; 279 UplinkSocket::Message() << "TKL + Z * " << x->GetHost() << " " << x->by << " " << Anope::CurTime + timeleft << " " << x->created << " :" << x->GetReason(); 280 } 281 282 /* SGLINE */ 283 /* 284 * SVSNLINE + reason_where_is_space :realname mask with spaces 285 */ 286 void SendSGLine(User *, const XLine *x) anope_override 287 { 288 Anope::string edited_reason = x->GetReason(); 289 edited_reason = edited_reason.replace_all_cs(" ", "_"); 290 UplinkSocket::Message() << "SVSNLINE + " << edited_reason << " :" << x->mask; 291 } 292 293 /* svsjoin 294 parv[0] - sender 295 parv[1] - nick to make join 296 parv[2] - channel to join 297 parv[3] - (optional) channel key(s) 298 */ 299 /* In older Unreal SVSJOIN and SVSNLINE tokens were mixed so SVSJOIN and SVSNLINE are broken 300 when coming from a none TOKEN'd server 301 */ 302 void SendSVSJoin(const MessageSource &source, User *user, const Anope::string &chan, const Anope::string ¶m) anope_override 303 { 304 if (!param.empty()) 305 UplinkSocket::Message() << "SVSJOIN " << user->GetUID() << " " << chan << " :" << param; 306 else 307 UplinkSocket::Message() << "SVSJOIN " << user->GetUID() << " " << chan; 308 } 309 310 void SendSVSPart(const MessageSource &source, User *user, const Anope::string &chan, const Anope::string ¶m) anope_override 311 { 312 if (!param.empty()) 313 UplinkSocket::Message() << "SVSPART " << user->GetUID() << " " << chan << " :" << param; 314 else 315 UplinkSocket::Message() << "SVSPART " << user->GetUID() << " " << chan; 316 } 317 318 void SendGlobopsInternal(const MessageSource &source, const Anope::string &buf) anope_override 319 { 320 UplinkSocket::Message(Me) << "SENDUMODE o :from " << source.GetName() << ": " << buf; 321 } 322 323 void SendSWhois(const MessageSource &source, const Anope::string &who, const Anope::string &mask) anope_override 324 { 325 UplinkSocket::Message() << "SWHOIS " << who << " :" << mask; 326 } 327 328 void SendEOB() anope_override 329 { 330 UplinkSocket::Message(Me) << "EOS"; 331 } 332 333 bool IsNickValid(const Anope::string &nick) anope_override 334 { 335 if (nick.equals_ci("ircd") || nick.equals_ci("irc")) 336 return false; 337 338 return IRCDProto::IsNickValid(nick); 339 } 340 341 bool IsChannelValid(const Anope::string &chan) anope_override 342 { 343 if (chan.find(':') != Anope::string::npos) 344 return false; 345 346 return IRCDProto::IsChannelValid(chan); 347 } 348 349 bool IsExtbanValid(const Anope::string &mask) anope_override 350 { 351 return mask.length() >= 4 && mask[0] == '~' && mask[2] == ':'; 352 } 353 354 void SendLogin(User *u, NickAlias *na) anope_override 355 { 356 /* 3.2.10.4+ treats users logged in with accounts as fully registered, even if -r, so we can not set this here. Just use the timestamp. */ 357 if (Servers::Capab.count("ESVID") > 0 && !na->nc->HasExt("UNCONFIRMED")) 358 IRCD->SendMode(Config->GetClient("NickServ"), u, "+d %s", na->nc->display.c_str()); 359 else 360 IRCD->SendMode(Config->GetClient("NickServ"), u, "+d %d", u->signon); 361 } 362 363 void SendLogout(User *u) anope_override 364 { 365 IRCD->SendMode(Config->GetClient("NickServ"), u, "+d 0"); 366 } 367 368 void SendChannel(Channel *c) anope_override 369 { 370 UplinkSocket::Message(Me) << "SJOIN " << c->creation_time << " " << c->name 371 << " +" << c->GetModes(true, true) << " :"; 372 } 373 374 void SendSASLMessage(const SASL::Message &message) anope_override 375 { 376 size_t p = message.target.find('!'); 377 Anope::string distmask; 378 379 if (p == Anope::string::npos) 380 { 381 Server *s = Server::Find(message.target.substr(0, 3)); 382 if (!s) 383 return; 384 distmask = s->GetName(); 385 } 386 else 387 { 388 distmask = message.target.substr(0, p); 389 } 390 391 UplinkSocket::Message(BotInfo::Find(message.source)) << "SASL " << distmask << " " << message.target << " " << message.type << " " << message.data << (message.ext.empty() ? "" : " " + message.ext); 392 } 393 394 void SendSVSLogin(const Anope::string &uid, const Anope::string &acc, const Anope::string &vident, const Anope::string &vhost) anope_override 395 { 396 size_t p = uid.find('!'); 397 Anope::string distmask; 398 399 if (p == Anope::string::npos) 400 { 401 Server *s = Server::Find(uid.substr(0, 3)); 402 if (!s) 403 return; 404 distmask = s->GetName(); 405 } 406 else 407 { 408 distmask = uid.substr(0, p); 409 } 410 UplinkSocket::Message(Me) << "SVSLOGIN " << distmask << " " << uid << " " << acc; 411 } 412 413 bool IsIdentValid(const Anope::string &ident) anope_override 414 { 415 if (ident.empty() || ident.length() > Config->GetBlock("networkinfo")->Get<unsigned>("userlen")) 416 return false; 417 418 for (unsigned i = 0; i < ident.length(); ++i) 419 { 420 const char &c = ident[i]; 421 422 if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '.' || c == '-') 423 continue; 424 425 if (c == '-' || c == '.' || c == '_') 426 continue; 427 428 return false; 429 } 430 431 return true; 432 } 433 }; 434 435 class UnrealExtBan : public ChannelModeVirtual<ChannelModeList> 436 { 437 char ext; 438 439 public: 440 UnrealExtBan(const Anope::string &mname, const Anope::string &basename, char extban) : ChannelModeVirtual<ChannelModeList>(mname, basename) 441 , ext(extban) 442 { 443 } 444 445 ChannelMode *Wrap(Anope::string ¶m) anope_override 446 { 447 param = "~" + Anope::string(ext) + ":" + param; 448 return ChannelModeVirtual<ChannelModeList>::Wrap(param); 449 } 450 451 ChannelMode *Unwrap(ChannelMode *cm, Anope::string ¶m) anope_override 452 { 453 if (cm->type != MODE_LIST || param.length() < 4 || param[0] != '~' || param[1] != ext || param[2] != ':') 454 return cm; 455 456 param = param.substr(3); 457 return this; 458 } 459 }; 460 461 namespace UnrealExtban 462 { 463 class ChannelMatcher : public UnrealExtBan 464 { 465 public: 466 ChannelMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : UnrealExtBan(mname, mbase, c) 467 { 468 } 469 470 bool Matches(User *u, const Entry *e) anope_override 471 { 472 const Anope::string &mask = e->GetMask(); 473 Anope::string channel = mask.substr(3); 474 475 ChannelMode *cm = NULL; 476 if (channel[0] != '#') 477 { 478 char modeChar = ModeManager::GetStatusChar(channel[0]); 479 channel.erase(channel.begin()); 480 cm = ModeManager::FindChannelModeByChar(modeChar); 481 if (cm != NULL && cm->type != MODE_STATUS) 482 cm = NULL; 483 } 484 485 Channel *c = Channel::Find(channel); 486 if (c != NULL) 487 { 488 ChanUserContainer *uc = c->FindUser(u); 489 if (uc != NULL) 490 if (cm == NULL || uc->status.HasMode(cm->mchar)) 491 return true; 492 } 493 494 return false; 495 } 496 }; 497 498 class EntryMatcher : public UnrealExtBan 499 { 500 public: 501 EntryMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : UnrealExtBan(mname, mbase, c) 502 { 503 } 504 505 bool Matches(User *u, const Entry *e) anope_override 506 { 507 const Anope::string &mask = e->GetMask(); 508 Anope::string real_mask = mask.substr(3); 509 510 return Entry(this->name, real_mask).Matches(u); 511 } 512 }; 513 514 class RealnameMatcher : public UnrealExtBan 515 { 516 public: 517 RealnameMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : UnrealExtBan(mname, mbase, c) 518 { 519 } 520 521 bool Matches(User *u, const Entry *e) anope_override 522 { 523 const Anope::string &mask = e->GetMask(); 524 Anope::string real_mask = mask.substr(3); 525 526 return Anope::Match(u->realname, real_mask); 527 } 528 }; 529 530 class RegisteredMatcher : public UnrealExtBan 531 { 532 public: 533 RegisteredMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : UnrealExtBan(mname, mbase, c) 534 { 535 } 536 537 bool Matches(User *u, const Entry *e) anope_override 538 { 539 const Anope::string &mask = e->GetMask(); 540 return u->HasMode("REGISTERED") && mask.equals_ci(u->nick); 541 } 542 }; 543 544 class AccountMatcher : public UnrealExtBan 545 { 546 public: 547 AccountMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : UnrealExtBan(mname, mbase, c) 548 { 549 } 550 551 bool Matches(User *u, const Entry *e) anope_override 552 { 553 const Anope::string &mask = e->GetMask(); 554 Anope::string real_mask = mask.substr(3); 555 556 if (real_mask == "0" && !u->Account()) /* ~a:0 is special and matches all unauthenticated users */ 557 return true; 558 559 return u->Account() && Anope::Match(u->Account()->display, real_mask); 560 } 561 }; 562 563 class FingerprintMatcher : public UnrealExtBan 564 { 565 public: 566 FingerprintMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : UnrealExtBan(mname, mbase, c) 567 { 568 } 569 570 bool Matches(User *u, const Entry *e) anope_override 571 { 572 const Anope::string &mask = e->GetMask(); 573 Anope::string real_mask = mask.substr(3); 574 return !u->fingerprint.empty() && Anope::Match(u->fingerprint, real_mask); 575 } 576 }; 577 578 class OperclassMatcher : public UnrealExtBan 579 { 580 public: 581 OperclassMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : UnrealExtBan(mname, mbase, c) 582 { 583 } 584 585 bool Matches(User *u, const Entry *e) anope_override 586 { 587 const Anope::string &mask = e->GetMask(); 588 Anope::string real_mask = mask.substr(3); 589 ModData *moddata = u->GetExt<ModData>("ClientModData"); 590 return moddata != NULL && moddata->find("operclass") != moddata->end() && Anope::Match((*moddata)["operclass"], real_mask); 591 } 592 }; 593 594 class TimedBanMatcher : public UnrealExtBan 595 { 596 public: 597 TimedBanMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : UnrealExtBan(mname, mbase, c) 598 { 599 } 600 601 bool Matches(User *u, const Entry *e) anope_override 602 { 603 /* strip down the time (~t:1234:) and call other matchers */ 604 const Anope::string &mask = e->GetMask(); 605 Anope::string real_mask = mask.substr(3); 606 real_mask = real_mask.substr(real_mask.find(":") + 1); 607 return Entry("BAN", real_mask).Matches(u); 608 } 609 }; 610 611 class CountryMatcher : public UnrealExtBan 612 { 613 public: 614 CountryMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : UnrealExtBan(mname, mbase, c) 615 { 616 } 617 618 bool Matches(User *u, const Entry *e) anope_override 619 { 620 const Anope::string &mask = e->GetMask(); 621 Anope::string real_mask = mask.substr(3); 622 ModData *moddata = u->GetExt<ModData>("ClientModData"); 623 if (moddata == NULL || moddata->find("geoip") == moddata->end()) 624 return false; 625 626 sepstream sep((*moddata)["geoip"], '|');/* "cc=PL|cd=Poland" */ 627 Anope::string tokenbuf; 628 while (sep.GetToken(tokenbuf)) 629 { 630 if (tokenbuf.rfind("cc=", 0) == 0) 631 return (tokenbuf.substr(3, 2) == real_mask); 632 } 633 return false; 634 } 635 }; 636 637 } 638 639 class ChannelModeFlood : public ChannelModeParam 640 { 641 public: 642 ChannelModeFlood(char modeChar, bool minusNoArg) : ChannelModeParam("FLOOD", modeChar, minusNoArg) { } 643 644 /* Borrowed part of this check from UnrealIRCd */ 645 bool IsValid(Anope::string &value) const anope_override 646 { 647 if (value.empty()) 648 return false; 649 try 650 { 651 Anope::string rest; 652 if (value[0] != ':' && convertTo<unsigned>(value[0] == '*' ? value.substr(1) : value, rest, false) > 0 && rest[0] == ':' && rest.length() > 1 && convertTo<unsigned>(rest.substr(1), rest, false) > 0 && rest.empty()) 653 return true; 654 } 655 catch (const ConvertException &) { } 656 657 /* '['<number><1 letter>[optional: '#'+1 letter],[next..]']'':'<number> */ 658 size_t end_bracket = value.find(']', 1); 659 if (end_bracket == Anope::string::npos) 660 return false; 661 Anope::string xbuf = value.substr(0, end_bracket); 662 if (value[end_bracket + 1] != ':') 663 return false; 664 commasepstream args(xbuf.substr(1)); 665 Anope::string arg; 666 while (args.GetToken(arg)) 667 { 668 /* <number><1 letter>[optional: '#'+1 letter] */ 669 size_t p = 0; 670 while (p < arg.length() && isdigit(arg[p])) 671 ++p; 672 if (p == arg.length() || !(arg[p] == 'c' || arg[p] == 'j' || arg[p] == 'k' || arg[p] == 'm' || arg[p] == 'n' || arg[p] == 't')) 673 continue; /* continue instead of break for forward compatibility. */ 674 try 675 { 676 int v = arg.substr(0, p).is_number_only() ? convertTo<int>(arg.substr(0, p)) : 0; 677 if (v < 1 || v > 999) 678 return false; 679 } 680 catch (const ConvertException &) 681 { 682 return false; 683 } 684 } 685 686 return true; 687 } 688 }; 689 690 class ChannelModeHistory : public ChannelModeParam /* stolen from inspircd3's ColonDelimitedParamMode */ 691 { 692 public: 693 ChannelModeHistory(char modeChar) : ChannelModeParam("HISTORY", modeChar, true) { } 694 695 bool IsValid(Anope::string &value) const anope_override 696 { 697 if (value.empty()) 698 return false; // empty param is never valid 699 700 Anope::string::size_type pos = value.find(':'); 701 if ((pos == Anope::string::npos) || (pos == 0)) 702 return false; // no ':' or it's the first char, both are invalid 703 704 Anope::string rest; 705 try 706 { 707 if (convertTo<int>(value, rest, false) <= 0) 708 return false; // negative numbers and zero are invalid 709 710 rest = rest.substr(1); 711 int n; 712 // The part after the ':' is a duration and it 713 // can be in the user friendly "1d3h20m" format, make sure we accept that 714 n = Anope::DoTime(rest); 715 716 if (n <= 0) 717 return false; 718 } 719 catch (const ConvertException &e) 720 { 721 // conversion error, invalid 722 return false; 723 } 724 725 return true; 726 } 727 }; 728 729 class ChannelModeUnrealSSL : public ChannelMode 730 { 731 public: 732 ChannelModeUnrealSSL(const Anope::string &n, char c) : ChannelMode(n, c) 733 { 734 } 735 736 bool CanSet(User *u) const anope_override 737 { 738 return false; 739 } 740 }; 741 742 struct IRCDMessageCapab : Message::Capab 743 { 744 IRCDMessageCapab(Module *creator) : Message::Capab(creator, "PROTOCTL") { } 745 746 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 747 { 748 for (unsigned i = 0; i < params.size(); ++i) 749 { 750 Anope::string capab = params[i]; 751 752 if (capab.find("USERMODES=") != Anope::string::npos) 753 { 754 Anope::string modebuf(capab.begin() + 10, capab.end()); 755 for (size_t t = 0, end = modebuf.length(); t < end; ++t) 756 { 757 switch (modebuf[t]) 758 { 759 case 'B': 760 ModeManager::AddUserMode(new UserMode("BOT", 'B')); 761 continue; 762 case 'G': 763 ModeManager::AddUserMode(new UserMode("CENSOR", 'G')); 764 continue; 765 case 'H': 766 ModeManager::AddUserMode(new UserModeOperOnly("HIDEOPER", 'H')); 767 continue; 768 case 'I': 769 ModeManager::AddUserMode(new UserModeOperOnly("HIDEIDLE", 'I')); 770 continue; 771 case 'R': 772 ModeManager::AddUserMode(new UserMode("REGPRIV", 'R')); 773 continue; 774 case 'S': 775 ModeManager::AddUserMode(new UserModeOperOnly("PROTECTED", 'S')); 776 continue; 777 case 'T': 778 ModeManager::AddUserMode(new UserMode("NOCTCP", 'T')); 779 continue; 780 case 'W': 781 ModeManager::AddUserMode(new UserModeOperOnly("WHOIS", 'W')); 782 continue; 783 case 'd': 784 ModeManager::AddUserMode(new UserMode("DEAF", 'd')); 785 continue; 786 case 'D': 787 ModeManager::AddUserMode(new UserMode("PRIVDEAF", 'D')); 788 continue; 789 case 'i': 790 ModeManager::AddUserMode(new UserMode("INVIS", 'i')); 791 continue; 792 case 'o': 793 ModeManager::AddUserMode(new UserModeOperOnly("OPER", 'o')); 794 continue; 795 case 'p': 796 ModeManager::AddUserMode(new UserMode("PRIV", 'p')); 797 continue; 798 case 'q': 799 ModeManager::AddUserMode(new UserModeOperOnly("GOD", 'q')); 800 continue; 801 case 'r': 802 ModeManager::AddUserMode(new UserModeNoone("REGISTERED", 'r')); 803 continue; 804 case 's': 805 ModeManager::AddUserMode(new UserModeOperOnly("SNOMASK", 's')); 806 continue; 807 case 't': 808 ModeManager::AddUserMode(new UserModeNoone("VHOST", 't')); 809 continue; 810 case 'w': 811 ModeManager::AddUserMode(new UserMode("WALLOPS", 'w')); 812 continue; 813 case 'x': 814 ModeManager::AddUserMode(new UserMode("CLOAK", 'x')); 815 continue; 816 case 'z': 817 ModeManager::AddUserMode(new UserModeNoone("SSL", 'z')); 818 continue; 819 case 'Z': 820 ModeManager::AddUserMode(new UserMode("SSLPRIV", 'Z')); 821 continue; 822 default: 823 ModeManager::AddUserMode(new UserMode("", modebuf[t])); 824 } 825 } 826 } 827 else if (capab.find("CHANMODES=") != Anope::string::npos) 828 { 829 Anope::string modes(capab.begin() + 10, capab.end()); 830 commasepstream sep(modes); 831 Anope::string modebuf; 832 833 sep.GetToken(modebuf); 834 for (size_t t = 0, end = modebuf.length(); t < end; ++t) 835 { 836 switch (modebuf[t]) 837 { 838 case 'b': 839 ModeManager::AddChannelMode(new ChannelModeList("BAN", 'b')); 840 841 ModeManager::AddChannelMode(new UnrealExtban::ChannelMatcher("CHANNELBAN", "BAN", 'c')); 842 ModeManager::AddChannelMode(new UnrealExtban::EntryMatcher("JOINBAN", "BAN", 'j')); 843 ModeManager::AddChannelMode(new UnrealExtban::EntryMatcher("NONICKBAN", "BAN", 'n')); 844 ModeManager::AddChannelMode(new UnrealExtban::EntryMatcher("QUIET", "BAN", 'q')); 845 ModeManager::AddChannelMode(new UnrealExtban::RealnameMatcher("REALNAMEBAN", "BAN", 'r')); 846 ModeManager::AddChannelMode(new UnrealExtban::RegisteredMatcher("REGISTEREDBAN", "BAN", 'R')); 847 ModeManager::AddChannelMode(new UnrealExtban::AccountMatcher("ACCOUNTBAN", "BAN", 'a')); 848 ModeManager::AddChannelMode(new UnrealExtban::FingerprintMatcher("SSLBAN", "BAN", 'S')); 849 ModeManager::AddChannelMode(new UnrealExtban::TimedBanMatcher("TIMEDBAN", "BAN", 't')); 850 ModeManager::AddChannelMode(new UnrealExtban::OperclassMatcher("OPERCLASSBAN", "BAN", 'O')); 851 ModeManager::AddChannelMode(new UnrealExtban::CountryMatcher("COUNTRYBAN", "BAN", 'C')); 852 continue; 853 case 'e': 854 ModeManager::AddChannelMode(new ChannelModeList("EXCEPT", 'e')); 855 continue; 856 case 'I': 857 ModeManager::AddChannelMode(new ChannelModeList("INVITEOVERRIDE", 'I')); 858 continue; 859 default: 860 ModeManager::AddChannelMode(new ChannelModeList("", modebuf[t])); 861 } 862 } 863 864 sep.GetToken(modebuf); 865 for (size_t t = 0, end = modebuf.length(); t < end; ++t) 866 { 867 switch (modebuf[t]) 868 { 869 case 'k': 870 ModeManager::AddChannelMode(new ChannelModeKey('k')); 871 continue; 872 case 'f': 873 ModeManager::AddChannelMode(new ChannelModeFlood('f', false)); 874 continue; 875 case 'L': 876 ModeManager::AddChannelMode(new ChannelModeParam("REDIRECT", 'L')); 877 continue; 878 default: 879 ModeManager::AddChannelMode(new ChannelModeParam("", modebuf[t])); 880 } 881 } 882 883 sep.GetToken(modebuf); 884 for (size_t t = 0, end = modebuf.length(); t < end; ++t) 885 { 886 switch (modebuf[t]) 887 { 888 case 'l': 889 ModeManager::AddChannelMode(new ChannelModeParam("LIMIT", 'l', true)); 890 continue; 891 case 'H': 892 ModeManager::AddChannelMode(new ChannelModeHistory('H')); 893 continue; 894 default: 895 ModeManager::AddChannelMode(new ChannelModeParam("", modebuf[t], true)); 896 } 897 } 898 899 sep.GetToken(modebuf); 900 for (size_t t = 0, end = modebuf.length(); t < end; ++t) 901 { 902 switch (modebuf[t]) 903 { 904 case 'p': 905 ModeManager::AddChannelMode(new ChannelMode("PRIVATE", 'p')); 906 continue; 907 case 's': 908 ModeManager::AddChannelMode(new ChannelMode("SECRET", 's')); 909 continue; 910 case 'm': 911 ModeManager::AddChannelMode(new ChannelMode("MODERATED", 'm')); 912 continue; 913 case 'n': 914 ModeManager::AddChannelMode(new ChannelMode("NOEXTERNAL", 'n')); 915 continue; 916 case 't': 917 ModeManager::AddChannelMode(new ChannelMode("TOPIC", 't')); 918 continue; 919 case 'i': 920 ModeManager::AddChannelMode(new ChannelMode("INVITE", 'i')); 921 continue; 922 case 'r': 923 ModeManager::AddChannelMode(new ChannelModeNoone("REGISTERED", 'r')); 924 continue; 925 case 'R': 926 ModeManager::AddChannelMode(new ChannelMode("REGISTEREDONLY", 'R')); 927 continue; 928 case 'c': 929 ModeManager::AddChannelMode(new ChannelMode("BLOCKCOLOR", 'c')); 930 continue; 931 case 'O': 932 ModeManager::AddChannelMode(new ChannelModeOperOnly("OPERONLY", 'O')); 933 continue; 934 case 'Q': 935 ModeManager::AddChannelMode(new ChannelMode("NOKICK", 'Q')); 936 continue; 937 case 'K': 938 ModeManager::AddChannelMode(new ChannelMode("NOKNOCK", 'K')); 939 continue; 940 case 'V': 941 ModeManager::AddChannelMode(new ChannelMode("NOINVITE", 'V')); 942 continue; 943 case 'C': 944 ModeManager::AddChannelMode(new ChannelMode("NOCTCP", 'C')); 945 continue; 946 case 'z': 947 ModeManager::AddChannelMode(new ChannelMode("SSL", 'z')); 948 continue; 949 case 'N': 950 ModeManager::AddChannelMode(new ChannelMode("NONICK", 'N')); 951 continue; 952 case 'S': 953 ModeManager::AddChannelMode(new ChannelMode("STRIPCOLOR", 'S')); 954 continue; 955 case 'M': 956 ModeManager::AddChannelMode(new ChannelMode("REGMODERATED", 'M')); 957 continue; 958 case 'T': 959 ModeManager::AddChannelMode(new ChannelMode("NONOTICE", 'T')); 960 continue; 961 case 'G': 962 ModeManager::AddChannelMode(new ChannelMode("CENSOR", 'G')); 963 continue; 964 case 'Z': 965 ModeManager::AddChannelMode(new ChannelModeUnrealSSL("ALLSSL", 'Z')); 966 continue; 967 case 'd': 968 // post delayed. means that channel is -D but invisible users still exist. 969 continue; 970 case 'D': 971 ModeManager::AddChannelMode(new ChannelMode("DELAYEDJOIN", 'D')); 972 continue; 973 case 'P': 974 ModeManager::AddChannelMode(new ChannelModeOperOnly("PERM", 'P')); 975 continue; 976 default: 977 ModeManager::AddChannelMode(new ChannelMode("", modebuf[t])); 978 } 979 } 980 } 981 else if (!capab.find("SID=")) 982 { 983 UplinkSID = capab.substr(4); 984 } 985 else if (!capab.find("PREFIX=")) /* PREFIX=(qaohv)~&@%+ */ 986 { 987 Anope::string modes(capab.begin() + 7, capab.end()); 988 reverse(modes.begin(), modes.end()); /* +%@&!)vhoaq( */ 989 std::size_t mode_count = modes.find(')'); 990 Anope::string mode_prefixes = modes.substr(0, mode_count); 991 Anope::string mode_chars = modes.substr(mode_count+1, mode_count); 992 993 for (size_t t = 0, end = mode_chars.length(); t < end; ++t) 994 { 995 Anope::string mode_name; 996 switch (mode_chars[t]) 997 { 998 999 case 'v': 1000 mode_name = "VOICE"; 1001 break; 1002 case 'h': 1003 mode_name = "HALFOP"; 1004 break; 1005 case 'o': 1006 mode_name = "OP"; 1007 break; 1008 case 'a': 1009 mode_name = "PROTECT"; 1010 break; 1011 case 'q': 1012 mode_name = "OWNER"; 1013 break; 1014 default: 1015 mode_name = ""; 1016 break; 1017 } 1018 ModeManager::AddChannelMode(new ChannelModeStatus(mode_name, mode_chars[t], mode_prefixes[t], t)); 1019 } 1020 } 1021 } 1022 1023 Message::Capab::Run(source, params); 1024 } 1025 }; 1026 1027 struct IRCDMessageChgHost : IRCDMessage 1028 { 1029 IRCDMessageChgHost(Module *creator) : IRCDMessage(creator, "CHGHOST", 2) { } 1030 1031 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1032 { 1033 User *u = User::Find(params[0]); 1034 if (u) 1035 u->SetDisplayedHost(params[1]); 1036 } 1037 }; 1038 1039 struct IRCDMessageChgIdent : IRCDMessage 1040 { 1041 IRCDMessageChgIdent(Module *creator) : IRCDMessage(creator, "CHGIDENT", 2) { } 1042 1043 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1044 { 1045 User *u = User::Find(params[0]); 1046 if (u) 1047 u->SetVIdent(params[1]); 1048 } 1049 }; 1050 1051 struct IRCDMessageChgName : IRCDMessage 1052 { 1053 IRCDMessageChgName(Module *creator) : IRCDMessage(creator, "CHGNAME", 2) { } 1054 1055 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1056 { 1057 User *u = User::Find(params[0]); 1058 if (u) 1059 u->SetRealname(params[1]); 1060 } 1061 }; 1062 1063 struct IRCDMessageMD : IRCDMessage 1064 { 1065 PrimitiveExtensibleItem<ModData> &ClientModData; 1066 PrimitiveExtensibleItem<ModData> &ChannelModData; 1067 1068 IRCDMessageMD(Module *creator, PrimitiveExtensibleItem<ModData> &clmoddata, PrimitiveExtensibleItem<ModData> &chmoddata) : IRCDMessage(creator, "MD", 3), ClientModData(clmoddata), ChannelModData(chmoddata) 1069 { 1070 SetFlag(IRCDMESSAGE_SOFT_LIMIT); 1071 } 1072 1073 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1074 { 1075 const Anope::string &mdtype = params[0], 1076 &obj = params[1], 1077 &var = params[2], 1078 &value = params.size() > 3 ? params[3] : ""; 1079 1080 if (mdtype == "client") /* can be a server too! */ 1081 { 1082 User *u = User::Find(obj); 1083 1084 if (u == NULL) 1085 return; 1086 1087 ModData &clientmd = *ClientModData.Require(u); 1088 1089 if (value.empty()) 1090 { 1091 clientmd.erase(var); 1092 Log(LOG_DEBUG) << "Erased client moddata " << var << " from " << u->nick; 1093 } 1094 else 1095 { 1096 clientmd[var] = value; 1097 Log(LOG_DEBUG) << "Set client moddata " << var << "=\"" << value << "\" to " << u->nick; 1098 } 1099 if (var == "certfp" && !value.empty()) 1100 { 1101 u->Extend<bool>("ssl"); 1102 u->fingerprint = value; 1103 FOREACH_MOD(OnFingerprint, (u)); 1104 } 1105 } 1106 else if (mdtype == "channel") 1107 { 1108 Channel *c = Channel::Find(obj); 1109 1110 if (c == NULL) 1111 return; 1112 1113 ModData &channelmd = *ChannelModData.Require(c); 1114 1115 if (value.empty()) 1116 { 1117 channelmd.erase(var); 1118 Log(LOG_DEBUG) << "Erased channel moddata " << var << " from " << c->name; 1119 } 1120 else 1121 { 1122 channelmd[var] = value; 1123 Log(LOG_DEBUG) << "Set channel moddata " << var << "=\"" << value << "\" to " << c->name; 1124 } 1125 } 1126 } 1127 }; 1128 1129 struct IRCDMessageMode : IRCDMessage 1130 { 1131 IRCDMessageMode(Module *creator, const Anope::string &mname) : IRCDMessage(creator, mname, 2) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); } 1132 1133 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1134 { 1135 bool server_source = source.GetServer() != NULL; 1136 Anope::string modes = params[1]; 1137 for (unsigned i = 2; i < params.size() - (server_source ? 1 : 0); ++i) 1138 modes += " " + params[i]; 1139 1140 if (IRCD->IsChannelValid(params[0])) 1141 { 1142 Channel *c = Channel::Find(params[0]); 1143 time_t ts = 0; 1144 1145 try 1146 { 1147 if (server_source) 1148 ts = convertTo<time_t>(params[params.size() - 1]); 1149 } 1150 catch (const ConvertException &) { } 1151 1152 if (c) 1153 c->SetModesInternal(source, modes, ts); 1154 } 1155 else 1156 { 1157 User *u = User::Find(params[0]); 1158 if (u) 1159 u->SetModesInternal(source, "%s", params[1].c_str()); 1160 } 1161 } 1162 }; 1163 1164 /* netinfo 1165 * argv[0] = max global count 1166 * argv[1] = time of end sync 1167 * argv[2] = unreal protocol using (numeric) 1168 * argv[3] = cloak-crc (> u2302) 1169 * argv[4] = free(**) 1170 * argv[5] = free(**) 1171 * argv[6] = free(**) 1172 * argv[7] = ircnet 1173 */ 1174 struct IRCDMessageNetInfo : IRCDMessage 1175 { 1176 IRCDMessageNetInfo(Module *creator) : IRCDMessage(creator, "NETINFO", 8) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); } 1177 1178 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1179 { 1180 UplinkSocket::Message() << "NETINFO " << MaxUserCount << " " << Anope::CurTime << " " << convertTo<int>(params[2]) << " " << params[3] << " 0 0 0 :" << params[7]; 1181 } 1182 }; 1183 1184 struct IRCDMessageNick : IRCDMessage 1185 { 1186 IRCDMessageNick(Module *creator) : IRCDMessage(creator, "NICK", 2) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); } 1187 1188 /* 1189 ** NICK - new 1190 ** source = NULL 1191 ** parv[0] = nickname 1192 ** parv[1] = hopcount 1193 ** parv[2] = timestamp 1194 ** parv[3] = username 1195 ** parv[4] = hostname 1196 ** parv[5] = servername 1197 ** parv[6] = servicestamp 1198 ** parv[7] = umodes 1199 ** parv[8] = virthost, * if none 1200 ** parv[9] = ip 1201 ** parv[10] = info 1202 ** 1203 ** NICK - change 1204 ** source = oldnick 1205 ** parv[0] = new nickname 1206 ** parv[1] = hopcount 1207 */ 1208 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1209 { 1210 if (params.size() == 11) 1211 { 1212 Anope::string ip; 1213 if (params[9] != "*") 1214 { 1215 Anope::string decoded_ip; 1216 Anope::B64Decode(params[9], decoded_ip); 1217 1218 sockaddrs ip_addr; 1219 ip_addr.ntop(params[9].length() == 8 ? AF_INET : AF_INET6, decoded_ip.c_str()); 1220 ip = ip_addr.addr(); 1221 } 1222 1223 Anope::string vhost = params[8]; 1224 if (vhost.equals_cs("*")) 1225 vhost.clear(); 1226 1227 time_t user_ts = params[2].is_pos_number_only() ? convertTo<time_t>(params[2]) : Anope::CurTime; 1228 1229 Server *s = Server::Find(params[5]); 1230 if (s == NULL) 1231 { 1232 Log(LOG_DEBUG) << "User " << params[0] << " introduced from nonexistent server " << params[5] << "?"; 1233 return; 1234 } 1235 1236 NickAlias *na = NULL; 1237 1238 if (params[6] == "0") 1239 ; 1240 else if (params[6].is_pos_number_only()) 1241 { 1242 if (convertTo<time_t>(params[6]) == user_ts) 1243 na = NickAlias::Find(params[0]); 1244 } 1245 else 1246 { 1247 na = NickAlias::Find(params[6]); 1248 } 1249 1250 User::OnIntroduce(params[0], params[3], params[4], vhost, ip, s, params[10], user_ts, params[7], "", na ? *na->nc : NULL); 1251 } 1252 else 1253 { 1254 User *u = source.GetUser(); 1255 if (u) 1256 u->ChangeNick(params[0]); 1257 } 1258 } 1259 }; 1260 1261 /** This is here because: 1262 * 1263 * If we had three servers, A, B & C linked like so: A<->B<->C 1264 * If Anope is linked to A and B splits from A and then reconnects 1265 * B introduces itself, introduces C, sends EOS for C, introduces Bs clients 1266 * introduces Cs clients, sends EOS for B. This causes all of Cs clients to be introduced 1267 * with their server "not syncing". We now send a PING immediately when receiving a new server 1268 * and then finish sync once we get a pong back from that server. 1269 */ 1270 struct IRCDMessagePong : IRCDMessage 1271 { 1272 IRCDMessagePong(Module *creator) : IRCDMessage(creator, "PONG", 0) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); SetFlag(IRCDMESSAGE_REQUIRE_SERVER); } 1273 1274 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1275 { 1276 if (!source.GetServer()->IsSynced()) 1277 source.GetServer()->Sync(false); 1278 } 1279 }; 1280 1281 struct IRCDMessageSASL : IRCDMessage 1282 { 1283 IRCDMessageSASL(Module *creator) : IRCDMessage(creator, "SASL", 4) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); SetFlag(IRCDMESSAGE_REQUIRE_SERVER); } 1284 1285 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1286 { 1287 if (!SASL::sasl) 1288 return; 1289 1290 SASL::Message m; 1291 m.source = params[1]; 1292 m.target = params[0]; 1293 m.type = params[2]; 1294 m.data = params[3]; 1295 m.ext = params.size() > 4 ? params[4] : ""; 1296 1297 SASL::sasl->ProcessMessage(m); 1298 } 1299 }; 1300 1301 struct IRCDMessageSDesc : IRCDMessage 1302 { 1303 IRCDMessageSDesc(Module *creator) : IRCDMessage(creator, "SDESC", 1) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); } 1304 1305 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1306 { 1307 source.GetServer()->SetDescription(params[0]); 1308 } 1309 }; 1310 1311 struct IRCDMessageSetHost : IRCDMessage 1312 { 1313 IRCDMessageSetHost(Module *creator) : IRCDMessage(creator, "SETHOST", 1) { SetFlag(IRCDMESSAGE_REQUIRE_USER); } 1314 1315 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1316 { 1317 User *u = source.GetUser(); 1318 1319 /* When a user sets +x we receive the new host and then the mode change */ 1320 if (u->HasMode("CLOAK")) 1321 u->SetDisplayedHost(params[0]); 1322 else 1323 u->SetCloakedHost(params[0]); 1324 } 1325 }; 1326 1327 struct IRCDMessageSetIdent : IRCDMessage 1328 { 1329 IRCDMessageSetIdent(Module *creator) : IRCDMessage(creator, "SETIDENT", 1) { SetFlag(IRCDMESSAGE_REQUIRE_USER); } 1330 1331 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1332 { 1333 User *u = source.GetUser(); 1334 u->SetVIdent(params[0]); 1335 } 1336 }; 1337 1338 struct IRCDMessageSetName : IRCDMessage 1339 { 1340 IRCDMessageSetName(Module *creator) : IRCDMessage(creator, "SETNAME", 1) { SetFlag(IRCDMESSAGE_REQUIRE_USER); } 1341 1342 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1343 { 1344 User *u = source.GetUser(); 1345 u->SetRealname(params[0]); 1346 } 1347 }; 1348 1349 struct IRCDMessageServer : IRCDMessage 1350 { 1351 IRCDMessageServer(Module *creator) : IRCDMessage(creator, "SERVER", 3) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); } 1352 1353 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1354 { 1355 unsigned int hops = Anope::string(params[1]).is_pos_number_only() ? convertTo<unsigned>(params[1]) : 0; 1356 1357 if (params[1].equals_cs("1")) 1358 { 1359 Anope::string desc; 1360 spacesepstream(params[2]).GetTokenRemainder(desc, 1); 1361 1362 new Server(source.GetServer() == NULL ? Me : source.GetServer(), params[0], hops, desc, UplinkSID); 1363 } 1364 else 1365 new Server(source.GetServer(), params[0], hops, params[2]); 1366 1367 IRCD->SendPing(Me->GetName(), params[0]); 1368 } 1369 }; 1370 1371 struct IRCDMessageSID : IRCDMessage 1372 { 1373 IRCDMessageSID(Module *creator) : IRCDMessage(creator, "SID", 4) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); } 1374 1375 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1376 { 1377 unsigned int hops = Anope::string(params[1]).is_pos_number_only() ? convertTo<unsigned>(params[1]) : 0; 1378 1379 new Server(source.GetServer(), params[0], hops, params[3], params[2]); 1380 1381 IRCD->SendPing(Me->GetName(), params[0]); 1382 } 1383 }; 1384 1385 static char UnrealSjoinPrefixToModeChar(char sjoin_prefix) 1386 { 1387 switch(sjoin_prefix) 1388 { 1389 case '*': 1390 return ModeManager::GetStatusChar('~'); 1391 case '~': 1392 return ModeManager::GetStatusChar('&'); 1393 default: 1394 return ModeManager::GetStatusChar(sjoin_prefix); /* remaining are regular */ 1395 } 1396 } 1397 1398 struct IRCDMessageSJoin : IRCDMessage 1399 { 1400 IRCDMessageSJoin(Module *creator) : IRCDMessage(creator, "SJOIN", 3) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); SetFlag(IRCDMESSAGE_SOFT_LIMIT); } 1401 1402 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1403 { 1404 Anope::string modes; 1405 if (params.size() >= 4) 1406 for (unsigned i = 2; i < params.size() - 1; ++i) 1407 modes += " " + params[i]; 1408 if (!modes.empty()) 1409 modes.erase(modes.begin()); 1410 1411 std::list<Anope::string> bans, excepts, invites; 1412 std::list<Message::Join::SJoinUser> users; 1413 1414 spacesepstream sep(params[params.size() - 1]); 1415 Anope::string buf; 1416 while (sep.GetToken(buf)) 1417 { 1418 /* Ban */ 1419 if (buf[0] == '&') 1420 { 1421 buf.erase(buf.begin()); 1422 bans.push_back(buf); 1423 } 1424 /* Except */ 1425 else if (buf[0] == '"') 1426 { 1427 buf.erase(buf.begin()); 1428 excepts.push_back(buf); 1429 } 1430 /* Invex */ 1431 else if (buf[0] == '\'') 1432 { 1433 buf.erase(buf.begin()); 1434 invites.push_back(buf); 1435 } 1436 else 1437 { 1438 Message::Join::SJoinUser sju; 1439 1440 /* Get prefixes from the nick */ 1441 for (char ch; (ch = UnrealSjoinPrefixToModeChar(buf[0]));) 1442 { 1443 sju.first.AddMode(ch); 1444 buf.erase(buf.begin()); 1445 } 1446 1447 sju.second = User::Find(buf); 1448 if (!sju.second) 1449 { 1450 Log(LOG_DEBUG) << "SJOIN for nonexistent user " << buf << " on " << params[1]; 1451 continue; 1452 } 1453 1454 users.push_back(sju); 1455 } 1456 } 1457 1458 time_t ts = Anope::string(params[0]).is_pos_number_only() ? convertTo<time_t>(params[0]) : Anope::CurTime; 1459 Message::Join::SJoin(source, params[1], ts, modes, users); 1460 1461 if (!bans.empty() || !excepts.empty() || !invites.empty()) 1462 { 1463 Channel *c = Channel::Find(params[1]); 1464 1465 if (!c || c->creation_time != ts) 1466 return; 1467 1468 ChannelMode *ban = ModeManager::FindChannelModeByName("BAN"), 1469 *except = ModeManager::FindChannelModeByName("EXCEPT"), 1470 *invex = ModeManager::FindChannelModeByName("INVITEOVERRIDE"); 1471 1472 if (ban) 1473 for (std::list<Anope::string>::iterator it = bans.begin(), it_end = bans.end(); it != it_end; ++it) 1474 c->SetModeInternal(source, ban, *it); 1475 if (except) 1476 for (std::list<Anope::string>::iterator it = excepts.begin(), it_end = excepts.end(); it != it_end; ++it) 1477 c->SetModeInternal(source, except, *it); 1478 if (invex) 1479 for (std::list<Anope::string>::iterator it = invites.begin(), it_end = invites.end(); it != it_end; ++it) 1480 c->SetModeInternal(source, invex, *it); 1481 } 1482 } 1483 }; 1484 1485 struct IRCDMessageTopic : IRCDMessage 1486 { 1487 IRCDMessageTopic(Module *creator) : IRCDMessage(creator, "TOPIC", 4) { } 1488 1489 /* 1490 ** source = sender prefix 1491 ** parv[0] = channel name 1492 ** parv[1] = topic nickname 1493 ** parv[2] = topic time 1494 ** parv[3] = topic text 1495 */ 1496 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1497 { 1498 Channel *c = Channel::Find(params[0]); 1499 if (c) 1500 c->ChangeTopicInternal(source.GetUser(), params[1], params[3], Anope::string(params[2]).is_pos_number_only() ? convertTo<time_t>(params[2]) : Anope::CurTime); 1501 } 1502 }; 1503 1504 /* 1505 * parv[0] = nickname 1506 * parv[1] = hopcount 1507 * parv[2] = timestamp 1508 * parv[3] = username 1509 * parv[4] = hostname 1510 * parv[5] = UID 1511 * parv[6] = servicestamp 1512 * parv[7] = umodes 1513 * parv[8] = virthost, * if none 1514 * parv[9] = cloaked host, * if none 1515 * parv[10] = ip 1516 * parv[11] = info 1517 */ 1518 struct IRCDMessageUID : IRCDMessage 1519 { 1520 IRCDMessageUID(Module *creator) : IRCDMessage(creator, "UID", 12) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); } 1521 1522 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1523 { 1524 Anope::string 1525 nickname = params[0], 1526 hopcount = params[1], 1527 timestamp = params[2], 1528 username = params[3], 1529 hostname = params[4], 1530 uid = params[5], 1531 account = params[6], 1532 umodes = params[7], 1533 vhost = params[8], 1534 chost = params[9], 1535 ip = params[10], 1536 info = params[11]; 1537 1538 if (ip != "*") 1539 { 1540 Anope::string decoded_ip; 1541 Anope::B64Decode(ip, decoded_ip); 1542 1543 sockaddrs ip_addr; 1544 ip_addr.ntop(ip.length() == 8 ? AF_INET : AF_INET6, decoded_ip.c_str()); 1545 ip = ip_addr.addr(); 1546 } 1547 1548 if (vhost == "*") 1549 vhost.clear(); 1550 1551 if (chost == "*") 1552 chost.clear(); 1553 1554 time_t user_ts; 1555 try 1556 { 1557 user_ts = convertTo<time_t>(timestamp); 1558 } 1559 catch (const ConvertException &) 1560 { 1561 user_ts = Anope::CurTime; 1562 } 1563 1564 NickAlias *na = NULL; 1565 1566 if (account == "0") 1567 { 1568 ; 1569 } 1570 else if (account.is_pos_number_only()) 1571 { 1572 if (convertTo<time_t>(account) == user_ts) 1573 na = NickAlias::Find(nickname); 1574 } 1575 else 1576 { 1577 na = NickAlias::Find(account); 1578 } 1579 1580 User *u = User::OnIntroduce(nickname, username, hostname, vhost, ip, source.GetServer(), info, user_ts, umodes, uid, na ? *na->nc : NULL); 1581 1582 if (u && !chost.empty() && chost != u->GetCloakedHost()) 1583 u->SetCloakedHost(chost); 1584 } 1585 }; 1586 1587 struct IRCDMessageUmode2 : IRCDMessage 1588 { 1589 IRCDMessageUmode2(Module *creator) : IRCDMessage(creator, "UMODE2", 1) { SetFlag(IRCDMESSAGE_REQUIRE_USER); } 1590 1591 void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override 1592 { 1593 source.GetUser()->SetModesInternal(source, "%s", params[0].c_str()); 1594 } 1595 }; 1596 1597 class ProtoUnreal : public Module 1598 { 1599 UnrealIRCdProto ircd_proto; 1600 1601 /* Core message handlers */ 1602 Message::Away message_away; 1603 Message::Error message_error; 1604 Message::Invite message_invite; 1605 Message::Join message_join; 1606 Message::Kick message_kick; 1607 Message::Kill message_kill, message_svskill; 1608 Message::MOTD message_motd; 1609 Message::Notice message_notice; 1610 Message::Part message_part; 1611 Message::Ping message_ping; 1612 Message::Privmsg message_privmsg; 1613 Message::Quit message_quit; 1614 Message::SQuit message_squit; 1615 Message::Stats message_stats; 1616 Message::Time message_time; 1617 Message::Version message_version; 1618 Message::Whois message_whois; 1619 1620 /* Our message handlers */ 1621 IRCDMessageCapab message_capab; 1622 IRCDMessageChgHost message_chghost; 1623 IRCDMessageChgIdent message_chgident; 1624 IRCDMessageChgName message_chgname; 1625 IRCDMessageMD message_md; 1626 IRCDMessageMode message_mode, message_svsmode, message_svs2mode; 1627 IRCDMessageNetInfo message_netinfo; 1628 IRCDMessageNick message_nick; 1629 IRCDMessagePong message_pong; 1630 IRCDMessageSASL message_sasl; 1631 IRCDMessageSDesc message_sdesc; 1632 IRCDMessageSetHost message_sethost; 1633 IRCDMessageSetIdent message_setident; 1634 IRCDMessageSetName message_setname; 1635 IRCDMessageServer message_server; 1636 IRCDMessageSID message_sid; 1637 IRCDMessageSJoin message_sjoin; 1638 IRCDMessageTopic message_topic; 1639 IRCDMessageUID message_uid; 1640 IRCDMessageUmode2 message_umode2; 1641 1642 bool use_server_side_mlock; 1643 1644 public: 1645 ProtoUnreal(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, PROTOCOL | VENDOR), 1646 ircd_proto(this), 1647 message_away(this), message_error(this), message_invite(this), message_join(this), message_kick(this), 1648 message_kill(this), message_svskill(this, "SVSKILL"), message_motd(this), message_notice(this), message_part(this), message_ping(this), 1649 message_privmsg(this), message_quit(this), message_squit(this), message_stats(this), message_time(this), 1650 message_version(this), message_whois(this), 1651 1652 message_capab(this), message_chghost(this), message_chgident(this), message_chgname(this), 1653 message_md(this, ircd_proto.ClientModData, ircd_proto.ChannelModData),message_mode(this, "MODE"), 1654 message_svsmode(this, "SVSMODE"), message_svs2mode(this, "SVS2MODE"), message_netinfo(this), message_nick(this), message_pong(this), 1655 message_sasl(this), message_sdesc(this), message_sethost(this), message_setident(this), message_setname(this), message_server(this), 1656 message_sid(this), message_sjoin(this), message_topic(this), message_uid(this), message_umode2(this) 1657 { 1658 1659 } 1660 1661 void Prioritize() anope_override 1662 { 1663 ModuleManager::SetPriority(this, PRIORITY_FIRST); 1664 } 1665 1666 void OnReload(Configuration::Conf *conf) anope_override 1667 { 1668 use_server_side_mlock = conf->GetModule(this)->Get<bool>("use_server_side_mlock"); 1669 } 1670 1671 void OnUserNickChange(User *u, const Anope::string &) anope_override 1672 { 1673 u->RemoveModeInternal(Me, ModeManager::FindUserModeByName("REGISTERED")); 1674 if (Servers::Capab.count("ESVID") == 0) 1675 IRCD->SendLogout(u); 1676 } 1677 1678 void OnChannelSync(Channel *c) anope_override 1679 { 1680 if (!c->ci) 1681 return; 1682 1683 ModeLocks *modelocks = c->ci->GetExt<ModeLocks>("modelocks"); 1684 if (use_server_side_mlock && Servers::Capab.count("MLOCK") > 0 && modelocks) 1685 { 1686 Anope::string modes = modelocks->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", ""); 1687 UplinkSocket::Message(Me) << "MLOCK " << static_cast<long>(c->creation_time) << " " << c->ci->name << " " << modes; 1688 } 1689 } 1690 1691 void OnChanRegistered(ChannelInfo *ci) anope_override 1692 { 1693 ModeLocks *modelocks = ci->GetExt<ModeLocks>("modelocks"); 1694 if (!ci->c || !use_server_side_mlock || !modelocks || !Servers::Capab.count("MLOCK")) 1695 return; 1696 Anope::string modes = modelocks->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", ""); 1697 UplinkSocket::Message(Me) << "MLOCK " << static_cast<long>(ci->c->creation_time) << " " << ci->name << " " << modes; 1698 } 1699 1700 void OnDelChan(ChannelInfo *ci) anope_override 1701 { 1702 if (!ci->c || !use_server_side_mlock || !Servers::Capab.count("MLOCK")) 1703 return; 1704 UplinkSocket::Message(Me) << "MLOCK " << static_cast<long>(ci->c->creation_time) << " " << ci->name << " :"; 1705 } 1706 1707 EventReturn OnMLock(ChannelInfo *ci, ModeLock *lock) anope_override 1708 { 1709 ModeLocks *modelocks = ci->GetExt<ModeLocks>("modelocks"); 1710 ChannelMode *cm = ModeManager::FindChannelModeByName(lock->name); 1711 if (use_server_side_mlock && cm && modelocks && ci->c && (cm->type == MODE_REGULAR || cm->type == MODE_PARAM) && Servers::Capab.count("MLOCK") > 0) 1712 { 1713 Anope::string modes = modelocks->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", "") + cm->mchar; 1714 UplinkSocket::Message(Me) << "MLOCK " << static_cast<long>(ci->c->creation_time) << " " << ci->name << " " << modes; 1715 } 1716 1717 return EVENT_CONTINUE; 1718 } 1719 1720 EventReturn OnUnMLock(ChannelInfo *ci, ModeLock *lock) anope_override 1721 { 1722 ModeLocks *modelocks = ci->GetExt<ModeLocks>("modelocks"); 1723 ChannelMode *cm = ModeManager::FindChannelModeByName(lock->name); 1724 if (use_server_side_mlock && cm && modelocks && ci->c && (cm->type == MODE_REGULAR || cm->type == MODE_PARAM) && Servers::Capab.count("MLOCK") > 0) 1725 { 1726 Anope::string modes = modelocks->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", "").replace_all_cs(cm->mchar, ""); 1727 UplinkSocket::Message(Me) << "MLOCK " << static_cast<long>(ci->c->creation_time) << " " << ci->name << " " << modes; 1728 } 1729 1730 return EVENT_CONTINUE; 1731 } 1732 1733 void OnChannelUnban(User *u, ChannelInfo *ci) anope_override 1734 { 1735 UplinkSocket::Message(ci->WhoSends()) << "SVS2MODE " << ci->c->name << " -b " << u->GetUID(); 1736 /* Unreal will remove all matching bans for us regardless of our internal matching. 1737 Don't use Message(Me) here as certain Unreal versions will always respond with TS-less MODE message. */ 1738 } 1739 }; 1740 1741 MODULE_INIT(ProtoUnreal)