#include "module.h" #define AUTHOR "DukePyrolator" #define VERSION "0.8d for anope 1.9.3-p1 only" void DoAutoIdentify(User *u) { NickAlias *na = findnick(u->nick); std::string fingerprint; if (!na) return; if (u->IsIdentified() && (u->Account() == na->nc)) return; if ((na->HasFlag(NS_FORBIDDEN)) || (na->nc->HasFlag(NI_SUSPENDED))) return; if (na->nc->access.empty()) // access list is empty return; if (!u->GetExtRegular("fingerprint", fingerprint)) // user is not using ssl return; for (unsigned i = 0; i < na->nc->access.size(); i++) { Anope::string access = na->nc->GetAccess(i); if (access == fingerprint) { u->UpdateHost(); na->last_realname = u->realname; na->last_seen = time(NULL); u->Login(na->nc); ircdproto->SendAccountLogin(u, u->Account()); ircdproto->SetAutoIdentificationToken(u); FOREACH_MOD(I_OnNickIdentify, OnNickIdentify(u)); Log() << NickServ->nick << ": " << u->GetMask() << "automatically identified for group " << u->Account()->display << " by SSL Fingerprint"; u->SendMessage(Config->s_NickServ, "SSL Fingerprint accepted. You are now recognized."); if (ircd->vhost) do_on_id(u); if (Config->NSModeOnID) do_setmodes(u); if (Config->NSForceEmail && u->IsIdentified() && u->Account()->email.empty()) { u->SendMessage(NickServ, NICK_IDENTIFY_EMAIL_REQUIRED); u->SendMessage(NickServ, NICK_IDENTIFY_EMAIL_HOWTO); } if (u->IsIdentified()) check_memos(u); } } } // debug: Received: :409 METADATA 409AAAAAA ssl :ON // debug: Received: :409 METADATA 409AAAAAA ssl_cert :vTrSe c38070ce96e41cc144ed6590a68d45a6 <...> <...> // debug: Received: :409 METADATA 409AAAAAC ssl_cert :vTrSE Could not get peer certificate: error:00000000:lib(0):func(0):reason(0) // source = numeric of the sending server // ac = number of parameters (default 3 ?) // av[0] = uuid // av[1] = metadata name // av[2] = data bool DoOnMetaData(const Anope::string &source, const std::vector ¶ms) { if (params.size() != 3) return MOD_CONT; // received invalid METADATA User* u; size_t pos1, pos2; std::string data = params[2].c_str(); std::string fingerprint; if ((params[1] == "ssl_cert") && (u = finduser(params[0]))) { pos1 = data.find(' ') + 1; pos2 = data.find(' ', pos1); fingerprint.assign(data, pos1,pos2-pos1); if (fingerprint.size() < 30) // not a valid fingerprint return EVENT_CONTINUE; u->Extend("fingerprint", new ExtensibleItemRegular(fingerprint)); DoAutoIdentify(u); } return EVENT_CONTINUE; } EventReturn DoOnAccess(User *u, const std::vector ¶ms) { Anope::string cmd = params[0]; Anope::string mask = params.size() > 1 ? params[1] : ""; std::string fingerprint; if (!u->IsIdentified()) return EVENT_CONTINUE; // nick not identified if (mask.empty()) return EVENT_CONTINUE; // let it handle by ns_access if (mask.find('@') != Anope::string::npos) return EVENT_CONTINUE; // let it handle by ns_access if (cmd.equals_ci("ADD") && mask.equals_ci("fingerprint")) { if (u->GetExtRegular("fingerprint", fingerprint)) { if (u->Account()->access.size() >= Config->NSAccessMax) { u->SendMessage(NickServ, NICK_ACCESS_REACHED_LIMIT, Config->NSAccessMax); return EVENT_STOP; } if (u->Account()->FindAccess(fingerprint)) { u->SendMessage(NickServ, NICK_ACCESS_ALREADY_PRESENT, fingerprint.c_str()); return EVENT_STOP; } u->Account()->AddAccess(fingerprint); u->SendMessage(NickServ, NICK_ACCESS_ADDED, fingerprint.c_str()); return EVENT_STOP; } else { u->SendMessage(Config->s_NickServ, Anope::string("You have no SSL Fingerprint to add")); return EVENT_STOP; } } if (cmd.equals_ci("DEL")) { if (mask.equals_ci("fingerprint")) { if (u->GetExtRegular("fingerprint", fingerprint)) { if (u->Account()->FindAccess(fingerprint)) { u->SendMessage(NickServ, NICK_ACCESS_DELETED, fingerprint.c_str()); u->Account()->EraseAccess(fingerprint); } else { u->SendMessage(NickServ, NICK_ACCESS_NOT_FOUND, fingerprint.c_str()); } } else { u->SendMessage(Config->s_NickServ, "You have no SSL Fingerprint to delete"); } return EVENT_STOP; } else if (u->Account()->FindAccess(mask)) { u->SendMessage(NickServ, NICK_ACCESS_DELETED, mask.c_str()); u->Account()->EraseAccess(mask); return EVENT_STOP; } } return EVENT_CONTINUE; } class NSFingerprint : public Module { private: Message m_metadata; public: NSFingerprint(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator), m_metadata("METADATA", DoOnMetaData) { ModuleManager::Attach(I_OnUserNickChange, this); ModuleManager::Attach(I_OnPreCommand, this); ModuleManager::Attach(I_OnUserLogoff, this); this->SetAuthor(AUTHOR); this->SetVersion(VERSION); this->SetType(THIRD); } ~NSFingerprint() { // Anope will crash on the next user-quit if we unload the module // but have still stored fingerprints in the Extensible class. // this is because we allocate the memory from within the module, // if we unload the module, any access to this memory is invalid // so we have to loop through all online users and delete the stored fingerprint std::string fingerprint; for (user_map::const_iterator it = UserListByNick.begin(), it_end = UserListByNick.end(); it != it_end; ++it) { User *u = it->second; if (u->GetExt("fingerprint")) u->Shrink("fingerprint"); } } void OnUserNickChange(User *u, const Anope::string &oldnick) // called on event nickchange { DoAutoIdentify(u); } EventReturn OnPreCommand(User *u, BotInfo *service, const Anope::string &command, const std::vector ¶ms) { if ((service == NickServ) && (command == "ACCESS")) return DoOnAccess(u, params); return EVENT_CONTINUE; } }; MODULE_INIT(NSFingerprint)