// 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); } } }
/** 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); } } }
int m_scan_idle(struct Client *cptr, struct Client *sptr, int parc, char *parv[], char *varparv[]) { struct Client *ptr, *target = NULL; char *eptr, buffer[321]; int idle_time, check_time, len = 0, count = 0; if(MyClient(sptr) && !HasUmode(sptr, UMODE_USER_AUSPEX)) { if(SeesOperMessages(sptr)) sendto_one(sptr,":%s NOTICE %s :You have no a umode", me.name, parv[0]); else sendto_one(sptr, form_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } if(parc < 3) { if (!IsServer(sptr)) sendto_one(sptr, form_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "SCAN IDLE"); return 0; } idle_time = strtoul(parv[2], &eptr, 10); if(eptr == parv[2]) return 0; /* Store the timestamp which last_sent should be >= to save time */ check_time = CurrentTime - idle_time; /* If the query is for another server, pass it on and return. */ if(parc > 3) { if(MyClient(sptr) && !HasUmode(sptr, UMODE_REMOTEINFO)) { if(SeesOperMessages(sptr)) sendto_one(sptr,":%s NOTICE %s :You have no S umode(cannot send remote)", me.name, parv[0]); else sendto_one(sptr, form_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } if(!irccmp(parv[3], "GLOBAL") || !irccmp(parv[3], "*")) sendto_serv_butone(cptr, ":%s SCAN IDLE %d *", parv[0], idle_time); else if((target = find_server(parv[3])) == NULL) { sendto_one(sptr, form_str(ERR_NOSUCHSERVER), me.name, parv[0], parv[3]); return 0; }else if(!IsMe(target)) { /* But only if the query is not on us... */ sendto_prefix_one(target, sptr, ":%s SCAN IDLE %d %s", parv[0], idle_time, target->name); return 0; } } buffer[0] = '\0'; for(ptr = local_cptr_list; ptr; ptr = ptr->next_local_client) { if(ptr->user->last_sent < check_time) continue; if(len + strlen(ptr->name) > 319) { buffer[len - 1] = '\0'; /* Strip the trailing space */ send_markup(sptr, &me, "SCAN-IDLE", "%d %s", idle_time, buffer); buffer[0] = '\0'; len = 0; } strcat(buffer, ptr->name); strcat(buffer, " "); len += strlen(ptr->name) + 1; count++; } if(buffer[0]) { buffer[len - 1] = '\0'; send_markup(sptr, &me, "SCAN-IDLE", "%d %s", idle_time, buffer); } send_markup(sptr, &me, "IDLE-END", "End of idle listing"); if(count > 0 || target || parc == 3) /* Don't give a summary for globals if no results matched */ send_markup(sptr, &me, "SCAN-SUMMARY", "%d matched", count); return 0; }
/* * * DoNumeric (replacement for the old do_numeric) * * * parc number of arguments ('sender' counted as one!) * parv[0] pointer to 'sender' (may point to empty string) * parv[1]..parv[parc-1] * pointers to additional parameters, this is a NULL * terminated list (parv[parc] == NULL). * * *WARNING* * Numerics are mostly error reports. If there is something * wrong with the message, just *DROP* it! Don't even think of * sending back a neat error message -- big danger of creating * a ping pong error message... */ int do_numeric(int numeric, aClient *cptr, aClient *sptr, int parc, char *parv[]) { aClient *acptr; aChannel *chptr; char *nick, *p; int i; if (parc < 1 || !IsServer(sptr)) return 0; /* Remap low number numerics. */ if (numeric < 100) numeric += 100; /* * Prepare the parameter portion of the message into 'buffer'. * (Because the buffer is twice as large as the message buffer for * the socket, no overflow can occur here... ...on current * assumptions--bets are off, if these are changed --msa) * Note: if buffer is non-empty, it will begin with SPACE. */ buffer[0] = '\0'; if (parc > 1) { int bpos = 0; char *p; for (i = 2; i < (parc - 1); i++) { buffer[bpos++] = ' '; for(p = parv[i]; *p; p++) buffer[bpos++] = *p; } buffer[bpos++] = ' '; buffer[bpos++] = ':'; for(p = parv[parc - 1]; *p; p++) buffer[bpos++] = *p; buffer[bpos] = '\0'; } for (; (nick = strtoken(&p, parv[1], ",")); parv[1] = NULL) { if ((acptr = find_client(nick, (aClient *) NULL))) { int dohide; /* * Drop to bit bucket if for me... ...one might consider * sendto_ops * here... --msa * And so it was done. -avalon * * And regretted. Dont do it that way. Make sure * it goes * only to non-servers. -avalon * Check added to make sure * servers don't try to loop * with numerics which can happen * with nick collisions. * - Avalon */ #ifdef HIDE_NUMERIC_SOURCE dohide = MyClient(acptr) ? 1 : 0; #else dohide = 0; #endif if (!IsMe(acptr) && IsPerson(acptr)) sendto_prefix_one(acptr, dohide ? &me : sptr, ":%s %d %s%s", dohide ? me.name : parv[0], numeric, nick, buffer); else if (IsServer(acptr) && acptr->from != cptr) sendto_prefix_one(acptr, sptr, ":%s %d %s%s", parv[0], numeric, nick, buffer); } else if ((chptr = find_channel(nick, (aChannel *) NULL))) { int dohide; #ifdef HIDE_NUMERIC_SOURCE dohide = 1; #else dohide = 0; #endif sendto_channel_butserv(chptr, dohide ? &me : sptr, ":%s %d %s%s", dohide ? me.name : parv[0], numeric, chptr->chname, buffer); sendto_channel_remote_butone(cptr, sptr, chptr, parv[0], numeric, chptr->chname, buffer); } } return 0; }
static int m_message(struct Client *cptr, struct Client *sptr, int parc, char *parv[], int notice) { struct Client *acptr; #ifdef NEED_TLD_FOR_MASS_NOTICE char *s; #endif struct Channel *chptr; char *nick, *server, *host; char errbuf[BUFSIZE]; const char *cmd; int type=0, msgs=0; #ifdef FLUD int flud; #endif cmd = notice ? MSG_NOTICE : MSG_PRIVATE; if (parc < 2 || *parv[1] == '\0') { sendto_one(sptr, form_str(ERR_NORECIPIENT), me.name, parv[0], cmd); return -1; } if (parc < 3 || *parv[2] == '\0') { sendto_one(sptr, form_str(ERR_NOTEXTTOSEND), me.name, parv[0]); return -1; } if (MyConnect(sptr)) { #ifdef ANTI_SPAMBOT #ifndef ANTI_SPAMBOT_WARN_ONLY /* if its a spambot, just ignore it */ if(sptr->join_leave_count >= MAX_JOIN_LEAVE_COUNT) return 0; #endif #endif #ifdef NO_DUPE_MULTI_MESSAGES if (strchr(parv[1],',')) parv[1] = canonize(parv[1]); #endif } /* ** channels are privmsg'd a lot more than other clients, moved up here ** plain old channel msg ? */ while(msgs < MAX_MULTI_MESSAGES) { if(!msgs) nick = strtok(parv[1], ","); else nick = strtok(NULL, ","); if(!nick && msgs == 0) nick = parv[1]; else if(!nick) break; if( IsChanPrefix(*nick) && (IsPerson(sptr) && (chptr = hash_find_channel(nick, NullChn)))) { #ifdef FLUD #ifdef DEATHFLUD if(!notice && check_for_ctcp(parv[2]) && check_for_flud(sptr, NULL, chptr, 1)) return 0; if((flud = check_for_spam(sptr, NULL, chptr, parv[2]))) { if (check_for_flud(sptr, NULL, chptr, flud)) return 0; } #else /* DEATHFLUD */ if(!notice) if(check_for_ctcp(parv[2])) check_for_flud(sptr, NULL, chptr, 1); #endif /* DEATHFLUD */ #endif /* FLUD */ /* * Channel color blocking. Usually set with the +c chanmode. * - Andre Guibert de Bruet <*****@*****.**> */ if(chptr->mode.mode & MODE_NOCOLOR) strip_colour(parv[2]); switch (can_send(sptr, chptr)) { case 0: sendto_channel_message_butone(cptr, sptr, chptr, cmd, parv[2]); break; case MODE_QUIETUNIDENT: if (!notice) sendto_one(sptr, form_str(ERR_QUIETUNIDENT), me.name, parv[0], nick); break; case MODE_MODERATED: if (chptr->mode.mode & MODE_OPMODERATE) { /* The flag MODE_OPMODERATE will instruct sendto_channel_type() * to put bare #channel in the message (instead of @#channel); * it will still be sent to ops and servers with ops only. * Strange things will happen if the user is not banned * remotely. * -- jilles */ sendto_channel_type(cptr, sptr, chptr, MODE_CHANOP | MODE_OPMODERATE, nick, cmd, parv[2]); } else { if (!notice) sendto_one(sptr, form_str(ERR_CANNOTSENDTOCHAN), me.name, parv[0], nick); } break; default: break; } msgs++; continue; } /* ** @# type of channel msg? */ if(*nick == '@') type = MODE_CHANOP; else if(*nick == '+') type = MODE_CHANOP|MODE_VOICE; if(type) { /* Strip if using DALnet chanop/voice prefix. */ if (*(nick+1) == '@' || *(nick+1) == '+') { nick++; *nick = '@'; type = MODE_CHANOP|MODE_VOICE; } /* suggested by Mortiis */ if(!*nick) /* if its a '\0' dump it, there is no recipient */ { sendto_one(sptr, form_str(ERR_NORECIPIENT), me.name, parv[0], cmd); return -1; } if (!IsPerson(sptr)) /* This means, servers can't send messages */ return -1; /* At this point, nick+1 should be a channel name i.e. #foo or &foo * if the channel is found, fine, if not report an error */ if ( (chptr = hash_find_channel(nick+1, NullChn)) ) { #ifdef FLUD #ifdef DEATHFLUD if(!notice && check_for_ctcp(parv[2]) && check_for_flud(sptr, NULL, chptr, 1)) return 0; if((flud = check_for_spam(sptr, NULL, chptr, parv[2]))) { if (check_for_flud(sptr, NULL, chptr, flud)) return 0; } #else /* DEATHFLUD */ if(!notice) if(check_for_ctcp(parv[2])) check_for_flud(sptr, NULL, chptr, 1); #endif /* DEATHFLUD */ #endif /* FLUD */ if (!is_chan_op(sptr,chptr)) { if (!notice) { sendto_one(sptr, form_str(ERR_CANNOTSENDTOCHAN), me.name, parv[0], nick); } msgs++; continue; } else { sendto_channel_type(cptr, sptr, chptr, type, nick+1, cmd, parv[2]); } } else { if (!IsServer(sptr)) sendto_one(sptr, form_str(ERR_NOSUCHNICK), me.name, parv[0], nick); msgs++; continue; } return 0; } /* ** nickname addressed? */ if ((acptr = find_person(nick, NULL))) { #ifdef FLUD #ifdef DEATHFLUD if(!notice && MyConnect(sptr) && check_for_ctcp(parv[2]) && check_for_flud(sptr, acptr, NULL, 1)) return 0; if(MyConnect(sptr) && (flud = check_for_spam(sptr, acptr, NULL, parv[2]))) { if (check_for_flud(sptr, acptr, NULL, flud)) return 0; } #else /* DEATHFLUD */ if(!notice && MyConnect(sptr)) if(check_for_ctcp(parv[2])) if(check_for_flud(sptr, acptr, NULL, 1)) return 0; #endif /* DEATHFLUD */ #endif /* FLUD */ #ifdef ANTI_DRONE_FLOOD if(MyConnect(acptr) && IsClient(sptr) && !NoFloodProtection(sptr) && DRONETIME) { if((acptr->first_received_message_time+DRONETIME) < CurrentTime) { acptr->received_number_of_privmsgs=1; acptr->first_received_message_time = CurrentTime; acptr->drone_noticed = 0; } else { if(acptr->received_number_of_privmsgs > DRONECOUNT) { if(acptr->drone_noticed == 0) /* tiny FSM */ { sendto_ops_flag(UMODE_BOTS, "Possible Drone Flooder %s [%s@%s] on %s target: %s", sptr->name, sptr->username, sptr->host, sptr->user->server, acptr->name); acptr->drone_noticed = 1; } /* heuristic here, if target has been getting a lot * of privmsgs from clients, and sendq is above halfway up * its allowed sendq, then throw away the privmsg, otherwise * let it through. This adds some protection, yet doesn't * DOS the client. * -Dianora */ if(DBufLength(&acptr->sendQ) > (get_sendq(acptr)/2UL)) { if(acptr->drone_noticed == 1) /* tiny FSM */ { sendto_ops_flag(UMODE_BOTS, "ANTI_DRONE_FLOOD SendQ protection activated for %s", acptr->name); sendto_one(acptr, ":%s NOTICE %s :*** Notice -- Server drone flood protection activated for %s", me.name, acptr->name, acptr->name); acptr->drone_noticed = 2; } } if(DBufLength(&acptr->sendQ) <= (get_sendq(acptr)/4UL)) { if(acptr->drone_noticed == 2) { sendto_one(acptr, ":%s NOTICE %s :*** Notice -- Server drone flood protection de-activated for %s", me.name, acptr->name, acptr->name); acptr->drone_noticed = 1; } } if(acptr->drone_noticed > 1) return 0; } else acptr->received_number_of_privmsgs++; } } #endif /* * Simple herustic here... If PRIVMSG is locked down via * F:noidprivmsg:1, then act like every client is +E. * Otherwise, assume the normal behaviour. All in a nice * single if statement. --nenolod */ if (MyClient(sptr) && sptr != acptr && (GlobalSetOptions.noidprivmsg != 0 || HasUmode(acptr,UMODE_BLOCK_NOTID)) && !HasUmode(sptr,UMODE_IDENTIFIED) && !sptr->user->servlogin[0] && !HasUmode(acptr,UMODE_DONTBLOCK) && !HasUmode(sptr,UMODE_DONTBLOCK)) { /* Replace errbuf with either the default or custom message, * then send the numeric on... * --nenolod */ if (GlobalSetOptions.noidprivmsg != 0 && GlobalSetOptions.noidprivmsg_notice[0]) { strncpy_irc(errbuf, GlobalSetOptions.noidprivmsg_notice, BUFSIZE); } else { ircsnprintf(errbuf, BUFSIZE, get_str(STR_NOTID_DEFAULT), nick); } sendto_one(sptr, form_str(ERR_BLOCKING_NOTID), me.name, parv[0], errbuf); return 0; } #ifdef SILENCE /* only check silence masks at the recipient's server -- jilles */ if (!MyConnect(acptr) || !is_silenced(sptr, acptr)) { #endif if (MyConnect(sptr) && acptr->user && (sptr != acptr)) { #ifdef NCTCP /* NCTCP (umode +C) checks -- PMA */ if (parv[2][0] == 1) /* is CTCP */ /* Huh? No way, NOCTCP means NOCTCP. */ /* if (!HasUmode(sptr,UMODE_IMMUNE) && */ /* !HasUmode(acptr,UMODE_IMMUNE)) */ if (HasUmode(acptr,UMODE_NOCTCP) || /* block to +C */ (notice && HasUmode(sptr,UMODE_NOCTCP))) /* block replies from +C */ return 0; /* kill it! */ #endif /* NCTCP */ if (!notice && acptr->user->away) sendto_one(sptr, form_str(RPL_AWAY), me.name, parv[0], acptr->name, acptr->user->away); } { /* here's where we actually send the message */ int is_ctcp = check_for_ctcp(parv[2]); int cap = is_ctcp ? CAP_IDENTIFY_CTCP : CAP_IDENTIFY_MSG; sendto_prefix_one(acptr, sptr, ":%s %s %s :%s%s", parv[0], cmd, nick, !(acptr->caps & cap) ? "" : (HasUmode(sptr, UMODE_IDENTIFIED) ? "+" : "-"), parv[2]); } #ifdef SILENCE } #endif msgs++; continue; } /* Everything below here should be reserved for opers * as pointed out by Mortiis, user%[email protected] * syntax could be used to flood without FLUD protection * its also a delightful way for non-opers to find users who * have changed nicks -Dianora * * Grrr it was pointed out to me that x@service is valid * for non-opers too, and wouldn't allow for flooding/stalking * -Dianora * * Valid or not, @servername is unacceptable, it reveals what server * a person is on. Auspexen only. * -- asuffield */ /* ** the following two cases allow masks in NOTICEs ** (for OPERs only) (with +M -- asuffield) ** ** Armin, 8Jun90 ([email protected]) */ if ((*nick == '$' || *nick == '>')) { if(!HasUmode(sptr,UMODE_MASSNOTICE)) { sendto_one(sptr, form_str(ERR_NOSUCHNICK), me.name, parv[0], nick); return -1; } #ifdef NEED_TLD_FOR_MASS_NOTICE if (!(s = (char *)strrchr(nick, '.'))) { sendto_one(sptr, form_str(ERR_NOTOPLEVEL), me.name, parv[0], nick); msgs++; continue; } while (*++s) if (*s == '.' || *s == '*' || *s == '?') break; if (*s == '*' || *s == '?') { sendto_one(sptr, form_str(ERR_WILDTOPLEVEL), me.name, parv[0], nick); msgs++; continue; } #endif /* NEED_TLD_FOR_MASS_NOTICE */ sendto_match_butone(IsServer(cptr) ? cptr : NULL, sptr, nick + 1, (*nick == '>') ? MATCH_HOST : MATCH_SERVER, ":%s %s %s :%s", parv[0], cmd, nick, parv[2]); msgs++; continue; } /* ** user[%host]@server addressed? */ if ((server = (char *)strchr(nick, '@')) && (acptr = find_server(server + 1))) { int count = 0; /* Disable the whole farping mess for non-auspexen * -- asuffield */ if (!HasUmode(sptr,UMODE_AUSPEX)) { sendto_one(sptr, form_str(ERR_NOSUCHNICK), me.name, parv[0], nick); msgs++; continue; } /* Disable the user%host@server form for non-opers * -Dianora */ /* Disabled. This isn't very useful and I don't feel like mucking around with privs for it * -- asuffield */ if((char *)strchr(nick,'%')) { sendto_one(sptr, form_str(ERR_NOSUCHNICK), me.name, parv[0], nick); msgs++; continue; } /* ** Not destined for a user on me :-( */ if (!IsMe(acptr)) { sendto_one(acptr,":%s %s %s :%s", parv[0], cmd, nick, parv[2]); msgs++; continue; } *server = '\0'; /* special case opers@server */ /* We don't want this on OPN -- asuffield */ #if 0 if(!irccmp(nick,"opers") && SendWallops(sptr)) { sendto_realops("To opers: From %s: %s",sptr->name,parv[2]); msgs++; continue; } #endif if ((host = (char *)strchr(nick, '%'))) *host++ = '\0'; /* ** Look for users which match the destination host ** (no host == wildcard) and if one and one only is ** found connected to me, deliver message! */ acptr = find_userhost(nick, host, NULL, &count); if (server) *server = '@'; if (host) *--host = '%'; if (acptr) { if (count == 1) sendto_prefix_one(acptr, sptr, ":%s %s %s :%s", parv[0], cmd, nick, parv[2]); else if (!notice) sendto_one(sptr, form_str(ERR_TOOMANYTARGETS), me.name, parv[0], nick, MAX_MULTI_MESSAGES); } if (acptr) { msgs++; continue; } } /* Let's not send these remotely for channels */ if (MyConnect(sptr) || (nick[0] != '#')) sendto_one(sptr, form_str(ERR_NOSUCHNICK), me.name, parv[0], nick); msgs++; } if (strtok(NULL, ",")) sendto_one(sptr, form_str(ERR_TOOMANYTARGETS), me.name, parv[0], cmd, MAX_MULTI_MESSAGES); return 0; }
/* ** m_kill ** parv[0] = sender prefix ** parv[1] = kill victim(s) - comma separated list ** parv[2] = kill path */ DLLFUNC int m_kill(aClient *cptr, aClient *sptr, int parc, char *parv[]) { aClient *acptr; anUser *auser; char inpath[HOSTLEN * 2 + USERLEN + 5]; char *oinpath = get_client_name(cptr, FALSE); char *user, *path, *killer, *nick, *p, *s; int chasing = 0, kcount = 0; if (parc < 2 || *parv[1] == '\0') { sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "KILL"); return 0; } user = parv[1]; path = parv[2]; /* Either defined or NULL (parc >= 2!!) */ strlcpy(inpath, oinpath, sizeof inpath); #ifndef ROXnet if (IsServer(cptr) && (s = (char *)index(inpath, '.')) != NULL) *s = '\0'; /* Truncate at first "." */ #endif if (!IsPrivileged(cptr)) { sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } if (IsAnOper(cptr)) { if (BadPtr(path)) { sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "KILL"); return 0; } if (strlen(path) > (size_t)TOPICLEN) path[TOPICLEN] = '\0'; } if (MyClient(sptr)) user = (char *)canonize(user); for (p = NULL, nick = strtoken(&p, user, ","); nick; nick = strtoken(&p, NULL, ",")) { chasing = 0; if (!(acptr = find_client(nick, NULL))) { /* ** If the user has recently changed nick, we automaticly ** rewrite the KILL for this new nickname--this keeps ** servers in synch when nick change and kill collide */ if (!(acptr = get_history(nick, (long)KILLCHASETIMELIMIT))) { sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], nick); continue; } sendto_one(sptr, ":%s %s %s :*** KILL changed from %s to %s", me.name, IsWebTV(sptr) ? "PRIVMSG" : "NOTICE", parv[0], nick, acptr->name); chasing = 1; } if ((!MyConnect(acptr) && MyClient(cptr) && !OPCanGKill(cptr)) || (MyConnect(acptr) && MyClient(cptr) && !OPCanLKill(cptr))) { sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); continue; } if (IsServer(acptr) || IsMe(acptr)) { sendto_one(sptr, err_str(ERR_CANTKILLSERVER), me.name, parv[0]); continue; } if (!IsPerson(acptr)) { /* Nick exists but user is not registered yet: IOTW "doesn't exist". -- Syzop */ sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], nick); continue; } if (IsServices(acptr) && !(IsNetAdmin(sptr) || IsULine(sptr))) { sendto_one(sptr, err_str(ERR_KILLDENY), me.name, parv[0], parv[1]); return 0; } /* From here on, the kill is probably going to be successful. */ kcount++; if (!IsServer(sptr) && (kcount > MAXKILLS)) { sendto_one(sptr, ":%s %s %s :*** Too many targets, kill list was truncated. Maximum is %d.", me.name, IsWebTV(sptr) ? "PRIVMSG" : "NOTICE", parv[0], MAXKILLS); break; } if (!IsServer(cptr)) { /* ** The kill originates from this server, initialize path. ** (In which case the 'path' may contain user suplied ** explanation ...or some nasty comment, sigh... >;-) ** ** ...!operhost!oper ** ...!operhost!oper (comment) */ strlcpy(inpath, GetHost(cptr), sizeof inpath); if (kcount < 2) { /* Only check the path the first time around, or it gets appended to itself. */ if (!BadPtr(path)) { (void)ircsprintf(buf, "%s%s (%s)", cptr->name, IsOper(sptr) ? "" : "(L)", path); path = buf; } else path = cptr->name; } } else if (BadPtr(path)) path = "*no-path*"; /* Bogus server sending??? */ /* ** Notify all *local* opers about the KILL (this includes the one ** originating the kill, if from this server--the special numeric ** reply message is not generated anymore). ** ** Note: "acptr->name" is used instead of "user" because we may ** have changed the target because of the nickname change. */ auser = acptr->user; sendto_snomask_normal(SNO_KILLS, "*** Notice -- Received KILL message for %s!%s@%s from %s Path: %s!%s", acptr->name, auser->username, IsHidden(acptr) ? auser->virthost : auser->realhost, parv[0], inpath, path); #if defined(USE_SYSLOG) && defined(SYSLOG_KILL) if (IsOper(sptr)) syslog(LOG_DEBUG, "KILL From %s For %s Path %s!%s", parv[0], acptr->name, inpath, path); #endif /* * By otherguy */ ircd_log (LOG_KILL, "KILL (%s) by %s(%s!%s)", make_nick_user_host (acptr->name, acptr->user->username, GetHost(acptr)), parv[0], inpath, path); /* ** And pass on the message to other servers. Note, that if KILL ** was changed, the message has to be sent to all links, also ** back. ** Suicide kills are NOT passed on --SRB */ if (!MyConnect(acptr) || !MyConnect(sptr) || !IsAnOper(sptr)) { sendto_serv_butone(cptr, ":%s KILL %s :%s!%s", parv[0], acptr->name, inpath, path); if (chasing && IsServer(cptr)) sendto_one(cptr, ":%s KILL %s :%s!%s", me.name, acptr->name, inpath, path); acptr->flags |= FLAGS_KILLED; } /* ** Tell the victim she/he has been zapped, but *only* if ** the victim is on current server--no sense in sending the ** notification chasing the above kill, it won't get far ** anyway (as this user don't exist there any more either) */ if (MyConnect(acptr)) sendto_prefix_one(acptr, sptr, ":%s KILL %s :%s!%s", parv[0], acptr->name, inpath, path); /* ** Set FLAGS_KILLED. This prevents exit_one_client from sending ** the unnecessary QUIT for this. (This flag should never be ** set in any other place) */ if (MyConnect(acptr) && MyConnect(sptr) && IsAnOper(sptr)) (void)ircsprintf(buf2, "[%s] Local kill by %s (%s)", me.name, sptr->name, BadPtr(parv[2]) ? sptr->name : parv[2]); else { if ((killer = index(path, ' '))) { while ((killer >= path) && *killer && *killer != '!') killer--; if (!*killer) killer = path; else killer++; } else killer = path; (void)ircsprintf(buf2, "Killed (%s)", killer); } if (MyClient(sptr)) RunHook3(HOOKTYPE_LOCAL_KILL, sptr, acptr, parv[2]); if (exit_client(cptr, acptr, sptr, buf2) == FLUSH_BUFFER) return FLUSH_BUFFER; } return 0; }
/* ** DoNumeric (replacement for the old do_numeric) ** ** parc number of arguments ('sender' counted as one!) ** parv[0] pointer to 'sender' (may point to empty string) (not used) ** parv[1]..parv[parc-1] ** pointers to additional parameters, this is a NULL ** terminated list (parv[parc] == NULL). ** ** *WARNING* ** Numerics are mostly error reports. If there is something ** wrong with the message, just *DROP* it! Don't even think of ** sending back a neat error message -- big danger of creating ** a ping pong error message... */ int do_numeric(int numeric, aClient *cptr, aClient *sptr, int parc, char *parv[]) { aClient *acptr; aChannel *chptr; char *nick, *p; int i; /* Is this an outgoing connect, and we get a numeric 451 (not registered) back for the * magic command __PANGPANG__ and we did not send a SERVER message yet? * Then this means we are dealing with an Unreal server <3.2.9 and we should send the * SERVER command right now. */ if (!IsServer(sptr) && !IsPerson(sptr) && (numeric == 451) && (parc > 2) && strstr(parv[1], "__PANGPANG__") && IsHandshake(cptr) && sptr->serv && !IsServerSent(sptr)) { send_server_message(sptr); return 0; } if (parc < 1 || !IsServer(sptr)) return 0; /* Remap low number numerics. */ if (numeric < 100) numeric += 100; /* ** Prepare the parameter portion of the message into 'buffer'. ** (Because the buffer is twice as large as the message buffer ** for the socket, no overflow can occur here... ...on current ** assumptions--bets are off, if these are changed --msa) ** Note: if buffer is non-empty, it will begin with SPACE. */ buffer[0] = '\0'; if (parc > 2) { /* * For strlcat nazis, please read above */ for (i = 2; i < (parc - 1); i++) { (void)strcat(buffer, " "); (void)strcat(buffer, parv[i]); } (void)strcat(buffer, " :"); (void)strcat(buffer, parv[parc - 1]); } else sendto_realops("do_numeric( %i, %s, %s, %i, { %s, %s } )!", numeric, cptr->name, sptr->name, parc, parv[0], parv[1] ? parv[1] : "<null>"); for (; (nick = strtoken(&p, parv[1], ",")); parv[1] = NULL) { if ((acptr = find_client(nick, (aClient *)NULL))) { /* ** Drop to bit bucket if for me... ** ...one might consider sendto_ops ** here... --msa ** And so it was done. -avalon ** And regretted. Dont do it that way. Make sure ** it goes only to non-servers. -avalon ** Check added to make sure servers don't try to loop ** with numerics which can happen with nick collisions. ** - Avalon */ if (!IsMe(acptr) && IsPerson(acptr)) { /* Added for .U3.2. drop remote 'You are not on ** that channel', we should be synced anyway, ** and this is an annoying message with TSpre7 ** still on the net; would result in numeric 442 for ** every KICK... Can be removed when TSpre7 is gone. ** --Run if (numeric==ERR_NOTONCHANNEL) return 0; */ sendto_prefix_one(acptr, sptr, ":%s %d %s%s", parv[0], numeric, nick, buffer); } else if (IsServer(acptr) && acptr->from != cptr) sendto_prefix_one(acptr, sptr, ":%s %d %s%s", parv[0], numeric, nick, buffer); } else if ((acptr = find_server_quick(nick))) { if (!IsMe(acptr) && acptr->from != cptr) sendto_prefix_one(acptr, sptr, ":%s %d %s%s", parv[0], numeric, nick, buffer); } else if ((chptr = find_channel(nick, (aChannel *)NULL))) sendto_channel_butone(cptr, sptr, chptr, ":%s %d %s%s", parv[0], numeric, chptr->chname, buffer); } return 0; }
/* ** DoNumeric (replacement for the old do_numeric) ** ** parc number of arguments ('sender' counted as one!) ** parv[0] pointer to 'sender' (may point to empty string) (not used) ** parv[1]..parv[parc-1] ** pointers to additional parameters, this is a NULL ** terminated list (parv[parc] == NULL). ** ** *WARNING* ** Numerics are mostly error reports. If there is something ** wrong with the message, just *DROP* it! Don't even think of ** sending back a neat error message -- big danger of creating ** a ping pong error message... */ int do_numeric(int numeric, aClient *cptr, aClient *sptr, int parc, char *parv[]) { aClient *acptr; aChannel *chptr; char *nick, *p; int i; if (parc < 1 || !IsServer(sptr)) return 0; /* Remap low number numerics. */ if (numeric < 100) numeric += 100; /* ** Prepare the parameter portion of the message into 'buffer'. ** (Because the buffer is twice as large as the message buffer ** for the socket, no overflow can occur here... ...on current ** assumptions--bets are off, if these are changed --msa) ** Note: if buffer is non-empty, it will begin with SPACE. */ buffer[0] = '\0'; if (parc > 1) { for (i = 2; i < (parc - 1); i++) { strcat(buffer, " "); strcat(buffer, parv[i]); } strcat(buffer, " :"); strcat(buffer, parv[parc-1]); } for (; (nick = strtok_r(parv[1], ",", &p)); parv[1] = NULL) { if ((acptr = find_client(nick, (aClient *)NULL))) { /* ** Drop to bit bucket if for me... ** ...one might consider sendto_ops ** here... --msa ** And so it was done. -avalon ** And regretted. Dont do it that way. Make sure ** it goes only to non-servers. -avalon ** Check added to make sure servers don't try to loop ** with numerics which can happen with nick collisions. ** - Avalon */ if (!IsMe(acptr) && IsPerson(acptr)) { /* Added for .U3.2. drop remote 'You are not on ** that channel', we should be synced anyway, ** and this is an annoying message with TSpre7 ** still on the net; would result in numeric 442 for ** every KICK... Can be removed when TSpre7 is gone. ** --Run */ if (numeric==ERR_NOTONCHANNEL) return 0; sendto_prefix_one(acptr, sptr,":%s %d %s%s", parv[0], numeric, nick, buffer); } else if (IsServer(acptr) && acptr->from != cptr) sendto_prefix_one(acptr, sptr,":%s %d %s%s", parv[0], numeric, nick, buffer); } else if ((acptr = find_server(nick, (aClient *)NULL))) { if (!IsMe(acptr) && acptr->from != cptr) sendto_prefix_one(acptr, sptr,":%s %d %s%s", parv[0], numeric, nick, buffer); } else if ((chptr = find_channel(nick, (aChannel *)NULL))) sendto_channel_butone(cptr,sptr,chptr,":%s %d %s%s", parv[0], numeric, chptr->chname, buffer); } return 0; }