00001
00002
00003
00004
00005
00006
00007
00008
00009
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> ¶ms) 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)