/******************************************************************
* PTlink Services is (C) Copyright PTlink IRC Software 1999-2005 *
* http://software.pt-link.net *
* This program is distributed under GNU Public License *
* Please read the file COPYING for copyright information. *
******************************************************************
File: ns_login.c
Description: nickserv login command
* $Id: ns_login.c,v 1.15 2005/12/11 16:51:17 jpinto Exp $
*/
#include "module.h"
#include "nickserv.h"
#include "dbconf.h"
#include "encrypt.h"
#include "my_sql.h"
#include "nsmacros.h"
#include "lang/common.lh"
#include "lang/nickserv.lh"
#include "lang/ns_login.lh"
SVS_Module mod_info =
/* module, version, description */
{ "ns_login", "2.3","nickserv login command" };
/* Change Log
2.3 - #50: nickserv login option to override nick language
#21 : remove unused/moved fields from nickserv table
#10 : add nickserv suspensions
2.2 - #23 : e_nick_identify is not called on ns_login when the nick is online
2.1 - 0000352: nickserv login is not informing the user with "Password accepted"
2.0 - 0000287: ns_getpass and ns_getsec to recover password and security code
0000272: move nickserv security info to a specific table
0000265: remove nickserv cache system
1.2 - 0000248: nick login log message using wrong string pointer
- 0000249: add nickserv REGAIN alias to LOGIN
1.1 - call the nick_identify event on login
*/
/* external functions we need */
ServiceUser* (*nickserv_suser)(void);
int (*update_nick_online_info)(IRC_User* u, u_int32_t snid, int lang);
int (*check_nick_security)
(u_int32_t snid, IRC_User *u, char* pass, char* email, int flags);
int e_nick_identify;
MOD_REQUIRES
MOD_FUNC(dbconf_get)
MOD_FUNC(nickserv_suser)
MOD_FUNC(e_nick_identify)
MOD_FUNC(update_nick_online_info)
MOD_FUNC(check_nick_security)
MOD_END
/* internal functions */
/* available commands from module */
void ns_login(IRC_User *s, IRC_User *u);
void ns_recover(IRC_User *s, IRC_User *u);
/* Local settings */
int FailedLoginMax;
/*
* List of dbconf items we require
*/
DBCONF_REQUIRES
DBCONF_GET("nickserv", FailedLoginMax)
DBCONF_END
/* this is called before load and at services rehash */
int mod_rehash(void)
{
if(dbconf_get(dbconf_requires) < 0 )
{
errlog("Error reading dbconf!");
return -1;
}
return 0;
}
ServiceUser *nsu;
int ns_log;
static int is_recover = 0; /* internal flag for the recover command */
int mod_load(void)
{
nsu = nickserv_suser();
ns_log = log_handle("nickserv");
suser_add_cmd(nsu, "LOGIN", ns_login, LOGIN_SUMMARY, LOGIN_HELP);
suser_add_cmd(nsu, "GHOST", ns_login, NULL, NULL);
suser_add_cmd(nsu, "REGAIN", ns_login, NULL, NULL);
suser_add_cmd(nsu, "RECOVER", ns_recover, NULL, NULL);
return 0;
}
void mod_unload(void)
{
suser_del_mod_cmds(nsu, &mod_info);
}
/* s = service the command was sent to
u = user the command was sent from */
void ns_login(IRC_User *s, IRC_User *u)
{
int diff;
int lang = -1;
char *target = strtok(NULL, " ");
char *pass = strtok(NULL, " ");
char *langstr = strtok(NULL, " ");
if(langstr)
{
lang2index(langstr, lang);
}
if(IsNull(target) || IsNull(pass)) /* all parts filled in ? */
send_lang(u, s, NICK_LOGIN_SYNTAX);
else if(sql_singlequery("SELECT snid, flags, lang, vhost, email"
" FROM nickserv WHERE nick=%s", sql_str(irc_lower_nick(target))) == 0)
send_lang(u, s, NICK_NOT_REGISTERED);
else /* ok to validate password */
{
char *check;
u_int32_t snid = sql_field_i(0);
u_int32_t flags = sql_field_i(1);
char *vhost = NULL;
char *email = NULL;
if(lang == -1)
lang = sql_field_i(2);
if(sql_field(3))
vhost = strdup(sql_field(3));
if(sql_field(4))
email = strdup(sql_field(4));
if((flags & NFL_SUSPENDED) &&
sql_singlequery("SELECT reason FROM nickserv_suspensions WHERE snid=%d", snid))
{
FREE(vhost);
FREE(email);
send_lang(u,s, NICK_X_IS_SUSPENDED_X, target, sql_field(0));
return;
}
check = is_recover ? "securitycode" : "pass";
if(sql_singlequery("SELECT %s"
" FROM nickserv_security WHERE snid=%d", check, snid) == 0)
{
send_lang(u, s, INCORRECT_PASSWORD);
log_log(ns_log, mod_info.name, "Missing nick security record for %d",
snid);
FREE(vhost);
FREE(email);
return;
}
if(sql_field(0))
{
if(is_recover)
{ /* case insentive for md5 validation */
diff = strcasecmp(sql_field(0), pass);
is_recover = 0;
}
else
{
diff = memcmp( hex_bin(sql_field(0)), encrypted_password(pass), 16);
}
}
if(diff !=0 )
{
log_log(ns_log, mod_info.name, "Failed login for %s by %s",
target, irc_UserMask(u));
if(FailedLoginMax && ++u->fcount > FailedLoginMax)
{
log_log(ns_log, mod_info.name,
"Killing %s after too many failed identifies", u->nick);
irc_Kill(u, s, "Too many invalid identify attempts");
}
else
send_lang(u, s, INCORRECT_PASSWORD);
}
else
{
IRC_User* ku; /* we may beed to kill the current used */
u->lang = lang;
log_log(ns_log, mod_info.name, "Nick %s login by %s",
target, irc_UserMask(u));
send_lang(u, s, NS_LOGIN_OK);
ku = irc_FindUser(target);
if(ku == u) /* nick is alreading using the proper nick */
{
int was_identified = irc_IsUMode(u, UMODE_IDENTIFIED);
check_nick_security(snid, u, NULL, email, flags);
update_nick_online_info(u, snid, lang);
if(vhost && irccmp(u->publichost, vhost)) /* we need to set the vhost */
irc_ChgHost(u, vhost);
irc_CancelUserTimerEvents(u); /* delete the pending change nick event */
if(!was_identified)
{
mod_do_event(e_nick_identify, u, &snid);
}
}
else
{
u->req_snid = snid; /* for auto-identify */
/* kill the user */
if(ku)
{
char killmsg[128];
snprintf(killmsg, sizeof(killmsg),
"LOGIN command used by %s", u->nick);
irc_Kill(ku, s, killmsg);
}
irc_SvsNick(u, s, target);
}
}
FREE(vhost);
FREE(email);
}
}
/* s = service the command was sent to
u = user the command was sent from */
void ns_recover(IRC_User *s, IRC_User *u)
{
is_recover = 1;
ns_login(s, u);
return;
}
syntax highlighted by Code2HTML, v. 0.9.1