DLLFUNC CMD_FUNC(m_svsfline) { if (!IsServer(sptr)) return 0; if (parc < 2) return 0; switch (*parv[1]) { /* Allow non-U:lines to send ONLY SVSFLINE +, but don't send it out * unless it is from a U:line -- codemastr */ case '+': { if (parc < 4) return 0; if (!Find_deny_dcc(parv[2])) DCCdeny_add(parv[2], parv[3], DCCDENY_HARD, CONF_BAN_TYPE_AKILL); if (IsULine(sptr)) sendto_serv_butone_token(cptr, sptr->name, MSG_SVSFLINE, TOK_SVSFLINE, "+ %s :%s", parv[2], parv[3]); break; } case '-': { ConfigItem_deny_dcc *deny; if (!IsULine(sptr)) return 0; if (parc < 3) return 0; if (!(deny = Find_deny_dcc(parv[2]))) break; DCCdeny_del(deny); sendto_serv_butone_token(cptr, sptr->name, MSG_SVSFLINE, TOK_SVSFLINE, "%s", parv[2]); break; } case '*': { if (!IsULine(sptr)) return 0; dcc_wipe_services(); sendto_serv_butone_token(cptr, sptr->name, MSG_SVSFLINE, TOK_SVSFLINE, "*"); break; } } return 0; }
DLLFUNC int m_rawto(aClient *cptr, aClient *sptr, int parc, char *parv[]) { aClient *acptr = NULL; if (!IsULine(sptr)) { sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); return -1; } if (parc < 3) { sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "RAWTO"); return -1; } if ((acptr = find_client(parv[1], NULL))) { if (MyConnect(acptr)) { sendto_one(acptr, "%s", parv[2]); return 0; } else { sendto_one(acptr, ":%s %s %s :%s", parv[0], IsToken(acptr->from) ? TOK_RAWTO : MSG_RAWTO, parv[1], parv[2]); return 0; } } return 0; }
DLLFUNC char *umsg_notice(aClient *cptr, aClient *sptr, aClient *acptr, char *text, int notice) { Hook *tmphook; int found = 0; if (!notice || !IsULine(sptr)) return text; /* We are going to deal with it ourselves! */ for (tmphook = Hooks[HOOKTYPE_USERMSG]; tmphook; tmphook = tmphook->next) { if (tmphook->func.pcharfunc == umsg_notice) { found = 1; continue; } if (!found) continue; text = (*(tmphook->func.pcharfunc))(cptr, sptr, acptr, text, notice); if (!text) return NULL; } sendto_message_one(acptr, sptr, sptr->name, MSG_PRIVATE, acptr->name, text); return NULL; /* always! we dealt with it! */ }
// Parts all insecure users on a +z channel (NOT KICK) void f_part_insecure_users (aChannel *chptr) { Member *member, *mb2; aClient *cptr; char *comment = "Insecure user not allowed on secure channel (+z)"; for (member = chptr->members; member; member = mb2) { mb2 = member->next; cptr = member->cptr; if (MyClient(cptr) && !IsSecureConnect(cptr) && !IsULine(cptr)) { RunHook4(HOOKTYPE_LOCAL_PART, cptr, &me, chptr, comment); if ((chptr->mode.mode & MODE_AUDITORIUM) && is_chanownprotop(cptr, chptr)) { sendto_chanops_butone(cptr, chptr, ":%s!%s@%s PART %s :%s", cptr->name, cptr->user->username, GetHost(cptr), chptr->chname, comment); sendto_prefix_one(cptr, &me, ":%s!%s@%s PART %s :%s", cptr->name, cptr->user->username, GetHost(cptr), chptr->chname, comment); } else { sendto_channel_butserv(chptr, &me, ":%s!%s@%s PART %s :%s", cptr->name, cptr->user->username, GetHost(cptr), chptr->chname, comment); } sendto_one(cptr, err_str(ERR_SECUREONLYCHAN), me.name, cptr->name, chptr->chname); sendto_serv_butone_token(&me, cptr->name, MSG_PART, TOK_PART, "%s :%s", chptr->chname, comment); remove_user_from_channel(cptr, chptr); } } }
int m_svso(aClient *cptr, aClient *sptr, int parc, char *parv[]) { aClient *acptr; long fLag; if (!IsULine(sptr)) return 0; if (parc < 3) return 0; if (!(acptr = find_person(parv[1], (aClient *)NULL))) return 0; if (!MyClient(acptr)) { sendto_one(acptr, ":%s SVSO %s %s", parv[0], parv[1], parv[2]); return 0; } if (*parv[2] == '+') { int *i, flag; char *m = NULL; for (m = (parv[2] + 1); *m; m++) { for (i = oper_access; (flag = *i); i += 2) { if (*m == (char) *(i + 1)) { acptr->oflag |= flag; break; } } } } if (*parv[2] == '-') { fLag = acptr->umodes; if (IsOper(acptr) && !IsHideOper(acptr)) { IRCstats.operators--; VERIFY_OPERCOUNT(acptr, "svso"); } if (IsAnOper(acptr)) delfrom_fdlist(acptr->slot, &oper_fdlist); acptr->umodes &= ~(UMODE_OPER | UMODE_LOCOP | UMODE_HELPOP |UMODE_SERVICES | UMODE_SADMIN | UMODE_ADMIN | UMODE_COADMIN); acptr->umodes &= ~(UMODE_NETADMIN | UMODE_WHOIS); acptr->umodes &= ~(UMODE_KIX | UMODE_DEAF | UMODE_HIDEOPER | UMODE_VICTIM); acptr->oflag = 0; remove_oper_snomasks(acptr); RunHook2(HOOKTYPE_LOCAL_OPER, acptr, 0); send_umode_out(acptr, acptr, fLag); } return 0; }
// this is where we handle the MODE command DLLFUNC int f_handle_mode (aClient *cptr, aClient *sptr, aChannel *chptr, char *mbuf, char *pbuf, time_t sendts, int samode) { int plusminus, securecount; char *p; if (f_config_ulinesecureaction == F_NOTHING) return MOD_SUCCESS; plusminus = 1; for (p = mbuf; *p; p++) { if (*p == '+') plusminus = 1; else if (*p == '-') plusminus = -1; else if (*p == 'z' && plusminus == 1 && (IsServer(sptr) || IsULine(sptr))) { securecount = f_count_secure_users(chptr); if (securecount < chptr->users) { sendto_snomask(SNO_EYES, "*** Uline %s set mode +z on %s: removing insecure users.", sptr->name, chptr->chname ); if (f_config_ulinesecureaction == F_KICK || securecount > 0) kick_insecure_users(chptr); else f_part_insecure_users(chptr); } } } return MOD_SUCCESS; }
/* show_servers * replies to stats v requests */ static void show_servers(aClient *cptr, char *name) { aClient *cptr2; DLink *lp; int j = 0; for (lp = server_list; lp; lp = lp->next) { cptr2 = lp->value.cptr; #ifdef HIDEULINEDSERVS if(IsULine(cptr2) && !IsAnOper(cptr)) continue; #endif j++; sendto_one(cptr, ":%s %d %s :%s (%s!%s@%s) Idle: %ld", me.name, RPL_STATSDEBUG, name, cptr2->name, (cptr2->serv->bynick[0] ? cptr2->serv->bynick : "Remote."), (cptr2->serv->byuser[0] ? cptr2->serv->byuser : "******"), (cptr2->serv->byhost[0] ? cptr2->serv->byhost : "*"), (long)(timeofday - cptr2->lasttime)); } sendto_one(cptr, ":%s %d %s :%d Server%s", me.name, RPL_STATSDEBUG, name, j, (j == 1) ? "" : "s"); }
DLLFUNC char *privdeaf_checkmsg(aClient *cptr, aClient *sptr, aClient *acptr, char *text, int notice) { if ((acptr->umodes & UMODE_PRIVDEAF) && !IsAnOper(sptr) && !IsULine(sptr) && !IsServer(sptr)) { sendnotice(sptr, "Message to '%s' has not been sent. The user has +D set. This blocks private messages.", acptr->name); return NULL; } else return text; }
DLLFUNC char *privdeaf_checkmsg(aClient *cptr, aClient *sptr, aClient *acptr, char *text, int notice) { if ((acptr->umodes & UMODE_PRIVDEAF) && !IsAnOper(sptr) && !IsULine(sptr) && !IsServer(sptr)) { sendnotice(sptr, "Message to '%s' not delivered: User does not accept private messages", acptr->name); return NULL; } else return text; }
char *nocolor_pre_usermsg(aClient *sptr, aClient *acptr, char *text, int notice) { if (IsULine(sptr) || IsServer(sptr)) return text; if (acptr->umodes & UMODE_STRIPCOLOR) return StripColors(text); return text; }
DLLFUNC char *restrictcolors_checkmsg(aClient *cptr, aClient *sptr, aChannel *chptr, char *text, int notice) { if (IsULine(sptr) || IsServer(sptr)) return text; if (chptr->mode.extmode && RESTRICT_COLORS && !is_chan_op(sptr, chptr) && !is_halfop(sptr, chptr)) return StripColors(text); return text; }
int sendmodeto_one(aClient *cptr, char *from, char *name, char *mode, char *param, TS creationtime) { if ((IsServer(cptr) && DoesOp(mode) && creationtime) || IsULine(cptr)) sendto_one(cptr, ":%s MODE %s %s %s %lu", from, name, mode, param, creationtime); else sendto_one(cptr, ":%s MODE %s %s %s", from, name, mode, param); return 0; }
char *h_nocodes_chanmsg(aClient *cptr, aClient *sptr, aChannel *acptr, char *text, int notice) { static char retbuf[4096]; if (IsULine(sptr) || IsServer(sptr)) { return text; } if (IsNoCodes(acptr)) { strncpyzt(retbuf, StripControlCodes(text), sizeof(retbuf)); return retbuf; } else { return text; } }
static void send_who_reply(aClient *sptr, aClient *acptr, char *channel, char *status, char *xstat) { char *stat; char *host; int flat = (FLAT_MAP && !IsAnOper(sptr)) ? 1 : 0; stat = malloc(strlen(status) + strlen(xstat) + 1); sprintf(stat, "%s%s", status, xstat); if (IsAnOper(sptr)) { if (who_flags & WF_REALHOST) host = acptr->user->realhost; else if (who_flags & WF_IP) host = (acptr->user->ip_str ? acptr->user->ip_str : acptr->user->realhost); else host = GetHost(acptr); } else host = GetHost(acptr); if (IsULine(acptr) && !IsOper(sptr) && HIDE_ULINES) sendto_one(sptr, getreply(RPL_WHOREPLY), me.name, sptr->name, channel, /* channel name */ acptr->user->username, /* user name */ host, /* hostname */ "hidden", /* let's hide the server from normal users if the server is a uline and HIDE_ULINES is on */ acptr->name, /* nick */ stat, /* status */ 0, /* hops (hidden) */ acptr->info /* realname */ ); else sendto_one(sptr, getreply(RPL_WHOREPLY), me.name, sptr->name, channel, /* channel name */ acptr->user->username, /* user name */ host, /* hostname */ acptr->user->server, /* server name */ acptr->name, /* nick */ stat, /* status */ flat ? 0 : acptr->hopcount, /* hops */ acptr->info /* realname */ ); free(stat); }
/* ** m_svsnick ** parv[0] = sender ** parv[1] = old nickname ** parv[2] = new nickname ** parv[3] = timestamp */ int m_svsnick(aClient *cptr, aClient *sptr, int parc, char *parv[]) { aClient *acptr; aClient *ocptr; /* Other client */ if (!IsULine(sptr) || parc < 4 || (strlen(parv[2]) > NICKLEN)) return -1; /* This looks like an error anyway -Studded */ if (hunt_server_token(cptr, sptr, MSG_SVSNICK, TOK_SVSNICK, "%s %s :%s", 1, parc, parv) != HUNTED_ISME) return 0; /* Forwarded, done */ if (do_nick_name(parv[2]) == 0) return 0; if (!(acptr = find_person(parv[1], NULL))) return 0; /* User not found, bail out */ if ((ocptr = find_client(parv[2], NULL)) && ocptr != acptr) /* Collision */ { exit_client(acptr, acptr, sptr, "Nickname collision due to Services enforced " "nickname change, your nick was overruled"); return 0; } if (acptr != ocptr) acptr->umodes &= ~UMODE_REGNICK; acptr->lastnick = TS2ts(parv[3]); sendto_common_channels(acptr, ":%s NICK :%s", parv[1], parv[2]); add_history(acptr, 1); sendto_serv_butone_token(NULL, parv[1], MSG_NICK, TOK_NICK, "%s :%ld", parv[2], TS2ts(parv[3])); (void)del_from_client_hash_table(acptr->name, acptr); hash_check_watch(acptr, RPL_LOGOFF); sendto_snomask(SNO_NICKCHANGE, "*** Notice -- %s (%s@%s) has been forced to change his/her nickname to %s", acptr->name, acptr->user->username, acptr->user->realhost, parv[2]); RunHook2(HOOKTYPE_LOCAL_NICKCHANGE, acptr, parv[2]); strlcpy(acptr->name, parv[2], sizeof acptr->name); add_to_client_hash_table(parv[2], acptr); hash_check_watch(acptr, RPL_LOGON); return 0; }
int m_svsnoop(aClient *cptr, aClient *sptr, int parc, char *parv[]) { aClient *acptr; if (!(IsULine(sptr) && parc > 2)) return 0; /* svsnoop bugfix --binary */ if (hunt_server_token(cptr, sptr, MSG_SVSNOOP, TOK_SVSNOOP, "%s :%s", 1, parc, parv) == HUNTED_ISME) { if (parv[2][0] == '+') { SVSNOOP = 1; sendto_ops("This server has been placed in NOOP mode"); for (acptr = &me; acptr; acptr = acptr->prev) { if (MyClient(acptr) && IsAnOper(acptr)) { if (IsOper(acptr)) { IRCstats.operators--; VERIFY_OPERCOUNT(acptr, "svsnoop"); } if (IsAnOper(acptr)) delfrom_fdlist(acptr->slot, &oper_fdlist); if (IsTotalInvis(acptr)) { sendto_channels_inviso_join(acptr); } acptr->umodes &= ~(UMODE_OPER|UMODE_HELPOP|UMODE_SADMIN|UMODE_ADMIN|UMODE_LOCOP|UMODE_SERVICES|UMODE_NETADMIN); acptr->umodes &= ~(UMODE_WHOIS|UMODE_KIX|UMODE_HIDEOPER|UMODE_HIDEWHOIS|UMODE_TOTALINVIS|UMODE_MODEWALK|UMODE_NOFAKELAG); acptr->oflag = 0; remove_oper_snomasks(acptr); sendto_one(acptr, ":%s NOTICE %s :*** Your OFLAGS have been cleared, because this server has been placed in NOOP mode", me.name, acptr->name); RunHook2(HOOKTYPE_LOCAL_OPER, acptr, 0); } } } else { SVSNOOP = 0; sendto_ops("This server is no longer in NOOP mode"); } } return 0; }
/* ** m_svslusers ** parv[0] = sender ** parv[1] = server to update ** parv[2] = max global users ** parv[3] = max local users ** If -1 is specified for either number, it is ignored and the current count ** is kept. */ int m_svslusers(aClient *cptr, aClient *sptr, int parc, char *parv[]) { if (!IsULine(sptr) || parc < 4) return -1; if (hunt_server_token(cptr, sptr, MSG_SVSLUSERS, TOK_SVSLUSERS, "%s %s :%s", 1, parc, parv) == HUNTED_ISME) { int temp; temp = atoi(parv[2]); if (temp >= 0) IRCstats.global_max = temp; temp = atoi(parv[3]); if (temp >= 0) IRCstats.me_max = temp; } return 0; }
/* ** m_sanick() - PID - 08-08-2011 ** ** parv[0] - sender ** parv[1] - nick to make join ** parv[2] - channel(s) to join */ int m_sanick(aClient * cptr, aClient * sptr, int parc, char *parv[]) { aClient *acptr; char *param[3]; int self = 0; // if (IsServer(sptr) || IsServices(sptr)) // return 0; //Servers and Services should be invoking SVSNICK directly... if (!IsOper(sptr) && !IsAdmin(sptr) && !IsULine(sptr)) { sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } if (parv[1] == NULL || !parv[1] || !parv[2]) { sendnotice(sptr, "*** Usage: \2/sanick oldnick newnick\2"); return 0; } if (parv[2] == NULL || !(acptr = find_person(parv[1], NULL))) { sendnotice(sptr, "*** No such user, %s.", parv[1]); return 0; } if (!strcmp(parv[2], parv[1]) || !strcmp(parv[2], parv[0])) { sendnotice(sptr, "*** Perhaps I should warn people that they have given an idiot IRCOp access?"); return 0; } if (!strcmp(parv[0], parv[1])) self = 1; if (find_client(parv[2], NULL)) { sendnotice(sptr, "*** WARNING: User %s already exists!", parv[2]); return 0; } if(acptr->umodes & UMODE_REGNICK) acptr->umodes &= ~UMODE_REGNICK; param[0] = acptr->name; param[1] = parv[2]; param[2] = NULL; sendnotice(acptr, "*** You were forced to change your nick to %s", parv[2]); do_cmd(acptr, acptr, "NICK", 2, param); if(self) { sendto_realops("%s used \2SANICK\2 to change their nick to %s.", parv[1], parv[2]); ircd_log(LOG_SACMDS,"SANICK: %s used SANICK to change their nick to %s", parv[1], parv[2]); } else { sendto_realops("%s used \2SANICK\2 to make %s change their nick to %s.", parv[0], parv[1], parv[2]); ircd_log(LOG_SACMDS,"SANICK: %s used SANICK to make %s change their nick to %s", acptr->name, parv[1], parv[2]); } return 0; }
int channel_canjoin(aClient *sptr, char *name) { ConfigItem_deny_channel *p; if (IsOper(sptr)) return 1; if (IsULine(sptr)) return 1; if (!conf_deny_channel) return 1; p = Find_channel_allowed(name); if (p) { sendto_one(sptr, ":%s NOTICE %s :*** %s", me.name, sptr->name, p->reason); return 0; } return 1; }
/** Kicks all insecure users on a +z channel */ static void secureonly_kick_insecure_users(aChannel *chptr) { Member *member, *mb2; aClient *cptr; int i = 0; Hook *h; char *comment = "Insecure user not allowed on secure channel (+z)"; if (!IsSecureOnly(chptr)) return; for (member = chptr->members; member; member = mb2) { mb2 = member->next; cptr = member->cptr; if (MyClient(cptr) && !IsSecureConnect(cptr) && !IsULine(cptr)) { RunHook5(HOOKTYPE_LOCAL_KICK, &me, &me, cptr, chptr, comment); i = 0; for (h = Hooks[HOOKTYPE_VISIBLE_IN_CHANNEL]; h; h = h->next) { i = (*(h->func.intfunc))(cptr,chptr); if (i != 0) break; } if (i != 0 && !(is_skochanop(cptr, chptr) || has_voice(cptr,chptr))) { sendto_chanops_butone(cptr, chptr, ":%s KICK %s %s :%s", me.name, chptr->chname, cptr->name, comment); sendto_prefix_one(cptr, &me, ":%s KICK %s %s :%s", me.name, chptr->chname, cptr->name, comment); } else { sendto_channel_butserv(chptr, &me, ":%s KICK %s %s :%s", me.name, chptr->chname, cptr->name, comment); } sendto_server(&me, 0, 0, ":%s KICK %s %s :%s", me.name, chptr->chname, cptr->name, comment); remove_user_from_channel(cptr, chptr); } } }
void exit_server(aClient *lcptr, aClient *cptr, aClient *from, char *comment) { char splitname[HOSTLEN + HOSTLEN + 2]; #ifdef HIDE_SPLIT_SERVERS ircsprintf(splitname, "%s %s", HIDDEN_SERVER_NAME, HIDDEN_SERVER_NAME); #else /* Don't show uplink servers for a u:lined link! */ if(IsULine(cptr)) ircsprintf(splitname, "%s %s", cptr->name, cptr->name); else ircsprintf(splitname, "%s %s", cptr->uplink->name, cptr->name); #endif Debug((DEBUG_NOTICE, "exit_server(%s, %s, %s)", cptr->name, from->name, comment)); exit_one_server(cptr, cptr, from, lcptr, splitname, comment); }
int nokick_can_kick(aClient *sptr, aClient *target, aChannel *chptr, char *comment, long sptr_flags, long target_flags, char **reject_reason) { static char errmsg[NICKLEN+256]; if (IsNokick(target) && !IsULine(sptr) && MyClient(sptr) && !ValidatePermissionsForPath("override:kick:nokick",sptr,target,chptr,NULL)) { ircsnprintf(errmsg, sizeof(errmsg), err_str(ERR_CANNOTDOCOMMAND), me.name, sptr->name, "KICK", "user is unkickable (user mode +q)"); *reject_reason = errmsg; sendnotice(target, "*** umode q: %s tried to kick you from channel %s (%s)", sptr->name, chptr->chname, comment); return EX_ALWAYS_DENY; } return EX_ALLOW; }
int channel_canjoin(aClient *sptr, char *name) { ConfigItem_deny_channel *p; aTKline *tklban; int ishold; if (!ValidatePermissionsForPath("channel:restricted",sptr,NULL,NULL,name)) return 1; if (IsULine(sptr)) return 1; if (!conf_deny_channel) return 1; p = Find_channel_allowed(sptr, name); if (p) { sendto_one(sptr, err_str(ERR_FORBIDDENCHANNEL), me.name, sptr->name, name, p->reason); return 0; } if ((tklban = find_qline(sptr, name, &ishold))) { sendto_one(sptr, err_str(ERR_FORBIDDENCHANNEL), me.name, sptr->name, name, tklban->reason); return 0; } return 1; }
DLLFUNC int m_rmtkl(aClient *cptr, aClient *sptr, int parc, char *parv[]) { aTKline *tk, *next = NULL; TKLType *tkltype; char *types, *uhmask, *cmask, *p; char gmt[256], flag; int tklindex; if (!IsULine(sptr) && !(IsPerson(sptr) && IsAnOper(sptr))) { sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); return -1; } if (IsNotParam(1)) return dumpit(sptr, rmtkl_help); if (IsNotParam(2)) { sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "RMTKL"); sendnotice(sptr, "Type '/RMTKL' for help"); return 0; } types = parv[1]; uhmask = parv[2]; cmask = IsParam(3) ? parv[3] : NULL; /* I don't add 'q' and 'Q' here. They are different. */ if (strchr(types, '*')) types = "KzGZs"; /* check access */ if (!IsULine(sptr)) for (p = types; *p; p++) { tkltype = find_TKLType_by_flag(*p); if (!tkltype->type) continue; if (((tkltype->type & TKL_GLOBAL) && !IsOper(sptr)) || !(sptr->oflag & tkltype->oflag)) { sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); return -1; } } for (tkltype = tkl_types; tkltype->type; tkltype++) { flag = tkltype->flag; tklindex = tkl_hash(flag); if (!strchr(types, flag)) continue; for (tk = tklines[tklindex]; tk; tk = next) { next = tk->next; if (tk->type != tkltype->type) continue; if (tk->type & TKL_NICK) { /* * If it's a services hold (ie. NickServ is holding * a nick), it's better not to touch it */ if (*tk->usermask == 'H') continue; if (match(uhmask, tk->hostmask)) continue; } else if (match(uhmask, make_user_host(tk->usermask, tk->hostmask))) continue; if (cmask && _match(cmask, tk->reason)) continue; strncpyzt(gmt, asctime(gmtime((TS *)&tk->set_at)), sizeof gmt); iCstrip(gmt); if (tk->type & TKL_NICK) { sendto_snomask(SNO_TKL, "%s removed %s %s (set at %s " "- reason: %s)", sptr->name, tkltype->txt, tk->hostmask, gmt, tk->reason); ircd_log(LOG_TKL, "%s removed %s %s (set at %s " "- reason: %s)", sptr->name, tkltype->txt, tk->hostmask, gmt, tk->reason); } else { sendto_snomask(SNO_TKL, "%s removed %s %s@%s (set at " "%s - reason: %s)", sptr->name, tkltype->txt, tk->usermask, tk->hostmask, gmt, tk->reason); ircd_log(LOG_TKL, "%s removed %s %s@%s (set at " "%s - reason: %s)", sptr->name, tkltype->txt, tk->usermask, tk->hostmask, gmt, tk->reason); } if ((tk->type & TKL_GLOBAL) && flag) sendto_serv_butone_token(&me, me.name, MSG_TKL, TOK_TKL, "- %c %s %s %s", flag, tk->usermask, tk->hostmask, parv[0]); if (tk->type & TKL_SHUN) tkl_check_local_remove_shun(tk); my_tkl_del_line(tk, tklindex); } } return 0; }
/* ** m_nick ** parv[0] = sender prefix ** parv[1] = nickname ** if from new client -taz ** parv[2] = nick password ** if from server: ** parv[2] = hopcount ** parv[3] = timestamp ** parv[4] = username ** parv[5] = hostname ** parv[6] = servername ** if NICK version 1: ** parv[7] = servicestamp ** parv[8] = info ** if NICK version 2: ** parv[7] = servicestamp ** parv[8] = umodes ** parv[9] = virthost, * if none ** parv[10] = info ** if NICKIP: ** parv[10] = ip ** parv[11] = info */ DLLFUNC CMD_FUNC(m_nick) { aTKline *tklban; int ishold; aClient *acptr, *serv = NULL; aClient *acptrs; char nick[NICKLEN + 2], *s; Membership *mp; time_t lastnick = (time_t) 0; int differ = 1, update_watch = 1; unsigned char newusr = 0, removemoder = 1; /* * If the user didn't specify a nickname, complain */ if (parc < 2) { sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN), me.name, parv[0]); return 0; } strncpyzt(nick, parv[1], NICKLEN + 1); if (MyConnect(sptr) && sptr->user && !IsAnOper(sptr)) { if ((sptr->user->flood.nick_c >= NICK_COUNT) && (TStime() - sptr->user->flood.nick_t < NICK_PERIOD)) { /* Throttle... */ sendto_one(sptr, err_str(ERR_NCHANGETOOFAST), me.name, sptr->name, nick, (int)(NICK_PERIOD - (TStime() - sptr->user->flood.nick_t))); return 0; } } /* For a local clients, do proper nickname checking via do_nick_name() * and reject the nick if it returns false. * For remote clients, do a quick check by using do_remote_nick_name(), * if this returned false then reject and kill it. -- Syzop */ if ((IsServer(cptr) && !do_remote_nick_name(nick)) || (!IsServer(cptr) && !do_nick_name(nick))) { sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME), me.name, parv[0], parv[1], "Illegal characters"); if (IsServer(cptr)) { ircstp->is_kill++; sendto_failops("Bad Nick: %s From: %s %s", parv[1], parv[0], get_client_name(cptr, FALSE)); sendto_one(cptr, ":%s KILL %s :%s (%s <- %s[%s])", me.name, parv[1], me.name, parv[1], nick, cptr->name); if (sptr != cptr) { /* bad nick change */ sendto_serv_butone(cptr, ":%s KILL %s :%s (%s <- %s!%s@%s)", me.name, parv[0], me.name, get_client_name(cptr, FALSE), parv[0], sptr->user ? sptr->username : "", sptr->user ? sptr->user->server : cptr->name); sptr->flags |= FLAGS_KILLED; return exit_client(cptr, sptr, &me, "BadNick"); } } return 0; } /* Kill quarantined opers early... */ if (IsServer(cptr) && (sptr->from->flags & FLAGS_QUARANTINE) && (parc >= 11) && strchr(parv[8], 'o')) { ircstp->is_kill++; /* Send kill to uplink only, hasn't been broadcasted to the rest, anyway */ sendto_one(cptr, ":%s KILL %s :%s (Quarantined: no global oper privileges allowed)", me.name, parv[1], me.name); sendto_realops("QUARANTINE: Oper %s on server %s killed, due to quarantine", parv[1], sptr->name); /* (nothing to exit_client or to free, since user was never added) */ return 0; } /* ** Protocol 4 doesn't send the server as prefix, so it is possible ** the server doesn't exist (a lagged net.burst), in which case ** we simply need to ignore the NICK. Also when we got that server ** name (again) but from another direction. --Run */ /* ** We should really only deal with this for msgs from servers. ** -- Aeto */ if (IsServer(cptr) && (parc > 7 && (!(serv = (aClient *)find_server_b64_or_real(parv[6])) || serv->from != cptr->from))) { sendto_realops("Cannot find server %s (%s)", parv[6], backupbuf); return 0; } /* ** Check against nick name collisions. ** ** Put this 'if' here so that the nesting goes nicely on the screen :) ** We check against server name list before determining if the nickname ** is present in the nicklist (due to the way the below for loop is ** constructed). -avalon */ /* I managed to f**k this up i guess --stskeeps */ if ((acptr = find_server(nick, NULL))) { if (MyConnect(sptr)) { #ifdef GUEST if (IsUnknown(sptr)) { RunHook4(HOOKTYPE_GUEST, cptr, sptr, parc, parv); return 0; } #endif sendto_one(sptr, err_str(ERR_NICKNAMEINUSE), me.name, BadPtr(parv[0]) ? "*" : parv[0], nick); return 0; /* NICK message ignored */ } } /* ** Check for a Q-lined nickname. If we find it, and it's our ** client, just reject it. -Lefler ** Allow opers to use Q-lined nicknames. -Russell */ if (!stricmp("ircd", nick)) { sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME), me.name, BadPtr(parv[0]) ? "*" : parv[0], nick, "Reserved for internal IRCd purposes"); return 0; } if (!stricmp("irc", nick)) { sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME), me.name, BadPtr(parv[0]) ? "*" : parv[0], nick, "Reserved for internal IRCd purposes"); return 0; } if (MyClient(sptr)) /* local client changin nick afterwards.. */ { int xx; spamfilter_build_user_string(spamfilter_user, nick, sptr); xx = dospamfilter(sptr, spamfilter_user, SPAMF_USER, NULL, 0, NULL); if (xx < 0) return xx; } if (!IsULine(sptr) && (tklban = find_qline(sptr, nick, &ishold))) { if (IsServer(sptr) && !ishold) /* server introducing new client */ { acptrs = (aClient *)find_server_b64_or_real(sptr->user == NULL ? (char *)parv[6] : (char *)sptr->user-> server); /* (NEW: no unregistered q:line msgs anymore during linking) */ if (!acptrs || (acptrs->serv && acptrs->serv->flags.synced)) sendto_snomask(SNO_QLINE, "Q:lined nick %s from %s on %s", nick, (*sptr->name != 0 && !IsServer(sptr) ? sptr->name : "<unregistered>"), acptrs ? acptrs->name : "unknown server"); } if (IsServer(cptr) && IsPerson(sptr) && !ishold) /* remote user changing nick */ { sendto_snomask(SNO_QLINE, "Q:lined nick %s from %s on %s", nick, sptr->name, sptr->srvptr ? sptr->srvptr->name : "<unknown>"); } if (!IsServer(cptr)) /* local */ { if (ishold) { sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME), me.name, BadPtr(parv[0]) ? "*" : parv[0], nick, tklban->reason); return 0; } if (!IsOper(cptr)) { sptr->since += 4; /* lag them up */ sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME), me.name, BadPtr(parv[0]) ? "*" : parv[0], nick, tklban->reason); sendto_snomask(SNO_QLINE, "Forbidding Q-lined nick %s from %s.", nick, get_client_name(cptr, FALSE)); return 0; /* NICK message ignored */ } } } /* ** acptr already has result from previous find_server() */ if (acptr) { /* ** We have a nickname trying to use the same name as ** a server. Send out a nick collision KILL to remove ** the nickname. As long as only a KILL is sent out, ** there is no danger of the server being disconnected. ** Ultimate way to jupiter a nick ? >;-). -avalon */ sendto_failops("Nick collision on %s(%s <- %s)", sptr->name, acptr->from->name, get_client_name(cptr, FALSE)); ircstp->is_kill++; sendto_one(cptr, ":%s KILL %s :%s (%s <- %s)", me.name, sptr->name, me.name, acptr->from->name, /* NOTE: Cannot use get_client_name ** twice here, it returns static ** string pointer--the other info ** would be lost */ get_client_name(cptr, FALSE)); sptr->flags |= FLAGS_KILLED; return exit_client(cptr, sptr, &me, "Nick/Server collision"); } if (MyClient(cptr) && !IsOper(cptr)) cptr->since += 3; /* Nick-flood prot. -Donwulff */ if (!(acptr = find_client(nick, NULL))) goto nickkilldone; /* No collisions, all clear... */ /* ** If the older one is "non-person", the new entry is just ** allowed to overwrite it. Just silently drop non-person, ** and proceed with the nick. This should take care of the ** "dormant nick" way of generating collisions... */ /* Moved before Lost User Field to fix some bugs... -- Barubary */ if (IsUnknown(acptr) && MyConnect(acptr)) { /* This may help - copying code below */ if (acptr == cptr) return 0; acptr->flags |= FLAGS_KILLED; exit_client(NULL, acptr, &me, "Overridden"); goto nickkilldone; } /* A sanity check in the user field... */ if (acptr->user == NULL) { /* This is a Bad Thing */ sendto_failops("Lost user field for %s in change from %s", acptr->name, get_client_name(cptr, FALSE)); ircstp->is_kill++; sendto_one(acptr, ":%s KILL %s :%s (Lost user field!)", me.name, acptr->name, me.name); acptr->flags |= FLAGS_KILLED; /* Here's the previous versions' desynch. If the old one is messed up, trash the old one and accept the new one. Remember - at this point there is a new nick coming in! Handle appropriately. -- Barubary */ exit_client(NULL, acptr, &me, "Lost user field"); goto nickkilldone; } /* ** If acptr == sptr, then we have a client doing a nick ** change between *equivalent* nicknames as far as server ** is concerned (user is changing the case of his/her ** nickname or somesuch) */ if (acptr == sptr) { if (strcmp(acptr->name, nick) != 0) { /* Allows change of case in his/her nick */ removemoder = 0; /* don't set the user -r */ goto nickkilldone; /* -- go and process change */ } else /* ** This is just ':old NICK old' type thing. ** Just forget the whole thing here. There is ** no point forwarding it to anywhere, ** especially since servers prior to this ** version would treat it as nick collision. */ return 0; /* NICK Message ignored */ } /* ** Note: From this point forward it can be assumed that ** acptr != sptr (point to different client structures). */ /* ** Decide, we really have a nick collision and deal with it */ if (!IsServer(cptr)) { /* ** NICK is coming from local client connection. Just ** send error reply and ignore the command. */ #ifdef GUEST if (IsUnknown(sptr)) { RunHook4(HOOKTYPE_GUEST, cptr, sptr, parc, parv); return 0; } #endif sendto_one(sptr, err_str(ERR_NICKNAMEINUSE), /* parv[0] is empty when connecting */ me.name, BadPtr(parv[0]) ? "*" : parv[0], nick); return 0; /* NICK message ignored */ } /* ** NICK was coming from a server connection. ** This means we have a race condition (two users signing on ** at the same time), or two net fragments reconnecting with ** the same nick. ** The latter can happen because two different users connected ** or because one and the same user switched server during a ** net break. ** If we have the old protocol (no TimeStamp and no user@host) ** or if the TimeStamps are equal, we kill both (or only 'new' ** if it was a "NICK new"). Otherwise we kill the youngest ** when user@host differ, or the oldest when they are the same. ** --Run ** */ if (IsServer(sptr)) { /* ** A new NICK being introduced by a neighbouring ** server (e.g. message type "NICK new" received) */ if (parc > 3) { lastnick = TS2ts(parv[3]); if (parc > 5) differ = (mycmp(acptr->user->username, parv[4]) || mycmp(acptr->user->realhost, parv[5])); } sendto_failops("Nick collision on %s (%s %ld <- %s %ld)", acptr->name, acptr->from->name, acptr->lastnick, cptr->name, lastnick); /* ** I'm putting the KILL handling here just to make it easier ** to read, it's hard to follow it the way it used to be. ** Basically, this is what it will do. It will kill both ** users if no timestamp is given, or they are equal. It will ** kill the user on our side if the other server is "correct" ** (user@host differ and their user is older, or user@host are ** the same and their user is younger), otherwise just kill the ** user an reintroduce our correct user. ** The old code just sat there and "hoped" the other server ** would kill their user. Not anymore. ** -- binary */ if (!(parc > 3) || (acptr->lastnick == lastnick)) { ircstp->is_kill++; sendto_serv_butone(NULL, ":%s KILL %s :%s (Nick Collision)", me.name, acptr->name, me.name); acptr->flags |= FLAGS_KILLED; (void)exit_client(NULL, acptr, &me, "Nick collision with no timestamp/equal timestamps"); return 0; /* We killed both users, now stop the process. */ } if ((differ && (acptr->lastnick > lastnick)) || (!differ && (acptr->lastnick < lastnick)) || acptr->from == cptr) /* we missed a QUIT somewhere ? */ { ircstp->is_kill++; sendto_serv_butone(cptr, ":%s KILL %s :%s (Nick Collision)", me.name, acptr->name, me.name); acptr->flags |= FLAGS_KILLED; (void)exit_client(NULL, acptr, &me, "Nick collision"); goto nickkilldone; /* OK, we got rid of the "wrong" user, ** now we're going to add the user the ** other server introduced. */ } if ((differ && (acptr->lastnick < lastnick)) || (!differ && (acptr->lastnick > lastnick))) { /* * Introduce our "correct" user to the other server */ sendto_one(cptr, ":%s KILL %s :%s (Nick Collision)", me.name, parv[1], me.name); send_umode(NULL, acptr, 0, SEND_UMODES, buf); sendto_one_nickcmd(cptr, acptr, buf); if (acptr->user->away) sendto_one(cptr, ":%s AWAY :%s", acptr->name, acptr->user->away); send_user_joins(cptr, acptr); return 0; /* Ignore the NICK */ } return 0; } else { /* ** A NICK change has collided (e.g. message type ":old NICK new"). */ if (parc > 2) lastnick = TS2ts(parv[2]); differ = (mycmp(acptr->user->username, sptr->user->username) || mycmp(acptr->user->realhost, sptr->user->realhost)); sendto_failops ("Nick change collision from %s to %s (%s %ld <- %s %ld)", sptr->name, acptr->name, acptr->from->name, acptr->lastnick, sptr->from->name, lastnick); if (!(parc > 2) || lastnick == acptr->lastnick) { ircstp->is_kill += 2; sendto_serv_butone(NULL, /* First kill the new nick. */ ":%s KILL %s :%s (Self Collision)", me.name, acptr->name, me.name); sendto_serv_butone(cptr, /* Tell my servers to kill the old */ ":%s KILL %s :%s (Self Collision)", me.name, sptr->name, me.name); sptr->flags |= FLAGS_KILLED; acptr->flags |= FLAGS_KILLED; (void)exit_client(NULL, sptr, &me, "Self Collision"); (void)exit_client(NULL, acptr, &me, "Self Collision"); return 0; /* Now that I killed them both, ignore the NICK */ } if ((differ && (acptr->lastnick > lastnick)) || (!differ && (acptr->lastnick < lastnick))) { /* sptr (their user) won, let's kill acptr (our user) */ ircstp->is_kill++; sendto_serv_butone(cptr, ":%s KILL %s :%s (Nick collision: %s <- %s)", me.name, acptr->name, me.name, acptr->from->name, sptr->from->name); acptr->flags |= FLAGS_KILLED; (void)exit_client(NULL, acptr, &me, "Nick collision"); goto nickkilldone; /* their user won, introduce new nick */ } if ((differ && (acptr->lastnick < lastnick)) || (!differ && (acptr->lastnick > lastnick))) { /* acptr (our user) won, let's kill sptr (their user), ** and reintroduce our "correct" user */ ircstp->is_kill++; /* Kill the user trying to change their nick. */ sendto_serv_butone(cptr, ":%s KILL %s :%s (Nick collision: %s <- %s)", me.name, sptr->name, me.name, sptr->from->name, acptr->from->name); sptr->flags |= FLAGS_KILLED; (void)exit_client(NULL, sptr, &me, "Nick collision"); /* * Introduce our "correct" user to the other server */ /* Kill their user. */ sendto_one(cptr, ":%s KILL %s :%s (Nick Collision)", me.name, parv[1], me.name); send_umode(NULL, acptr, 0, SEND_UMODES, buf); sendto_one_nickcmd(cptr, acptr, buf); if (acptr->user->away) sendto_one(cptr, ":%s AWAY :%s", acptr->name, acptr->user->away); send_user_joins(cptr, acptr); return 0; /* their user lost, ignore the NICK */ } } return 0; /* just in case */ nickkilldone: if (IsServer(sptr)) { /* A server introducing a new client, change source */ sptr = make_client(cptr, serv); add_client_to_list(sptr); if (parc > 2) sptr->hopcount = TS2ts(parv[2]); if (parc > 3) sptr->lastnick = TS2ts(parv[3]); else /* Little bit better, as long as not all upgraded */ sptr->lastnick = TStime(); if (sptr->lastnick < 0) { sendto_realops ("Negative timestamp recieved from %s, resetting to TStime (%s)", cptr->name, backupbuf); sptr->lastnick = TStime(); } newusr = 1; } else if (sptr->name[0] && IsPerson(sptr)) { /* ** If the client belongs to me, then check to see ** if client is currently on any channels where it ** is currently banned. If so, do not allow the nick ** change to occur. ** Also set 'lastnick' to current time, if changed. */ if (MyClient(sptr)) { for (mp = sptr->user->channel; mp; mp = mp->next) { if (!is_skochanop(sptr, mp->chptr) && is_banned(sptr, mp->chptr, BANCHK_NICK)) { sendto_one(sptr, err_str(ERR_BANNICKCHANGE), me.name, parv[0], mp->chptr->chname); return 0; } if (CHECK_TARGET_NICK_BANS && !is_skochanop(sptr, mp->chptr) && is_banned_with_nick(sptr, mp->chptr, BANCHK_NICK, nick)) { sendto_one(sptr, ":%s 437 %s %s :Cannot change to a nickname banned on channel", me.name, parv[0], mp->chptr->chname); return 0; } if (!IsOper(sptr) && !IsULine(sptr) && mp->chptr->mode.mode & MODE_NONICKCHANGE && !is_chanownprotop(sptr, mp->chptr)) { sendto_one(sptr, err_str(ERR_NONICKCHANGE), me.name, parv[0], mp->chptr->chname); return 0; } } if (TStime() - sptr->user->flood.nick_t >= NICK_PERIOD) { sptr->user->flood.nick_t = TStime(); sptr->user->flood.nick_c = 1; } else sptr->user->flood.nick_c++; sendto_snomask(SNO_NICKCHANGE, "*** Notice -- %s (%s@%s) has changed his/her nickname to %s", sptr->name, sptr->user->username, sptr->user->realhost, nick); RunHook2(HOOKTYPE_LOCAL_NICKCHANGE, sptr, nick); } else { if (!IsULine(sptr)) sendto_snomask(SNO_FNICKCHANGE, "*** Notice -- %s (%s@%s) has changed his/her nickname to %s", sptr->name, sptr->user->username, sptr->user->realhost, nick); RunHook3(HOOKTYPE_REMOTE_NICKCHANGE, cptr, sptr, nick); } /* * Client just changing his/her nick. If he/she is * on a channel, send note of change to all clients * on that channel. Propagate notice to other servers. */ if (mycmp(parv[0], nick) || /* Next line can be removed when all upgraded --Run */ (!MyClient(sptr) && parc > 2 && TS2ts(parv[2]) < sptr->lastnick)) sptr->lastnick = (MyClient(sptr) || parc < 3) ? TStime() : TS2ts(parv[2]); if (sptr->lastnick < 0) { sendto_realops("Negative timestamp (%s)", backupbuf); sptr->lastnick = TStime(); } add_history(sptr, 1); sendto_common_channels(sptr, ":%s NICK :%s", parv[0], nick); sendto_serv_butone_token(cptr, parv[0], MSG_NICK, TOK_NICK, "%s %ld", nick, sptr->lastnick); if (removemoder) sptr->umodes &= ~UMODE_REGNICK; } else if (!sptr->name[0]) { #ifdef NOSPOOF /* * Client setting NICK the first time. * * Generate a random string for them to pong with. */ sptr->nospoof = getrandom32(); if (PINGPONG_WARNING) sendto_one(sptr, ":%s NOTICE %s :*** If you are having problems" " connecting due to ping timeouts, please" " type /quote pong %X or /raw pong %X now.", me.name, nick, sptr->nospoof, sptr->nospoof); sendto_one(sptr, "PING :%X", sptr->nospoof); #endif /* NOSPOOF */ #ifdef CONTACT_EMAIL sendto_one(sptr, ":%s NOTICE %s :*** If you need assistance with a" " connection problem, please email " CONTACT_EMAIL " with the name and version of the client you are" " using, and the server you tried to connect to: %s", me.name, nick, me.name); #endif /* CONTACT_EMAIL */ #ifdef CONTACT_URL sendto_one(sptr, ":%s NOTICE %s :*** If you need assistance with" " connecting to this server, %s, please refer to: " CONTACT_URL, me.name, nick, me.name); #endif /* CONTACT_URL */ /* Copy password to the passwd field if it's given after NICK * - originally by taz, modified by Wizzu */ if ((parc > 2) && (strlen(parv[2]) <= PASSWDLEN) && !(sptr->listener->umodes & LISTENER_JAVACLIENT)) { if (sptr->passwd) MyFree(sptr->passwd); sptr->passwd = MyMalloc(strlen(parv[2]) + 1); (void)strcpy(sptr->passwd, parv[2]); } /* This had to be copied here to avoid problems.. */ (void)strcpy(sptr->name, nick); if (sptr->user && IsNotSpoof(sptr)) { /* ** USER already received, now we have NICK. ** *NOTE* For servers "NICK" *must* precede the ** user message (giving USER before NICK is possible ** only for local client connection!). register_user ** may reject the client and call exit_client for it ** --must test this and exit m_nick too!!! */ #ifndef NOSPOOF if (USE_BAN_VERSION && MyConnect(sptr)) sendto_one(sptr, ":IRC!IRC@%s PRIVMSG %s :\1VERSION\1", me.name, nick); #endif sptr->lastnick = TStime(); /* Always local client */ if (register_user(cptr, sptr, nick, sptr->user->username, NULL, NULL, NULL) == FLUSH_BUFFER) return FLUSH_BUFFER; strcpy(nick, sptr->name); /* don't ask, but I need this. do not remove! -- Syzop */ update_watch = 0; newusr = 1; } } /* * Finally set new nick name. */ if (update_watch && sptr->name[0]) { (void)del_from_client_hash_table(sptr->name, sptr); if (IsPerson(sptr)) hash_check_watch(sptr, RPL_LOGOFF); } (void)strcpy(sptr->name, nick); (void)add_to_client_hash_table(nick, sptr); if (IsServer(cptr) && parc > 7) { parv[3] = nick; do_cmd(cptr, sptr, "USER", parc - 3, &parv[3]); if (GotNetInfo(cptr) && !IsULine(sptr)) sendto_fconnectnotice(sptr->name, sptr->user, sptr, 0, NULL); } else if (IsPerson(sptr) && update_watch) hash_check_watch(sptr, RPL_LOGON); #ifdef NEWCHFLOODPROT if (sptr->user && !newusr && !IsULine(sptr)) { for (mp = sptr->user->channel; mp; mp = mp->next) { aChannel *chptr = mp->chptr; if (chptr && !(mp->flags & (CHFL_CHANOP|CHFL_VOICE|CHFL_CHANOWNER|CHFL_HALFOP|CHFL_CHANPROT)) && chptr->mode.floodprot && do_chanflood(chptr->mode.floodprot, FLD_NICK) && MyClient(sptr)) { do_chanflood_action(chptr, FLD_NICK, "nick"); } } } #endif if (newusr && !MyClient(sptr) && IsPerson(sptr)) { RunHook(HOOKTYPE_REMOTE_CONNECT, sptr); } return 0; }
/* * exit_client * This is old "m_bye". Name changed, because this is not a * protocol function, but a general server utility function. * * This function exits a client of *any* type (user, server, etc) * from this server. Also, this generates all necessary prototol * messages that this exit may cause. * * 1) If the client is a local client, then this implicitly exits * all other clients depending on this connection (e.g. remote * clients having 'from'-field that points to this. * * 2) If the client is a remote client, then only this is exited. * * For convenience, this function returns a suitable value for * m_function return value: * * FLUSH_BUFFER if (cptr == sptr) * 0 if (cptr != sptr) */ int exit_client(aClient *cptr, aClient *sptr, aClient *from, char *comment) { #ifdef FNAME_USERLOG time_t on_for; #endif if (MyConnect(sptr)) { call_hooks(CHOOK_SIGNOFF, sptr); if (IsUnknown(sptr)) Count.unknown--; if (IsAnOper(sptr)) remove_from_list(&oper_list, sptr, NULL); if (sptr->flags & FLAGS_HAVERECVQ) { /* mark invalid, will be deleted in do_recvqs() */ DLink *lp = find_dlink(recvq_clients, sptr); if (lp) lp->flags = -1; } if (IsClient(sptr)) Count.local--; if (IsNegoServer(sptr)) sendto_realops("Lost server %s during negotiation: %s", sptr->name, comment); if (IsServer(sptr)) { Count.myserver--; if (IsULine(sptr)) Count.myulined--; remove_from_list(&server_list, sptr, NULL); if (server_list == NULL) server_was_split = YES; } sptr->flags |= FLAGS_CLOSING; if (IsPerson(sptr)) { Link *lp, *next; LOpts *lopt = sptr->user->lopt; /* poof goes their watchlist! */ hash_del_watch_list(sptr); /* if they have listopts, axe those, too */ if(lopt != NULL) { remove_from_list(&listing_clients, sptr, NULL); for (lp = lopt->yeslist; lp; lp = next) { next = lp->next; MyFree(lp->value.cp); free_link(lp); } for (lp = lopt->nolist; lp; lp = next) { next = lp->next; MyFree(lp->value.cp); free_link(lp); } MyFree(sptr->user->lopt); sptr->user->lopt = NULL; } sendto_realops_lev(CCONN_LEV, "Client exiting: %s (%s@%s) [%s] [%s]", sptr->name, sptr->user->username, sptr->user->host, (sptr->flags & FLAGS_NORMALEX) ? "Client Quit" : comment, sptr->hostip); } #ifdef FNAME_USERLOG on_for = timeofday - sptr->firsttime; #endif #if defined(USE_SYSLOG) && defined(SYSLOG_USERS) if (IsPerson(sptr)) syslog(LOG_NOTICE, "%s (%3d:%02d:%02d): %s!%s@%s %d/%d\n", myctime(sptr->firsttime), on_for / 3600, (on_for % 3600) / 60, on_for % 60, sptr->name, sptr->user->username, sptr->user->host, sptr->sendK, sptr->receiveK); #endif #if defined(FNAME_USERLOG) { char linebuf[300]; static int logfile = -1; static long lasttime; /* * This conditional makes the logfile active only after it's * been created - thus logging can be turned off by removing * the file. * * stop NFS hangs...most systems should be able to open a file in * 3 seconds. -avalon (curtesy of wumpus) * * Keep the logfile open, syncing it every 10 seconds -Taner */ if (IsPerson(sptr)) { if (logfile == -1) { alarm(3); logfile = open(FNAME_USERLOG, O_WRONLY | O_APPEND); alarm(0); } ircsprintf(linebuf, "%s (%3d:%02d:%02d): %s!%s@%s %d/%d\n", myctime(sptr->firsttime), on_for / 3600, (on_for % 3600) / 60, on_for % 60, sptr->name, sptr->user->username, sptr->user->host, sptr->sendK, sptr->receiveK); alarm(3); write(logfile, linebuf, strlen(linebuf)); alarm(0); /* Resync the file evey 10 seconds*/ if (timeofday - lasttime > 10) { alarm(3); close(logfile); alarm(0); logfile = -1; lasttime = timeofday; } } } #endif if (sptr->fd >= 0) { if (cptr != NULL && sptr != cptr) sendto_one(&me, sptr, "ERROR :Closing Link: %s %s (%s)", IsPerson(sptr) ? sptr->sockhost : "0.0.0.0", sptr->name, comment); else sendto_one(&me, sptr, "ERROR :Closing Link: %s (%s)", IsPerson(sptr) ? sptr->sockhost : "0.0.0.0", comment); } /* * * Currently only server connections can have * depending * remote clients here, but it does no * harm to check for all * local clients. In * future some other clients than servers * might * have remotes too... * * * Close the Client connection first and mark it * so that no * messages are attempted to send to it. *, The following *must* * make MyConnect(sptr) == FALSE!). * It also makes sptr->from == * NULL, thus it's unnecessary * to test whether "sptr != acptr" * in the following loops. */ if (IsServer(sptr)) { sendto_ops("%s was connected for %lu seconds. %lu/%lu " "sendK/recvK.", sptr->name, (long)(timeofday - sptr->firsttime), sptr->sendK, sptr->receiveK); #ifdef USE_SYSLOG syslog(LOG_NOTICE, "%s was connected for %lu seconds. %lu/%lu " "sendK/recvK.", sptr->name, (u_long) timeofday - sptr->firsttime, sptr->sendK, sptr->receiveK); #endif close_connection(sptr); sptr->sockerr = 0; sptr->flags |= FLAGS_DEADSOCKET; } else { close_connection(sptr); sptr->sockerr = 0; sptr->flags |= FLAGS_DEADSOCKET; } } exit_one_client(cptr, sptr, from, comment); return cptr == sptr ? FLUSH_BUFFER : 0; }
/* * do_svssno() * parv[0] - sender * parv[1] - username to change snomask for * parv[2] - snomasks to change * show_change determines whether to show the change to the user */ int do_svssno(aClient *cptr, aClient *sptr, int parc, char *parv[], int show_change) { char *p; aClient *acptr; int what = MODE_ADD, i; if (!IsULine(sptr)) return 0; if (parc < 2) return 0; if (parv[1][0] == '#') return 0; if (!(acptr = find_person(parv[1], NULL))) return 0; if (hunt_server_token(cptr, sptr, show_change ? MSG_SVS2SNO : MSG_SVSSNO, show_change ? TOK_SVS2SNO : TOK_SVSSNO, "%s %s", 1, parc, parv) != HUNTED_ISME) { return 0; } if (MyClient(acptr)) { if (parc == 2) acptr->user->snomask = 0; else { for (p = parv[2]; p && *p; p++) { switch (*p) { case '+': what = MODE_ADD; break; case '-': what = MODE_DEL; break; default: for (i = 0; i <= Snomask_highest; i++) { if (!Snomask_Table[i].flag) continue; if (*p == Snomask_Table[i].flag) { if (what == MODE_ADD) acptr->user->snomask |= Snomask_Table[i].mode; else acptr->user->snomask &= ~Snomask_Table[i].mode; } } } } } } if (show_change) sendto_one(acptr, rpl_str(RPL_SNOMASK), me.name, acptr->name, get_sno_str(acptr)); return 0; }
static void serv_info(aClient *cptr, char *name) { static char Lformat[] = ":%s %d %s %s %u %u %u %u %u :%u %u %s"; long sendK, receiveK, uptime; aClient *acptr; DLink *lp; int i = 0; sendK = receiveK = 0; for (lp = server_list; lp; lp = lp->next) { acptr = lp->value.cptr; #ifdef HIDEULINEDSERVS if (IsULine(acptr) && !IsAnOper(cptr)) continue; #endif sendK += acptr->sendK; receiveK += acptr->receiveK; sendto_one(cptr, Lformat, me.name, RPL_STATSLINKINFO, name, ( (MyClient(cptr) && IsAdmin(cptr)) ? get_client_name(acptr, FALSE) : get_client_name(acptr, HIDEME) ), (int) SBufLength(&acptr->sendQ), (int) acptr->sendM, (int) acptr->sendK, (int) acptr->receiveM, (int) acptr->receiveK, timeofday - acptr->firsttime, timeofday - acptr->since, IsServer(acptr) ? (DoesTS(acptr) ? "TS" : "NoTS") : "-"); if(RC4EncLink(acptr)) sendto_one(cptr, ":%s %d %s : - RC4 encrypted", me.name, RPL_STATSDEBUG, name); if(ZipOut(acptr)) { unsigned long ib, ob; double rat; zip_out_get_stats(acptr->serv->zip_out, &ib, &ob, &rat); if(ib) { sendto_one(cptr, ":%s %d %s : - [O] Zip inbytes %lu, " "outbytes %lu (%3.2f%%)", me.name, RPL_STATSDEBUG, name, ib, ob, rat); } } if(ZipIn(acptr)) { unsigned long ib, ob; double rat; zip_in_get_stats(acptr->serv->zip_in, &ib, &ob, &rat); if(ob) { sendto_one(cptr, ":%s %d %s : - [I] Zip inbytes %lu, " "outbytes %lu (%3.2f%%)", me.name, RPL_STATSDEBUG, name, ib, ob, rat); } } i++; } sendto_one(cptr, ":%s %d %s :%u total server%s", me.name, RPL_STATSDEBUG, name, i, (i == 1) ? "" : "s"); sendto_one(cptr, ":%s %d %s :Sent total : %7.2f %s", me.name, RPL_STATSDEBUG, name, _GMKv(sendK), _GMKs(sendK)); sendto_one(cptr, ":%s %d %s :Recv total : %7.2f %s", me.name, RPL_STATSDEBUG, name, _GMKv(receiveK), _GMKs(receiveK)); uptime = (timeofday - me.since); sendto_one(cptr, ":%s %d %s :Server send: %7.2f %s (%4.1f K/s total," " %4.1f K/s current)", me.name, RPL_STATSDEBUG, name, _GMKv(me.sendK), _GMKs(me.sendK), (float) ((float) me.sendK / (float) uptime), curSendK); sendto_one(cptr, ":%s %d %s :Server recv: %7.2f %s (%4.1f K/s total," " %4.1f K/s current)", me.name, RPL_STATSDEBUG, name, _GMKv(me.receiveK), _GMKs(me.receiveK), (float) ((float) me.receiveK / (float) uptime), curRecvK); }
/* Routine that actually makes a user join the channel * this does no actual checking (banned, etc.) it just adds the user */ DLLFUNC void _join_channel(aChannel *chptr, aClient *cptr, aClient *sptr, int flags) { char *parv[] = { 0, 0 }; /* ** Complete user entry to the new channel (if any) */ add_user_to_channel(chptr, sptr, flags); /* ** notify all other users on the new channel */ if (chptr->mode.mode & MODE_AUDITORIUM) { if (MyClient(sptr)) sendto_one(sptr, ":%s!%s@%s JOIN :%s", sptr->name, sptr->user->username, GetHost(sptr), chptr->chname); sendto_chanops_butone(NULL, chptr, ":%s!%s@%s JOIN :%s", sptr->name, sptr->user->username, GetHost(sptr), chptr->chname); } else sendto_channel_butserv(chptr, sptr, ":%s JOIN :%s", sptr->name, chptr->chname); sendto_serv_butone_token_opt(cptr, OPT_NOT_SJ3, sptr->name, MSG_JOIN, TOK_JOIN, "%s", chptr->chname); #ifdef JOIN_INSTEAD_OF_SJOIN_ON_REMOTEJOIN if ((MyClient(sptr) && !(flags & CHFL_CHANOP)) || !MyClient(sptr)) sendto_serv_butone_token_opt(cptr, OPT_SJ3, sptr->name, MSG_JOIN, TOK_JOIN, "%s", chptr->chname); if (flags && !(flags & CHFL_DEOPPED)) { #endif /* I _know_ that the "@%s " look a bit wierd with the space and all .. but its to get around a SJOIN bug --stskeeps */ sendto_serv_butone_token_opt(cptr, OPT_SJ3|OPT_SJB64, me.name, MSG_SJOIN, TOK_SJOIN, "%B %s :%s%s ", (long)chptr->creationtime, chptr->chname, chfl_to_sjoin_symbol(flags), sptr->name); sendto_serv_butone_token_opt(cptr, OPT_SJ3|OPT_NOT_SJB64, me.name, MSG_SJOIN, TOK_SJOIN, "%li %s :%s%s ", chptr->creationtime, chptr->chname, chfl_to_sjoin_symbol(flags), sptr->name); #ifdef JOIN_INSTEAD_OF_SJOIN_ON_REMOTEJOIN } #endif if (MyClient(sptr)) { /* ** Make a (temporal) creationtime, if someone joins ** during a net.reconnect : between remote join and ** the mode with TS. --Run */ if (chptr->creationtime == 0) { chptr->creationtime = TStime(); sendto_serv_butone_token(cptr, me.name, MSG_MODE, TOK_MODE, "%s + %lu", chptr->chname, chptr->creationtime); } del_invite(sptr, chptr); if (flags && !(flags & CHFL_DEOPPED)) { #ifndef PREFIX_AQ if ((flags & CHFL_CHANOWNER) || (flags & CHFL_CHANPROT)) { /* +ao / +qo for when PREFIX_AQ is off */ sendto_serv_butone_token_opt(cptr, OPT_NOT_SJ3, me.name, MSG_MODE, TOK_MODE, "%s +o%c %s %s %lu", chptr->chname, chfl_to_chanmode(flags), sptr->name, sptr->name, chptr->creationtime); } else { #endif /* +v/+h/+o (and +a/+q if PREFIX_AQ is on) */ sendto_serv_butone_token_opt(cptr, OPT_NOT_SJ3, me.name, MSG_MODE, TOK_MODE, "%s +%c %s %lu", chptr->chname, chfl_to_chanmode(flags), sptr->name, chptr->creationtime); #ifndef PREFIX_AQ } #endif } if (chptr->topic) { sendto_one(sptr, rpl_str(RPL_TOPIC), me.name, sptr->name, chptr->chname, chptr->topic); sendto_one(sptr, rpl_str(RPL_TOPICWHOTIME), me.name, sptr->name, chptr->chname, chptr->topic_nick, chptr->topic_time); } if (chptr->users == 1 && (MODES_ON_JOIN #ifdef EXTCMODE || iConf.modes_on_join.extmodes) #endif ) { #ifdef EXTCMODE int i; chptr->mode.extmode = iConf.modes_on_join.extmodes; /* Param fun */ for (i = 0; i <= Channelmode_highest; i++) { if (!Channelmode_Table[i].flag || !Channelmode_Table[i].paracount) continue; if (chptr->mode.extmode & Channelmode_Table[i].mode) { CmodeParam *p; p = Channelmode_Table[i].put_param(NULL, iConf.modes_on_join.extparams[i]); AddListItem(p, chptr->mode.extmodeparam); } } #endif chptr->mode.mode = MODES_ON_JOIN; #ifdef NEWCHFLOODPROT if (iConf.modes_on_join.floodprot.per) { chptr->mode.floodprot = MyMalloc(sizeof(ChanFloodProt)); memcpy(chptr->mode.floodprot, &iConf.modes_on_join.floodprot, sizeof(ChanFloodProt)); } #else chptr->mode.kmode = iConf.modes_on_join.kmode; chptr->mode.per = iConf.modes_on_join.per; chptr->mode.msgs = iConf.modes_on_join.msgs; #endif *modebuf = *parabuf = 0; channel_modes(sptr, modebuf, parabuf, chptr); /* This should probably be in the SJOIN stuff */ sendto_serv_butone_token(&me, me.name, MSG_MODE, TOK_MODE, "%s %s %s %lu", chptr->chname, modebuf, parabuf, chptr->creationtime); sendto_one(sptr, ":%s MODE %s %s %s", me.name, chptr->chname, modebuf, parabuf); } parv[0] = sptr->name; parv[1] = chptr->chname; do_cmd(cptr, sptr, "NAMES", 2, parv); RunHook4(HOOKTYPE_LOCAL_JOIN, cptr, sptr,chptr,parv); } else { RunHook4(HOOKTYPE_REMOTE_JOIN, cptr, sptr, chptr, parv); /* (rarely used) */ } #ifdef NEWCHFLOODPROT /* I'll explain this only once: * 1. if channel is +f * 2. local client OR synced server * 3. then, increase floodcounter * 4. if we reached the limit AND only if source was a local client.. do the action (+i). * Nr 4 is done because otherwise you would have a noticeflood with 'joinflood detected' * from all servers. */ if (chptr->mode.floodprot && (MyClient(sptr) || sptr->srvptr->serv->flags.synced) && !IsULine(sptr) && do_chanflood(chptr->mode.floodprot, FLD_JOIN) && MyClient(sptr)) { do_chanflood_action(chptr, FLD_JOIN, "join"); } #endif }
/* * m_nick * parv[0] = sender prefix * parv[1] = nickname * parv[2] = hopcount when new user; TS when nick change * parv[3] = TS * ---- new user only below ---- * parv[4] = umode * parv[5] = username * parv[6] = hostname * parv[7] = server * parv[8] = serviceid * parv[9] = IP * parv[10] = ircname * -- endif */ int m_nick(aClient *cptr, aClient *sptr, int parc, char *parv[]) { struct simBan *ban; aClient *acptr, *uplink; Link *lp, *lp2; char nick[NICKLEN + 2]; ts_val newts = 0; int sameuser = 0, samenick = 0; if (parc < 2) { sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN), me.name, parv[0]); return 0; } if (!IsServer(sptr) && IsServer(cptr) && parc > 2) newts = atol(parv[2]); else if (IsServer(sptr) && parc > 3) newts = atol(parv[3]); else parc = 2; /* * parc == 2 on a normal client sign on (local) and a normal client * nick change * parc == 4 on a normal server-to-server client nick change * parc == 11 on a normal TS style server-to-server NICK introduction */ if ((IsServer(sptr) || (parc > 4)) && (parc < 11)) { /* * We got the wrong number of params. Someone is trying to trick * us. Kill it. -ThemBones As discussed with ThemBones, not much * point to this code now sending a whack of global kills would * also be more annoying then its worth, just note the problem, * and continue -Dianora */ sendto_realops("IGNORING BAD NICK: %s[%s@%s] on %s (from %s)", parv[1], (parc >= 6) ? parv[5] : "-", (parc >= 7) ? parv[6] : "-", (parc >= 8) ? parv[7] : "-", parv[0]); return 0; } strncpyzt(nick, parv[1], NICKLEN + 1); /* * if do_nick_name() returns a null name OR if the server sent a * nick name and do_nick_name() changed it in some way (due to rules * of nick creation) then reject it. If from a server and we reject * it, and KILL it. -avalon 4/4/92 */ if (do_nick_name(nick) == 0 || (IsServer(cptr) && strcmp(nick, parv[1]))) { sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME), me.name, parv[0], parv[1], "Erroneous Nickname"); if (IsServer(cptr)) { ircstp->is_kill++; sendto_realops_lev(DEBUG_LEV, "Bad Nick: %s From: %s Via: %s", parv[1], parv[0], get_client_name(cptr, HIDEME)); sendto_one(cptr, ":%s KILL %s :%s (Bad Nick)", me.name, parv[1], me.name); if (sptr != cptr) { /* bad nick change */ sendto_serv_butone(cptr, ":%s KILL %s :%s (Bad Nick)", me.name, parv[0], me.name); sptr->flags |= FLAGS_KILLED; return exit_client(cptr, sptr, &me, "BadNick"); } } return 0; } /* * Check against nick name collisions. * * Put this 'if' here so that the nesting goes nicely on the screen * :) We check against server name list before determining if the * nickname is present in the nicklist (due to the way the below * for loop is constructed). -avalon */ do { if ((acptr = find_server(nick, NULL))) if (MyConnect(sptr)) { sendto_one(sptr, err_str(ERR_NICKNAMEINUSE), me.name, BadPtr(parv[0]) ? "*" : parv[0], nick); return 0; } /* * acptr already has result from find_server * Well. unless we have a capricious server on the net, a nick can * never be the same as a server name - Dianora * That's not the only case; maybe someone broke do_nick_name * or changed it so they could use "." in nicks on their network * - sedition */ if (acptr) { /* * We have a nickname trying to use the same name as a * server. Send out a nick collision KILL to remove the * nickname. As long as only a KILL is sent out, there is no * danger of the server being disconnected. Ultimate way to * jupiter a nick ? >;-). -avalon */ sendto_realops_lev(SKILL_LEV, "Nick collision on %s", sptr->name); ircstp->is_kill++; sendto_one(cptr, ":%s KILL %s :%s (Nick Collision)", me.name, sptr->name, me.name); sptr->flags |= FLAGS_KILLED; return exit_client(cptr, sptr, &me, "Nick/Server collision"); } if (!(acptr = find_client(nick, NULL))) break; /* * If acptr == sptr, then we have a client doing a nick change * between *equivalent* nicknames as far as server is concerned * (user is changing the case of his/her nickname or somesuch) */ if (acptr == sptr) { if (strcmp(acptr->name, nick) == 0) return 0; else break; } /* If user is changing nick to itself no point in propogating */ /* * Note: From this point forward it can be assumed that acptr != * sptr (point to different client structures). * * If the older one is "non-person", the new entry is just * allowed to overwrite it. Just silently drop non-person, and * proceed with the nick. This should take care of the "dormant * nick" way of generating collisions... */ if (IsUnknown(acptr)) { if (MyConnect(acptr)) { exit_client(NULL, acptr, &me, "Overridden"); break; } else if (!(acptr->user)) { sendto_realops_lev(SKILL_LEV, "Nick Collision on %s", parv[1]); sendto_serv_butone(NULL, ":%s KILL %s :%s (Nick Collision)", me.name, acptr->name, me.name); acptr->flags |= FLAGS_KILLED; /* Having no USER struct should be ok... */ return exit_client(cptr, acptr, &me, "Got TS NICK before Non-TS USER"); } } if (!IsServer(cptr)) { /* * NICK is coming from local client connection. Just send * error reply and ignore the command. * parv[0] is empty on connecting clients */ sendto_one(sptr, err_str(ERR_NICKNAMEINUSE), me.name, BadPtr(parv[0]) ? "*" : parv[0], nick); return 0; } /* * NICK was coming from a server connection. Means that the same * nick is registered for different users by different server. * This is either a race condition (two users coming online about * same time, or net reconnecting) or just two net fragments * becoming joined and having same nicks in use. We cannot have * TWO users with same nick--purge this NICK from the system with * a KILL... >;) * * Changed to something reasonable like IsServer(sptr) (true if * "NICK new", false if ":old NICK new") -orabidoo */ if (IsServer(sptr)) { /* * A new NICK being introduced by a neighbouring server (e.g. * message type "NICK new" received) */ if (!newts || !acptr->tsinfo || (newts == acptr->tsinfo)) { sendto_realops_lev(SKILL_LEV, "Nick collision on %s", parv[1]); ircstp->is_kill++; sendto_one(acptr, err_str(ERR_NICKCOLLISION), me.name, acptr->name, acptr->name); sendto_serv_butone(NULL, ":%s KILL %s :%s (Nick Collision)", me.name, acptr->name, me.name); acptr->flags |= FLAGS_KILLED; return exit_client(cptr, acptr, &me, "Nick collision"); } else { /* XXX This looks messed up to me XXX - Raist */ sameuser = (acptr->user) && mycmp(acptr->user->username, parv[5]) == 0 && mycmp(acptr->user->host, parv[6]) == 0; if ((sameuser && newts < acptr->tsinfo) || (!sameuser && newts > acptr->tsinfo)) { return 0; } else { sendto_realops_lev(SKILL_LEV, "Nick collision on %s",parv[1]); ircstp->is_kill++; sendto_one(acptr, err_str(ERR_NICKCOLLISION), me.name, acptr->name, acptr->name); sendto_serv_butone(sptr, ":%s KILL %s :%s (Nick Collision)", me.name, acptr->name, me.name); acptr->flags |= FLAGS_KILLED; (void) exit_client(cptr, acptr, &me, "Nick collision"); break; } } } /* * * A NICK change has collided (e.g. message type * ":old NICK * new". This requires more complex cleanout. * Both clients must be * purged from this server, the "new" * must be killed from the * incoming connection, and "old" must * be purged from all outgoing * connections. */ if (!newts || !acptr->tsinfo || (newts == acptr->tsinfo) || !sptr->user) { sendto_realops_lev(SKILL_LEV, "Nick change collision: %s", parv[1]); ircstp->is_kill++; sendto_one(acptr, err_str(ERR_NICKCOLLISION), me.name, acptr->name, acptr->name); sendto_serv_butone(NULL, ":%s KILL %s :%s (Nick Collision)",me.name, sptr->name, me.name); ircstp->is_kill++; sendto_serv_butone(NULL, ":%s KILL %s :%s (Nick Collision)",me.name, acptr->name, me.name); acptr->flags |= FLAGS_KILLED; (void) exit_client(NULL, acptr, &me, "Nick collision(new)"); sptr->flags |= FLAGS_KILLED; return exit_client(cptr, sptr, &me, "Nick collision(old)"); } else { /* XXX This looks messed up XXX */ sameuser = mycmp(acptr->user->username, sptr->user->username) == 0 && mycmp(acptr->user->host, sptr->user->host) == 0; if ((sameuser && newts < acptr->tsinfo) || (!sameuser && newts > acptr->tsinfo)) { if (sameuser) sendto_realops_lev(SKILL_LEV, "Nick change collision from %s to %s", sptr->name, acptr->name); ircstp->is_kill++; sendto_serv_butone(cptr, ":%s KILL %s :%s (Nick Collision)", me.name, sptr->name, me.name); sptr->flags |= FLAGS_KILLED; if (sameuser) return exit_client(cptr, sptr, &me, "Nick collision(old)"); else return exit_client(cptr, sptr, &me, "Nick collision(new)"); } else { sendto_realops_lev(SKILL_LEV, "Nick collision on %s", acptr->name); ircstp->is_kill++; sendto_one(acptr, err_str(ERR_NICKCOLLISION), me.name, acptr->name, acptr->name); sendto_serv_butone(sptr, ":%s KILL %s :%s (Nick Collision)",me.name, acptr->name, me.name); acptr->flags |= FLAGS_KILLED; (void) exit_client(cptr, acptr, &me, "Nick collision"); } } } while (0); if (IsServer(sptr)) { uplink = find_server(parv[7], NULL); if(!uplink) { /* if we can't find the server this nick is on, * complain loudly and ignore it. - lucas */ sendto_realops("Remote nick %s on UNKNOWN server %s", nick, parv[7]); return 0; } sptr = make_client(cptr, uplink); /* If this is on a U: lined server, it's a U: lined client. */ if(IsULine(uplink)) sptr->flags|=FLAGS_ULINE; add_client_to_list(sptr); if (parc > 2) sptr->hopcount = atoi(parv[2]); if (newts) { sptr->tsinfo = newts; } else { newts = sptr->tsinfo = (ts_val) timeofday; ts_warn("Remote nick %s introduced without a TS", nick); } /* copy the nick in place */ (void) strcpy(sptr->name, nick); (void) add_to_client_hash_table(nick, sptr); if (parc >= 10) { int *s, flag; char *m; /* parse the usermodes -orabidoo */ m = &parv[4][1]; while (*m) { for (s = user_modes; (flag = *s); s += 2) if (*m == *(s + 1)) { if ((flag == UMODE_o) || (flag == UMODE_O)) Count.oper++; sptr->umode |= flag & SEND_UMODES; break; } m++; } if (parc==10) { return do_user(nick, cptr, sptr, parv[5], parv[6], parv[7], strtoul(parv[8], NULL, 0), "0.0.0.0", parv[9]); } else if (parc==11) { return do_user(nick, cptr, sptr, parv[5], parv[6], parv[7], strtoul(parv[8], NULL, 0), parv[9], parv[10]); } } } else if (sptr->name[0]) { #ifdef DONT_CHECK_QLINE_REMOTE if (MyConnect(sptr)) { #endif if ((ban = check_mask_simbanned(nick, SBAN_NICK))) { #ifndef DONT_CHECK_QLINE_REMOTE if (!MyConnect(sptr)) sendto_realops("Restricted nick %s from %s on %s", nick, (*sptr->name != 0 && !IsServer(sptr)) ? sptr->name : "<unregistered>", (sptr->user == NULL) ? ((IsServer(sptr)) ? parv[6] : me.name) : sptr->user->server); #endif if (MyConnect(sptr) && (!IsServer(cptr)) && (!IsOper(cptr)) && (!IsULine(sptr))) { sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME), me.name, BadPtr(parv[0]) ? "*" : parv[0], nick, BadPtr(ban->reason) ? "Erroneous Nickname" : ban->reason); if (call_hooks(CHOOK_FORBID, cptr, nick, ban) != FLUSH_BUFFER) sendto_realops_lev(REJ_LEV, "Forbidding restricted nick %s from %s", nick, get_client_name(cptr, FALSE)); return 0; } } #ifdef DONT_CHECK_QLINE_REMOTE } #endif if (MyConnect(sptr)) { if (IsRegisteredUser(sptr)) { /* before we change their nick, make sure they're not banned * on any channels, and!! make sure they're not changing to * a banned nick -sed */ /* a little cleaner - lucas */ for (lp = sptr->user->channel; lp; lp = lp->next) { if (can_send(sptr, lp->value.chptr, NULL)) { sendto_one(sptr, err_str(ERR_BANNICKCHANGE), me.name, sptr->name, lp->value.chptr->chname); return 0; } if (nick_is_banned(lp->value.chptr, nick, sptr) != NULL) { sendto_one(sptr, err_str(ERR_BANONCHAN), me.name, sptr->name, nick, lp->value.chptr->chname); return 0; } } #ifdef ANTI_NICK_FLOOD if ((sptr->last_nick_change + MAX_NICK_TIME) < NOW) sptr->number_of_nick_changes = 0; sptr->last_nick_change = NOW; sptr->number_of_nick_changes++; if (sptr->number_of_nick_changes > MAX_NICK_CHANGES && !IsAnOper(sptr)) { sendto_one(sptr, ":%s NOTICE %s :*** Notice -- Too many nick " "changes. Wait %d seconds before trying again.", me.name, sptr->name, MAX_NICK_TIME); return 0; } #endif /* If it changed nicks, -r it */ if ((sptr->umode & UMODE_r) && (mycmp(parv[0], nick) != 0)) { unsigned int oldumode; char mbuf[BUFSIZE]; oldumode = sptr->umode; sptr->umode &= ~UMODE_r; send_umode(sptr, sptr, oldumode, ALL_UMODES, mbuf); } /* LOCAL NICKHANGE */ /* * Client just changing his/her nick. If he/she is on a * channel, send note of change to all clients on that channel. * Propagate notice to other servers. */ /* if the nickname is different, set the TS */ if (mycmp(parv[0], nick)) { sptr->tsinfo = newts ? newts : (ts_val) timeofday; } sendto_common_channels(sptr, ":%s NICK :%s", parv[0], nick); if (sptr->user) { add_history(sptr, 1); sendto_serv_butone(cptr, ":%s NICK %s :%ld", parv[0], nick, sptr->tsinfo); } } } else { /* REMOTE NICKCHANGE */ /* * Client just changing his/her nick. If he/she is on a * channel, send note of change to all clients on that channel. * Propagate notice to other servers. */ /* if the nickname is different, set the TS */ if (mycmp(parv[0], nick)) { sptr->tsinfo = newts ? newts : (ts_val) timeofday; } sendto_common_channels(sptr, ":%s NICK :%s", parv[0], nick); if (sptr->user) { add_history(sptr, 1); sendto_serv_butone(cptr, ":%s NICK %s :%ld", parv[0], nick, sptr->tsinfo); } /* If it changed nicks, -r it */ if (mycmp(parv[0], nick)) sptr->umode &= ~UMODE_r; /* * Flush the banserial for the channels the user is in, since this * could be a SVSNICK induced nick change, which overrides any ban * checking on the originating server. */ flush_user_banserial(sptr); } /* Remove dccallow entries for users who don't share common channel(s) unless they only change their nick capitalization -Kobi_S */ if(sptr->user && mycmp(parv[0], nick)) { for(lp = sptr->user->dccallow; lp; lp = lp2) { lp2 = lp->next; if(lp->flags == DCC_LINK_ME) continue; if(!find_shared_chan(sptr, lp->value.cptr)) { sendto_one(lp->value.cptr, ":%s %d %s :%s has been removed from " "your DCC allow list for signing off", me.name, RPL_DCCINFO, lp->value.cptr->name, parv[0]); del_dccallow(lp->value.cptr, sptr, 1); } } } } else { /* Client setting NICK the first time */ if (MyConnect(sptr)) { if ((ban = check_mask_simbanned(nick, SBAN_NICK))) { if (MyConnect(sptr) && (!IsServer(cptr)) && (!IsOper(cptr)) && (!IsULine(sptr))) { sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME), me.name, BadPtr(parv[0]) ? "*" : parv[0], nick, BadPtr(ban->reason) ? "Erroneous Nickname" : ban->reason); if (call_hooks(CHOOK_FORBID, cptr, nick, ban) != FLUSH_BUFFER) sendto_realops_lev(REJ_LEV, "Forbidding restricted nick %s from %s", nick, get_client_name(cptr, FALSE)); return 0; } } } strcpy(sptr->name, nick); sptr->tsinfo = timeofday; if (sptr->user) { /* USER already received, now we have NICK */ if (register_user(cptr, sptr, nick, sptr->user->username, NULL) == FLUSH_BUFFER) return FLUSH_BUFFER; } } /* Finally set new nick name. */ if (sptr->name[0]) { del_from_client_hash_table(sptr->name, sptr); samenick = mycmp(sptr->name, nick) ? 0 : 1; if (IsPerson(sptr)) { if (!samenick) hash_check_watch(sptr, RPL_LOGOFF); #ifdef RWHO_PROBABILITY probability_change(sptr->name, nick); #endif } } strcpy(sptr->name, nick); add_to_client_hash_table(nick, sptr); if (IsPerson(sptr) && !samenick) hash_check_watch(sptr, RPL_LOGON); return 0; }