mirror of
https://github.com/anope/anope.git
synced 2026-07-02 08:06:37 +02:00
04fe8e623c
git-svn-id: http://anope.svn.sourceforge.net/svnroot/anope/trunk@2083 5417fbe8-f217-4b02-8779-1006273d7864
519 lines
13 KiB
C
519 lines
13 KiB
C
/* NickServ core functions
|
|
*
|
|
* (C) 2003-2009 Anope Team
|
|
* Contact us at team@anope.org
|
|
*
|
|
* Please read COPYING and README for further details.
|
|
*
|
|
* Based on the original code of Epona by Lara.
|
|
* Based on the original code of Services by Andy Church.
|
|
*
|
|
* $Id$
|
|
*
|
|
*/
|
|
/*************************************************************************/
|
|
|
|
#include "module.h"
|
|
#include "encrypt.h"
|
|
|
|
void myNickServHelp(User *u);
|
|
NickRequest *makerequest(const char *nick);
|
|
NickAlias *makenick(const char *nick);
|
|
int do_sendregmail(User *u, NickRequest *nr);
|
|
|
|
class CommandNSConfirm : public Command
|
|
{
|
|
protected:
|
|
CommandReturn ActuallyConfirmNick(User *u, NickRequest *nr, bool force)
|
|
{
|
|
NickAlias *na;
|
|
na = makenick(nr->nick);
|
|
|
|
if (!na)
|
|
{
|
|
alog("%s: makenick(%s) failed", s_NickServ, u->nick);
|
|
notice_lang(s_NickServ, u, NICK_REGISTRATION_FAILED);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
int i, len;
|
|
char tsbuf[16];
|
|
char tmp_pass[PASSMAX];
|
|
char modes[512];
|
|
|
|
memcpy(na->nc->pass, nr->password, PASSMAX);
|
|
na->status = static_cast<int16>(NS_IDENTIFIED | NS_RECOGNIZED);
|
|
|
|
na->nc->flags |= NSDefFlags;
|
|
for (i = 0; i < RootNumber; ++i)
|
|
{
|
|
if (!stricmp(ServicesRoots[i], nr->nick))
|
|
{
|
|
na->nc->flags |= NI_SERVICES_ROOT;
|
|
break;
|
|
}
|
|
}
|
|
|
|
na->nc->memos.memomax = MSMaxMemos;
|
|
|
|
if (force)
|
|
{
|
|
na->last_usermask = sstrdup("*@*");
|
|
na->last_realname = sstrdup("unknown");
|
|
}
|
|
else
|
|
{
|
|
na->last_usermask = new char[u->GetIdent().length() + u->GetDisplayedHost().length() + 2];
|
|
sprintf(na->last_usermask, "%s@%s", u->GetIdent().c_str(), u->GetDisplayedHost().c_str());
|
|
na->last_realname = sstrdup(u->realname);
|
|
}
|
|
|
|
na->time_registered = na->last_seen = time(NULL);
|
|
|
|
if (NSAddAccessOnReg)
|
|
{
|
|
na->nc->accesscount = 1;
|
|
na->nc->access = static_cast<char **>(scalloc(sizeof(char *), 1));
|
|
na->nc->access[0] = create_mask(u);
|
|
}
|
|
else
|
|
{
|
|
na->nc->accesscount = 0;
|
|
na->nc->access = NULL;
|
|
}
|
|
|
|
na->nc->language = NSDefLanguage;
|
|
if (nr->email)
|
|
na->nc->email = sstrdup(nr->email);
|
|
|
|
if (!force)
|
|
{
|
|
u->nc = na->nc;
|
|
alog("%s: '%s' registered by %s@%s (e-mail: %s)", s_NickServ, u->nick, u->GetIdent().c_str(), u->host, nr->email ? nr->email : "none");
|
|
if (NSAddAccessOnReg)
|
|
notice_lang(s_NickServ, u, NICK_REGISTERED, u->nick, na->nc->access[0]);
|
|
else
|
|
notice_lang(s_NickServ, u, NICK_REGISTERED_NO_MASK, u->nick);
|
|
send_event(EVENT_NICK_REGISTERED, 1, u->nick);
|
|
|
|
if (enc_decrypt(na->nc->pass, tmp_pass, PASSMAX - 1) == 1)
|
|
notice_lang(s_NickServ, u, NICK_PASSWORD_IS, tmp_pass);
|
|
|
|
u->lastnickreg = time(NULL);
|
|
if (ircd->modeonreg)
|
|
{
|
|
len = strlen(ircd->modeonreg);
|
|
strncpy(modes, ircd->modeonreg, 512);
|
|
if (ircd->rootmodeonid && is_services_root(u))
|
|
strncat(modes, ircd->rootmodeonid, 512 - len);
|
|
else if (ircd->adminmodeonid && is_services_admin(u))
|
|
strncat(modes, ircd->adminmodeonid, 512 - len);
|
|
else if (ircd->opermodeonid && is_services_oper(u))
|
|
strncat(modes, ircd->opermodeonid, 512 - len);
|
|
|
|
if (ircd->tsonmode)
|
|
{
|
|
snprintf(tsbuf, sizeof(tsbuf), "%lu", static_cast<unsigned long>(u->timestamp));
|
|
common_svsmode(u, modes, tsbuf);
|
|
}
|
|
else
|
|
common_svsmode(u, modes, NULL);
|
|
}
|
|
}
|
|
else
|
|
notice_lang(s_NickServ, u, NICK_FORCE_REG, nr->nick);
|
|
delnickrequest(nr); /* remove the nick request */
|
|
|
|
return MOD_CONT;
|
|
|
|
}
|
|
|
|
CommandReturn DoConfirm(User *u, std::vector<std::string> ¶ms)
|
|
{
|
|
NickRequest *nr = NULL;
|
|
const char *passcode = params.size() ? params[0].c_str() : NULL;
|
|
|
|
nr = findrequestnick(u->nick);
|
|
|
|
if (NSEmailReg)
|
|
{
|
|
if (!passcode)
|
|
{
|
|
notice_lang(s_NickServ, u, NICK_CONFIRM_INVALID);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
if (!nr)
|
|
{
|
|
if (is_services_admin(u))
|
|
{
|
|
/* If an admin, their nick is obviously already regged, so look at the passcode to get the nick
|
|
of the user they are trying to validate, and push that user through regardless of passcode */
|
|
nr = findrequestnick(passcode);
|
|
if (nr)
|
|
{
|
|
User *utmp = finduser(passcode);
|
|
if (utmp)
|
|
{
|
|
ActuallyConfirmNick(u, nr, false);
|
|
notice_lang(s_NickServ, u, NICK_FORCE_REG, nr->nick);
|
|
return MOD_CONT;
|
|
}
|
|
else
|
|
{
|
|
passcode = nr->passcode;
|
|
ActuallyConfirmNick(u, nr, true);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
notice_lang(s_NickServ, u, NICK_CONFIRM_NOT_FOUND, s_NickServ);
|
|
return MOD_CONT;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
notice_lang(s_NickServ, u, NICK_CONFIRM_NOT_FOUND, s_NickServ);
|
|
return MOD_CONT;
|
|
}
|
|
}
|
|
|
|
if (stricmp(nr->passcode, passcode))
|
|
{
|
|
notice_lang(s_NickServ, u, NICK_CONFIRM_INVALID);
|
|
return MOD_CONT;
|
|
}
|
|
}
|
|
|
|
if (!nr)
|
|
{
|
|
notice_lang(s_NickServ, u, NICK_REGISTRATION_FAILED);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
ActuallyConfirmNick(u, nr, false);
|
|
return MOD_CONT;
|
|
}
|
|
public:
|
|
CommandNSConfirm(const std::string &cmdn, int min, int max) : Command(cmdn, min, max)
|
|
{
|
|
}
|
|
|
|
CommandReturn Execute(User *u, std::vector<std::string> ¶ms)
|
|
{
|
|
return this->DoConfirm(u, params);
|
|
}
|
|
|
|
bool OnHelp(User *u, const std::string &subcommand)
|
|
{
|
|
notice_help(s_NickServ, u, NICK_HELP_CONFIRM);
|
|
return true;
|
|
}
|
|
};
|
|
|
|
class CommandNSRegister : public CommandNSConfirm
|
|
{
|
|
public:
|
|
CommandNSRegister() : CommandNSConfirm("REGISTER", 1, 2)
|
|
{
|
|
this->SetFlag(CFLAG_ALLOW_UNREGISTERED);
|
|
}
|
|
|
|
CommandReturn Execute(User *u, std::vector<std::string> ¶ms)
|
|
{
|
|
NickRequest *nr = NULL, *anr = NULL;
|
|
NickCore *nc = NULL;
|
|
NickAlias *na;
|
|
int prefixlen = strlen(NSGuestNickPrefix);
|
|
int nicklen = strlen(u->nick);
|
|
const char *pass = params[0].c_str();
|
|
const char *email = params.size() > 1 ? params[1].c_str() : NULL;
|
|
char passcode[11];
|
|
int idx, min = 1, max = 62, i = 0;
|
|
int chars[] =
|
|
{ ' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
|
|
'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
|
|
'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
|
|
'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y',
|
|
'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
|
|
};
|
|
|
|
if (readonly)
|
|
{
|
|
notice_lang(s_NickServ, u, NICK_REGISTRATION_DISABLED);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
if (checkDefCon(DEFCON_NO_NEW_NICKS))
|
|
{
|
|
notice_lang(s_NickServ, u, OPER_DEFCON_DENIED);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
if (!is_oper(u) && NickRegDelay && time(NULL) - u->my_signon < NickRegDelay)
|
|
{
|
|
notice_lang(s_NickServ, u, NICK_REG_DELAY, NickRegDelay);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
if ((anr = findrequestnick(u->nick)))
|
|
{
|
|
notice_lang(s_NickServ, u, NICK_REQUESTED);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
/* Prevent "Guest" nicks from being registered. -TheShadow */
|
|
|
|
/* Guest nick can now have a series of between 1 and 7 digits.
|
|
* --lara
|
|
*/
|
|
if (nicklen <= prefixlen + 7 && nicklen >= prefixlen + 1 && stristr(u->nick, NSGuestNickPrefix) == u->nick && strspn(u->nick + prefixlen, "1234567890") == nicklen - prefixlen)
|
|
{
|
|
notice_lang(s_NickServ, u, NICK_CANNOT_BE_REGISTERED, u->nick);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
if (!ircdproto->IsNickValid(u->nick))
|
|
{
|
|
notice_lang(s_NickServ, u, NICK_X_FORBIDDEN, u->nick);
|
|
return MOD_CONT;
|
|
}
|
|
|
|
if (RestrictOperNicks)
|
|
{
|
|
for (i = 0; i < RootNumber; ++i)
|
|
{
|
|
if (stristr(u->nick, ServicesRoots[i]) && !is_oper(u))
|
|
{
|
|
notice_lang(s_NickServ, u, NICK_CANNOT_BE_REGISTERED, u->nick);
|
|
return MOD_CONT;
|
|
}
|
|
}
|
|
for (i = 0; i < servadmins.count && (nc = static_cast<NickCore *>(servadmins.list[i])); ++i)
|
|
{
|
|
if (stristr(u->nick, nc->display) && !is_oper(u))
|
|
{
|
|
notice_lang(s_NickServ, u, NICK_CANNOT_BE_REGISTERED, u->nick);
|
|
return MOD_CONT;
|
|
}
|
|
}
|
|
for (i = 0; i < servopers.count && (nc = static_cast<NickCore *>(servopers.list[i])); ++i)
|
|
{
|
|
if (stristr(u->nick, nc->display) && !is_oper(u))
|
|
{
|
|
notice_lang(s_NickServ, u, NICK_CANNOT_BE_REGISTERED, u->nick);
|
|
return MOD_CONT;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (NSForceEmail && !email)
|
|
this->OnSyntaxError(u);
|
|
else if (time(NULL) < u->lastnickreg + NSRegDelay)
|
|
notice_lang(s_NickServ, u, NICK_REG_PLEASE_WAIT, NSRegDelay);
|
|
else if ((na = findnick(u->nick)))
|
|
{
|
|
/* i.e. there's already such a nick regged */
|
|
if (na->status & NS_FORBIDDEN)
|
|
{
|
|
alog("%s: %s@%s tried to register FORBIDden nick %s", s_NickServ, u->GetIdent().c_str(), u->host, u->nick);
|
|
notice_lang(s_NickServ, u, NICK_CANNOT_BE_REGISTERED, u->nick);
|
|
}
|
|
else
|
|
notice_lang(s_NickServ, u, NICK_ALREADY_REGISTERED, u->nick);
|
|
}
|
|
else if (!stricmp(u->nick, pass) || (StrictPasswords && strlen(pass) < 5))
|
|
notice_lang(s_NickServ, u, MORE_OBSCURE_PASSWORD);
|
|
else if (enc_encrypt_check_len(strlen(pass), PASSMAX - 1))
|
|
notice_lang(s_NickServ, u, PASSWORD_TOO_LONG);
|
|
else if (email && !MailValidate(email))
|
|
notice_lang(s_NickServ, u, MAIL_X_INVALID, email);
|
|
else
|
|
{
|
|
for (idx = 0; idx < 9; ++idx)
|
|
passcode[idx] = chars[1 + static_cast<int>((static_cast<float>(max - min)) * getrandom16() / 65536.0) + min];
|
|
passcode[idx] = '\0';
|
|
nr = makerequest(u->nick);
|
|
nr->passcode = sstrdup(passcode);
|
|
strscpy(nr->password, pass, PASSMAX);
|
|
enc_encrypt_in_place(nr->password, PASSMAX);
|
|
if (email)
|
|
nr->email = sstrdup(email);
|
|
nr->requested = time(NULL);
|
|
if (NSEmailReg)
|
|
{
|
|
if (!do_sendregmail(u, nr))
|
|
{
|
|
notice_lang(s_NickServ, u, NICK_ENTER_REG_CODE, email, s_NickServ);
|
|
alog("%s: sent registration verification code to %s", s_NickServ, nr->email);
|
|
}
|
|
else
|
|
{
|
|
alog("%s: Unable to send registration verification mail", s_NickServ);
|
|
notice_lang(s_NickServ, u, NICK_REG_UNABLE);
|
|
delnickrequest(nr); /* Delete the NickRequest if we couldnt send the mail */
|
|
return MOD_CONT;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::vector<std::string> empty_params;
|
|
return this->DoConfirm(u, empty_params);
|
|
}
|
|
}
|
|
|
|
return MOD_CONT;
|
|
}
|
|
|
|
bool OnHelp(User *u, const std::string &subcommand)
|
|
{
|
|
notice_help(s_NickServ, u, NICK_HELP_REGISTER);
|
|
return true;
|
|
}
|
|
|
|
void OnSyntaxError(User *u)
|
|
{
|
|
if (NSForceEmail)
|
|
syntax_error(s_NickServ, u, "REGISTER", NICK_REGISTER_SYNTAX_EMAIL);
|
|
else
|
|
syntax_error(s_NickServ, u, "REGISTER", NICK_REGISTER_SYNTAX);
|
|
}
|
|
};
|
|
|
|
class CommandNSResend : public Command
|
|
{
|
|
public:
|
|
CommandNSResend() : Command("RESEND", 0, 0)
|
|
{
|
|
}
|
|
|
|
CommandReturn Execute(User *u, std::vector<std::string> ¶ms)
|
|
{
|
|
NickRequest *nr = NULL;
|
|
if (NSEmailReg)
|
|
{
|
|
if ((nr = findrequestnick(u->nick)))
|
|
{
|
|
if (time(NULL) < nr->lastmail + NSResendDelay)
|
|
{
|
|
notice_lang(s_NickServ, u, MAIL_LATER);
|
|
return MOD_CONT;
|
|
}
|
|
if (!do_sendregmail(u, nr))
|
|
{
|
|
nr->lastmail = time(NULL);
|
|
notice_lang(s_NickServ, u, NICK_REG_RESENT, nr->email);
|
|
alog("%s: re-sent registration verification code for %s to %s", s_NickServ, nr->nick, nr->email);
|
|
}
|
|
else
|
|
{
|
|
alog("%s: Unable to re-send registration verification mail for %s", s_NickServ, nr->nick);
|
|
return MOD_CONT;
|
|
}
|
|
}
|
|
}
|
|
return MOD_CONT;
|
|
}
|
|
|
|
bool OnHelp(User *u, const std::string &subcommand)
|
|
{
|
|
notice_help(s_NickServ, u, NICK_HELP_RESEND);
|
|
return true;
|
|
}
|
|
};
|
|
|
|
class NSRegister : public Module
|
|
{
|
|
public:
|
|
NSRegister(const std::string &modname, const std::string &creator) : Module(modname, creator)
|
|
{
|
|
this->SetAuthor("Anope");
|
|
this->SetVersion("$Id$");
|
|
this->SetType(CORE);
|
|
|
|
this->AddCommand(NICKSERV, new CommandNSRegister(), MOD_UNIQUE);
|
|
this->AddCommand(NICKSERV, new CommandNSConfirm("CONFIRM", 0, 1), MOD_UNIQUE);
|
|
this->AddCommand(NICKSERV, new CommandNSResend(), MOD_UNIQUE);
|
|
|
|
this->SetNickHelp(myNickServHelp);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Add the help response to anopes /ns help output.
|
|
* @param u The user who is requesting help
|
|
**/
|
|
void myNickServHelp(User *u)
|
|
{
|
|
notice_lang(s_NickServ, u, NICK_HELP_CMD_REGISTER);
|
|
if (NSEmailReg)
|
|
{
|
|
notice_lang(s_NickServ, u, NICK_HELP_CMD_CONFIRM);
|
|
notice_lang(s_NickServ, u, NICK_HELP_CMD_RESEND);
|
|
}
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
NickRequest *makerequest(const char *nick)
|
|
{
|
|
NickRequest *nr;
|
|
|
|
nr = new NickRequest;
|
|
nr->nick = sstrdup(nick);
|
|
insert_requestnick(nr);
|
|
alog("%s: Nick %s has been requested", s_NickServ, nr->nick);
|
|
return nr;
|
|
}
|
|
|
|
/* Creates a full new nick (alias + core) in NickServ database. */
|
|
NickAlias *makenick(const char *nick)
|
|
{
|
|
NickAlias *na;
|
|
NickCore *nc;
|
|
|
|
/* First make the core */
|
|
nc = new NickCore();
|
|
nc->display = sstrdup(nick);
|
|
slist_init(&nc->aliases);
|
|
insert_core(nc);
|
|
alog("%s: group %s has been created", s_NickServ, nc->display);
|
|
|
|
/* Then make the alias */
|
|
na = new NickAlias;
|
|
na->nick = sstrdup(nick);
|
|
na->nc = nc;
|
|
slist_add(&nc->aliases, na);
|
|
alpha_insert_alias(na);
|
|
return na;
|
|
}
|
|
|
|
int do_sendregmail(User *u, NickRequest *nr)
|
|
{
|
|
MailInfo *mail = NULL;
|
|
char buf[BUFSIZE];
|
|
|
|
if (!nr && !u)
|
|
return -1;
|
|
snprintf(buf, sizeof(buf), getstring(NICK_REG_MAIL_SUBJECT), nr->nick);
|
|
mail = MailRegBegin(u, nr, buf, s_NickServ);
|
|
if (!mail)
|
|
return -1;
|
|
fprintf(mail->pipe, getstring(NICK_REG_MAIL_HEAD));
|
|
fprintf(mail->pipe, "\n\n");
|
|
fprintf(mail->pipe, getstring(NICK_REG_MAIL_LINE_1), nr->nick);
|
|
fprintf(mail->pipe, "\n\n");
|
|
fprintf(mail->pipe, getstring(NICK_REG_MAIL_LINE_2), s_NickServ, nr->passcode);
|
|
fprintf(mail->pipe, "\n\n");
|
|
fprintf(mail->pipe, getstring(NICK_REG_MAIL_LINE_3));
|
|
fprintf(mail->pipe, "\n\n");
|
|
fprintf(mail->pipe, getstring(NICK_REG_MAIL_LINE_4));
|
|
fprintf(mail->pipe, "\n\n");
|
|
fprintf(mail->pipe, getstring(NICK_REG_MAIL_LINE_5), NetworkName);
|
|
fprintf(mail->pipe, "\n.\n");
|
|
MailEnd(mail);
|
|
return 0;
|
|
}
|
|
|
|
MODULE_INIT("ns_register", NSRegister)
|