/********************************************************************* * IRCd-ratbox * m_forcenick: change a user's nick: ops only * * Copyright (C) 2005 ASO Development Team * * Bob Krouse * NoUse * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 1, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * ********************************************************************/ #include "stdinc.h" #include "client.h" #include "hash.h" #include "irc_string.h" #include "ircd.h" #include "numeric.h" #include "s_conf.h" #include "s_stats.h" #include "s_user.h" #include "hash.h" #include "whowas.h" #include "s_serv.h" #include "send.h" #include "channel.h" #include "s_log.h" #include "msg.h" #include "parse.h" #include "modules.h" #include "common.h" #include "packet.h" #include "scache.h" #include "s_newconf.h" #include "monitor.h" /* #define __EVIL_SANICK */ /* Evil Sanick is NoUse's funny way of teaching non-opers to leave it alone */ #ifdef __EVIL_SANICK static int munreg_sanick(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]); static int mclient_sanick(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]); static int mserver_sanick(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]); static int mrclient_sanick(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]); #endif /* __EVIL_SANICK */ static int moper_sanick(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]); struct Message sanick_msgtab = { "sanick", 0,0,0,MFLG_SLOW, { #ifdef __EVIL_SANICK {munreg_sanick, 0}, /* unreg -NoUse */ {mclient_sanick, 0}, /* local -NoUse */ mg_ignore, /* remote -lovepump */ mg_ignore, /* server -lovepump */ mg_ignore, /* ENCAP */ #else mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, #endif /* __EVIL_SANICK */ {moper_sanick, 2} /* ops -lovepump */ } }; mapi_clist_av1 sanick_clist[] = { &sanick_msgtab, NULL }; DECLARE_MODULE_AV1( sanick, NULL, NULL, sanick_clist, NULL, NULL, "$Revision: 0.01 $"); static int validate_nick(char *nick) { if(nick == NULL) return 0; if(nick[0] == '-' || IsDigit(*nick) || strlen(nick) == 0) return 0; while(*nick != NULL) { if(!IsNickChar(nick)) return 0; nick++; } return 1; } #ifdef __EVIL_SANICK /* unreg */ static int munreg_sanick(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Channel *chptr; struct membership *msptr; chptr = find_channel(source_p->name); msptr = find_channel_membership(chptr, client_p); sendto_one(source_p, ":%s NOTICE %s :You are unregistered, goodbye (_)_):::D", me.name, source_p->name); sendto_channel_local(ALL_MEMBERS, chptr, ":%s KICK %s %s :%s",me.name, chptr->chname, source_p->name, "Fuck off!"); sendto_server(&me, chptr, NOCAPS, NOCAPS, ":%s KICK %s %s :%s", me.name, chptr->chname, source_p->name, "Fuck off!"); remove_user_from_channel(msptr); return 0; } /* local non op */ static int mclient_sanick(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Channel *chptr; struct membership *msptr; chptr = find_channel(source_p->name); msptr = find_channel_membership(chptr, client_p); sendto_one(source_p, ":%s NOTICE %s :You are unregistered, goodbye (_)_):::D", me.name, source_p->name); sendto_channel_local(ALL_MEMBERS, chptr, ":%s KICK %s %s :%s",me.name, chptr->chname, source_p->name, "Fuck off!"); sendto_server(&me, chptr, NOCAPS, NOCAPS, ":%s KICK %s %s :%s", me.name, chptr->chname, source_p->name, "Fuck off!"); remove_user_from_channel(msptr); return 0; } #endif static void change_local_nick(struct Client *client_p, struct Client *source_p, char *nick) { struct Client *target_p; dlink_node *ptr, *next_ptr; int samenick; if((source_p->localClient->last_nick_change + ConfigFileEntry.max_nick_time) < CurrentTime) source_p->localClient->number_of_nick_changes = 0; source_p->localClient->last_nick_change = CurrentTime; source_p->localClient->number_of_nick_changes++; if(ConfigFileEntry.anti_nick_flood && !IsOper(source_p) && source_p->localClient->number_of_nick_changes > ConfigFileEntry.max_nick_changes) { sendto_one(source_p, form_str(ERR_NICKTOOFAST), me.name, source_p->name, source_p->name, nick, ConfigFileEntry.max_nick_time); return; } samenick = irccmp(source_p->name, nick) ? 0 : 1; /* dont reset TS if theyre just changing case of nick */ if(!samenick) { source_p->tsinfo = CurrentTime; monitor_signoff(source_p); } sendto_realops_flags(UMODE_NCHANGE, L_ALL, "Nick change: From %s to %s [%s@%s]", source_p->name, nick, source_p->username, source_p->host); /* send the nick change to the users channels */ sendto_common_channels_local(source_p, ":%s!%s@%s NICK :%s", source_p->name, source_p->username, source_p->host, nick); /* send the nick change to servers.. */ if(source_p->user) { add_history(source_p, 1); sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s NICK %s :%ld", use_id(source_p), nick, (long) source_p->tsinfo); sendto_server(client_p, NULL, NOCAPS, CAP_TS6, ":%s NICK %s :%ld", source_p->name, nick, (long) source_p->tsinfo); } /* Finally, add to hash */ del_from_client_hash(source_p->name, source_p); strcpy(source_p->name, nick); add_to_client_hash(nick, source_p); if(!samenick) monitor_signon(source_p); /* Make sure everyone that has this client on its accept list * loses that reference. */ /* we used to call del_all_accepts() here, but theres no real reason * to clear a clients own list of accepted clients. So just remove * them from everyone elses list --anfl */ DLINK_FOREACH_SAFE(ptr, next_ptr, source_p->on_allow_list.head) { target_p = ptr->data; dlinkFindDestroy(source_p, &target_p->localClient->allow_list); dlinkDestroy(ptr, &source_p->on_allow_list); } /* fd_desc is long enough */ comm_note(client_p->localClient->fd, "Nick: %s", nick); return; } static int moper_sanick(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Client *target_p; char new_nick[NICKLEN]; if(parc < 2) { sendto_one(source_p, ":%s ERROR %s : Incorrect Syntax.", me.name, source_p->name); return 0; } /* Ensure source is an oper */ if(!IsOper(source_p)) { sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "sanick"); return 0; } /* Valid target nick? If not, quit */ if((target_p = find_client(parv[1])) == NULL) { sendto_one(source_p, form_str(ERR_NOSUCHNICK), me.name, source_p->name, parv[1]); return 0; } strlcpy(new_nick, parv[2], sizeof(new_nick)); /*if(!validate_nick(new_nick)) { sendto_one(source_p, ":%s NOTICE %s: Invalid Target Nick %s", me.name, source_p->name, new_nick); return 0; }*/ /* Now make sure the new nick is not a duplicate of an existing nick */ if(find_client(new_nick) != NULL) { sendto_one(source_p, ":%s NOTICE %s : *** Notice, nick %s is in use.", me.name, source_p->name, parv[2]); return 0; } change_local_nick(target_p, target_p, new_nick); return 0; }