ns_cert.cpp

Go to the documentation of this file.
00001 /* NickServ core functions
00002  *
00003  * (C) 2003-2013 Anope Team
00004  * Contact us at team@anope.org
00005  *
00006  * Please read COPYING and README for further details.
00007  *
00008  * Based on the original code of Epona by Lara.
00009  * Based on the original code of Services by Andy Church.
00010  */
00011 
00012 /*************************************************************************/
00013 
00014 #include "module.h"
00015 
00016 class CommandNSCert : public Command
00017 {
00018  private:
00019         void DoServAdminList(CommandSource &source, const NickCore *nc)
00020         {
00021                 if (nc->cert.empty())
00022                 {
00023                         source.Reply(_("Certificate list for \002%s\002 is empty."), nc->display.c_str());
00024                         return;
00025                 }
00026 
00027                 if (nc->HasExt("SUSPENDED"))
00028                 {
00029                         source.Reply(NICK_X_SUSPENDED, nc->display.c_str());
00030                         return;
00031                 }
00032 
00033                 ListFormatter list;
00034                 list.AddColumn("Certificate");
00035 
00036                 for (unsigned i = 0, end = nc->cert.size(); i < end; ++i)
00037                 {
00038                         Anope::string fingerprint = nc->GetCert(i);
00039                         ListFormatter::ListEntry entry;
00040                         entry["Certificate"] = fingerprint;
00041                         list.AddEntry(entry);
00042                 }
00043 
00044                 source.Reply(_("Certificate list for \002%s\002:"), nc->display.c_str());
00045 
00046                 std::vector<Anope::string> replies;
00047                 list.Process(replies);
00048                 for (unsigned i = 0; i < replies.size(); ++i)
00049                         source.Reply(replies[i]);
00050 
00051                 return;
00052         }
00053 
00054         void DoAdd(CommandSource &source, NickCore *nc, const Anope::string &mask)
00055         {
00056 
00057                 if (nc->cert.size() >= Config->NSAccessMax)
00058                 {
00059                         source.Reply(_("Sorry, you can only have %d certificate entries for a nickname."), Config->NSAccessMax);
00060                         return;
00061                 }
00062 
00063                 if (source.GetUser() && !source.GetUser()->fingerprint.empty() && !nc->FindCert(source.GetUser()->fingerprint))
00064                 {
00065                         nc->AddCert(source.GetUser()->fingerprint);
00066                         source.Reply(_("\002%s\002 added to your certificate list."), source.GetUser()->fingerprint.c_str());
00067                         return;
00068                 }
00069 
00070                 if (mask.empty())
00071                 {
00072                         this->OnSyntaxError(source, "ADD");
00073                         return;
00074                 }
00075 
00076                 if (nc->FindCert(mask))
00077                 {
00078                         source.Reply(_("Fingerprint \002%s\002 already present on your certificate list."), mask.c_str());
00079                         return;
00080                 }
00081 
00082                 nc->AddCert(mask);
00083                 source.Reply(_("\002%s\002 added to your certificate list."), mask.c_str());
00084                 return;
00085         }
00086 
00087         void DoDel(CommandSource &source, NickCore *nc, const Anope::string &mask)
00088         {
00089                 if (source.GetUser() && !source.GetUser()->fingerprint.empty() && nc->FindCert(source.GetUser()->fingerprint))
00090                 {
00091                         nc->EraseCert(source.GetUser()->fingerprint);
00092                         source.Reply(_("\002%s\002 deleted from your certificate list."), source.GetUser()->fingerprint.c_str());
00093                         return;
00094                 }
00095 
00096                 if (mask.empty())
00097                 {
00098                         this->OnSyntaxError(source, "DEL");
00099                         return;
00100                 }
00101 
00102                 if (!nc->FindCert(mask))
00103                 {
00104                         source.Reply(_("\002%s\002 not found on your certificate list."), mask.c_str());
00105                         return;
00106                 }
00107 
00108                 source.Reply(_("\002%s\002 deleted from your certificate list."), mask.c_str());
00109                 nc->EraseCert(mask);
00110 
00111                 return;
00112         }
00113 
00114         void DoList(CommandSource &source, const NickCore *nc)
00115         {
00116 
00117                 if (nc->cert.empty())
00118                 {
00119                         source.Reply(_("Your certificate list is empty."));
00120                         return;
00121                 }
00122 
00123                 ListFormatter list;
00124                 list.AddColumn("Certificate");
00125 
00126                 for (unsigned i = 0, end = nc->cert.size(); i < end; ++i)
00127                 {
00128                         ListFormatter::ListEntry entry;
00129                         entry["Certificate"] = nc->GetCert(i);
00130                         list.AddEntry(entry);
00131                 }
00132 
00133                 source.Reply(_("Certificate list:"));
00134                 std::vector<Anope::string> replies;
00135                 list.Process(replies);
00136                 for (unsigned i = 0; i < replies.size(); ++i)
00137                         source.Reply(replies[i]);
00138         }
00139 
00140  public:
00141         CommandNSCert(Module *creator) : Command(creator, "nickserv/cert", 1, 2)
00142         {
00143                 this->SetDesc("Modify the nickname client certificate list");
00144                 this->SetSyntax("ADD \037fingerprint\037");
00145                 this->SetSyntax("DEL \037fingerprint\037");
00146                 this->SetSyntax("LIST");
00147         }
00148 
00149         void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
00150         {
00151                 const Anope::string &cmd = params[0];
00152                 const Anope::string &mask = params.size() > 1 ? params[1] : "";
00153 
00154                 const NickAlias *na;
00155                 if (cmd.equals_ci("LIST") && source.IsServicesOper() && !mask.empty() && (na = NickAlias::Find(mask)))
00156                         return this->DoServAdminList(source, na->nc);
00157 
00158                 NickCore *nc = source.nc;
00159 
00160                 if (source.nc->HasExt("SUSPENDED"))
00161                         source.Reply(NICK_X_SUSPENDED, source.nc->display.c_str());
00162                 else if (cmd.equals_ci("ADD"))
00163                         return this->DoAdd(source, nc, mask);
00164                 else if (cmd.equals_ci("DEL"))
00165                         return this->DoDel(source, nc, mask);
00166                 else if (cmd.equals_ci("LIST"))
00167                         return this->DoList(source, nc);
00168                 else
00169                         this->OnSyntaxError(source, cmd);
00170 
00171                 return;
00172         }
00173 
00174         bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
00175         {
00176                 this->SendSyntax(source);
00177                 source.Reply(" ");
00178                 source.Reply(_("Modifies or displays the certificate list for your nick.\n"
00179                                 "If you connect to IRC and provide a client certificate with a\n"
00180                                 "matching fingerprint in the cert list, your nick will be\n"
00181                                 "automatically identified to %s.\n"
00182                                 " \n"), Config->NickServ.c_str(), Config->NickServ.c_str());
00183                 source.Reply(_("Examples:\n"
00184                                 " \n"
00185                                 "    \002CERT ADD <fingerprint>\002\n"
00186                                 "        Adds this fingerprint to the certificate list and\n"
00187                                 "        automatically identifies you when you connect to IRC\n"
00188                                 "        using this certificate.\n"
00189                                 " \n"
00190                                 "    \002CERT DEL <fingerprint>\002\n"
00191                                 "        Reverses the previous command.\n"
00192                                 " \n"
00193                                 "    \002CERT LIST\002\n"
00194                                 "        Displays the current certificate list."), Config->NickServ.c_str());
00195                 return true;
00196         }
00197 };
00198 
00199 class NSCert : public Module
00200 {
00201         CommandNSCert commandnscert;
00202 
00203         void DoAutoIdentify(User *u)
00204         {
00205                 NickAlias *na = NickAlias::Find(u->nick);
00206                 if (!NickServ || !na)
00207                         return;
00208                 if (u->IsIdentified() && u->Account() == na->nc)
00209                         return;
00210                 if (na->nc->HasExt("SUSPENDED"))
00211                         return;
00212                 if (!na->nc->FindCert(u->fingerprint))
00213                         return;
00214 
00215                 u->Identify(na);
00216                 u->SendMessage(NickServ, _("SSL Fingerprint accepted. You are now identified."));
00217                 Log(u) << "automatically identified for account " << na->nc->display << " using a valid SSL fingerprint";
00218                 return;
00219         }
00220 
00221  public:
00222         NSCert(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, CORE),
00223                 commandnscert(this)
00224         {
00225                 this->SetAuthor("Anope");
00226 
00227                 if (!IRCD || !IRCD->CanCertFP)
00228                         throw ModuleException("Your IRCd does not support ssl client certificates");
00229 
00230                 Implementation i[] = { I_OnFingerprint };
00231                 ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation));
00232 
00233         }
00234 
00235         void OnFingerprint(User *u) anope_override
00236         {
00237                 DoAutoIdentify(u);
00238         }
00239 };
00240 
00241 MODULE_INIT(NSCert)