/*! \brief PONG command handler * * \param source_p Pointer to allocated Client struct from which the message * originally comes from. This can be a local or remote client. * \param parc Integer holding the number of supplied arguments. * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL * pointers. * \note Valid arguments for this command are: * - parv[0] = command * - parv[1] = origin * - parv[2] = destination */ static int ms_pong(struct Client *source_p, int parc, char *parv[]) { struct Client *target_p = NULL; const char *destination = NULL; if (parc < 2 || EmptyString(parv[1])) { sendto_one_numeric(source_p, &me, ERR_NOORIGIN); return 0; } destination = parv[2]; /* Now attempt to route the PONG, comstud pointed out routable PING * is used for SPING. routable PING should also probably be left in * -Dianora * That being the case, we will route, but only for registered clients (a * case can be made to allow them only from servers). -Shadowfax */ if (!EmptyString(destination) && match(destination, me.name) && irccmp(destination, me.id)) { if ((target_p = hash_find_client(destination)) || (target_p = hash_find_id(destination))) sendto_one(target_p, ":%s PONG %s %s", ID_or_name(source_p, target_p), parv[1], ID_or_name(target_p, target_p)); else if (!IsDigit(*destination)) sendto_one_numeric(source_p, &me, ERR_NOSUCHSERVER, destination); } return 0; }
/*! \brief NICK command handler * * \param source_p Pointer to allocated Client struct from which the message * originally comes from. This can be a local or remote client. * \param parc Integer holding the number of supplied arguments. * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL * pointers. * \note Valid arguments for this command are: * * server -> server nick change * - parv[0] = command * - parv[1] = nickname * - parv[2] = timestamp */ static int ms_nick(struct Client *source_p, int parc, char *parv[]) { struct Client *target_p = NULL; if (parc != 3 || EmptyString(parv[parc - 1])) return 0; if (IsServer(source_p)) return 0; /* Servers can't change nicks.. */ if (check_clean_nick(source_p, parv[1], source_p->servptr)) return 0; /* If the nick doesn't exist, allow it and process like normal */ if ((target_p = hash_find_client(parv[1])) == NULL) change_remote_nick(source_p, parv); else if (IsUnknown(target_p)) { /* We're not living in the past anymore, an unknown client is local only. */ exit_client(target_p, "Overridden by other sign on"); change_remote_nick(source_p, parv); } else if (target_p == source_p) { if (strcmp(target_p->name, parv[1])) change_remote_nick(source_p, parv); } else if (perform_nick_change_collides(source_p, target_p, parc, parv)) change_remote_nick(source_p, parv); return 0; }
/* * Whats happening in this next loop ? Well, it takes a name like * foo.bar.edu and proceeds to earch for *.edu and then *.bar.edu. * This is for checking full server names against masks although * it isnt often done this way in lieu of using matches(). * * Rewrote to do *.bar.edu first, which is the most likely case, * also made const correct * --Bleep */ static struct Client* hash_find_masked_server(const char* name) { char buf[HOSTLEN + 1]; char* p = buf; char* s; struct Client* server; if ('*' == *name || '.' == *name) return 0; /* * copy the damn thing and be done with it */ strncpy_irc(buf, name, HOSTLEN + 1); buf[HOSTLEN] = '\0'; while ((s = strchr(p, '.')) != 0) { *--s = '*'; /* * Dont need to check IsServer() here since nicknames cant * have *'s in them anyway. */ if ((server = hash_find_client(s, NULL))) return server; p = s + 2; } return 0; }
/* * add_to_client_hash_table */ void add_to_client_hash_table(const char* name, struct Client* cptr) { struct Client *acptr; unsigned int hashv; assert(0 != name); assert(0 != cptr); if ((acptr = hash_find_client(name, NULL))) { sendto_ops_flag(UMODE_DEBUG, "WTF: Already got client %s in hash table, but something tried to add it again. Dumping core...", name); logprintf(L_WARN, "WTF: Already got %s in hash table but something tried to add it again, dumping core", name); flush_connections(0); abort(); } hashv = hash_nick_name(name); if ((clientTable[hashv].links == 0) && (clientTable[hashv].list != NULL)) { sendto_ops_flag(UMODE_DEBUG, "WTF: clientTable[%d].links == 0 but list not NULL. Whacking list...", hashv); logprintf(L_WARN, "WTF: clientTable[%d].links == 0 but list not NULL. Whacking list...", hashv); clientTable[hashv].list = NULL; } cptr->hnext = (struct Client*) clientTable[hashv].list; clientTable[hashv].list = (void*) cptr; ++clientTable[hashv].links; ++clientTable[hashv].hits; }
static void mo_chgname(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct Client *target_p = NULL; if (MyClient(source_p) && !HasUMode(source_p, UMODE_ADMIN)) { sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "CHGNAME"); return; } if (EmptyString(parv[2])) { parv[2] = parv[1]; target_p = source_p; } else if ((target_p = hash_find_client(parv[1])) == NULL) { sendto_one(source_p, form_str(ERR_NOSUCHNICK), me.name, source_p->name, parv[1]); return; } if (strlen(parv[2]) > REALLEN || !*parv[2]) { sendto_one(source_p, ":%s NOTICE %s :Invalid realname", me.name, source_p->name); return; } if (parc > 3 && MyClient(source_p)) sendto_one(source_p, ":%s NOTICE %s :Warning -- too many parameters " "for CHGNAME. You are probably missing a : before the new " "IRC name.", me.name, source_p->name); strlcpy(target_p->info, parv[2], sizeof(target_p->info)); if (MyClient(source_p)) { sendto_server(client_p, NOCAPS, NOCAPS, ":%s ENCAP * CHGNAME %s :%s", source_p->name, target_p->name, parv[2]); sendto_one(source_p, ":%s NOTICE %s :%s realname changed to [%s]", me.name, source_p->name, target_p->name, target_p->info); } if (MyClient(target_p) && IsClient(source_p)) sendto_one(target_p, ":%s NOTICE %s :Your realname is now [%s]", me.name, target_p->name, target_p->info); }
/*! \brief NICK command handler (called by unregistered, * locally connected clients) * * \param client_p Pointer to allocated Client struct with physical connection * to this server, i.e. with an open socket connected. * \param source_p Pointer to allocated Client struct from which the message * originally comes from. This can be a local or remote client. * \param parc Integer holding the number of supplied arguments. * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL * pointers. * \note Valid arguments for this command are: * - parv[0] = sender prefix * - parv[1] = nickname */ static void mr_nick(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { char nick[NICKLEN + 1] = { '\0' }; char *s = NULL; struct Client *target_p = NULL; struct MaskItem *conf = NULL; if (parc < 2 || EmptyString(parv[1])) { sendto_one(source_p, form_str(ERR_NONICKNAMEGIVEN), me.name, source_p->name[0] ? source_p->name : "*"); return; } /* Terminate the nick at the first ~ */ if ((s = strchr(parv[1], '~')) != NULL) *s = '\0'; /* Copy the nick and terminate it */ strlcpy(nick, parv[1], IRCD_MIN(sizeof(nick), ServerInfo.max_nick_length + 1)); /* Check the nickname is ok */ if (!valid_nickname(nick, 1)) { sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME), me.name, source_p->name[0] ? source_p->name : "*", parv[1], "Erroneous Nickname"); return; } /* Check if the nick is resv'd */ if ((conf = find_matching_name_conf(CONF_NRESV, nick, NULL, NULL, 0))) { ++conf->count; sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME), me.name, source_p->name[0] ? source_p->name : "*", nick, conf->reason); sendto_realops_flags(UMODE_REJ, L_ALL, SEND_NOTICE, "Forbidding reserved nick [%s] from user %s", nick, get_client_name(client_p, HIDE_IP)); return; } if ((target_p = hash_find_client(nick)) == NULL) set_initial_nick(source_p, nick); else if (source_p == target_p) strlcpy(source_p->name, nick, sizeof(source_p->name)); else sendto_one(source_p, form_str(ERR_NICKNAMEINUSE), me.name, "*", nick); }
/*! \brief UID command handler (called by servers) * * \param client_p Pointer to allocated Client struct with physical connection * to this server, i.e. with an open socket connected. * \param source_p Pointer to allocated Client struct from which the message * originally comes from. This can be a local or remote client. * \param parc Integer holding the number of supplied arguments. * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL * pointers. * \note Valid arguments for this command are: * * server introducing new nick (without services support) * - parv[0] = sender prefix * - parv[1] = nickname * - parv[2] = hop count * - parv[3] = TS * - parv[4] = umode * - parv[5] = username * - parv[6] = hostname * - parv[7] = ip * - parv[8] = uid * - parv[9] = ircname (gecos) * * server introducing new nick (with services support) * - parv[ 0] = sender prefix * - parv[ 1] = nickname * - parv[ 2] = hop count * - parv[ 3] = TS * - parv[ 4] = umode * - parv[ 5] = username * - parv[ 6] = hostname * - parv[ 7] = ip * - parv[ 8] = uid * - parv[ 9] = services id (timestamp) * - parv[10] = ircname (gecos) */ static void ms_uid(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct Client *target_p = NULL; time_t newts = 0; const char *svsid = "0"; if (parc < 10 || EmptyString(parv[parc-1])) return; if (check_clean_nick(client_p, source_p, parv[1], source_p) || check_clean_user(client_p, parv[1], parv[5], source_p) || check_clean_host(client_p, parv[1], parv[6], source_p)) return; newts = atol(parv[3]); svsid = parc == 11 ? parv[9] : "0"; /* * If there is an ID collision, kill our client, and kill theirs. * This may generate 401's, but it ensures that both clients always * go, even if the other server refuses to do the right thing. */ if ((target_p = hash_find_id(parv[8])) != NULL) { sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE, "ID collision on %s(%s <- %s)(both killed)", target_p->name, target_p->from->name, client_p->name); kill_client_ll_serv_butone(NULL, target_p, "%s (ID collision)", me.name); ++ServerStats.is_kill; AddFlag(target_p, FLAGS_KILLED); exit_client(target_p, &me, "ID Collision"); return; } if ((target_p = hash_find_client(parv[1])) == NULL) uid_from_server(client_p, source_p, parc, parv, newts, svsid, parv[1], parv[parc-1]); else if (IsUnknown(target_p)) { exit_client(target_p, &me, "Overridden"); uid_from_server(client_p, source_p, parc, parv, newts, svsid, parv[1], parv[parc-1]); } else perform_nick_collides(source_p, client_p, target_p, parc, parv, newts, svsid, parv[1], parv[parc-1], parv[8]); }
/*! \brief UID command handler * * \param source_p Pointer to allocated Client struct from which the message * originally comes from. This can be a local or remote client. * \param parc Integer holding the number of supplied arguments. * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL * pointers. * \note Valid arguments for this command are: * * server introducing new nick/UID (without services support) * - parv[0] = command * - parv[1] = nickname * - parv[2] = hop count * - parv[3] = TS * - parv[4] = umode * - parv[5] = username * - parv[6] = hostname * - parv[7] = ip * - parv[8] = uid * - parv[9] = ircname (gecos) * * server introducing new nick/UID (with services support) * - parv[ 0] = command * - parv[ 1] = nickname * - parv[ 2] = hop count * - parv[ 3] = TS * - parv[ 4] = umode * - parv[ 5] = username * - parv[ 6] = hostname * - parv[ 7] = ip * - parv[ 8] = uid * - parv[ 9] = services id (account name) * - parv[10] = ircname (gecos) */ static int ms_uid(struct Client *source_p, int parc, char *parv[]) { struct Client *target_p = NULL; if (check_clean_nick(source_p, parv[1], source_p) || check_clean_user(source_p, parv[1], parv[5], source_p) || check_clean_host(source_p, parv[1], parv[6], source_p)) return 0; /* * If there is an ID collision, kill our client, and kill theirs. * This may generate 401's, but it ensures that both clients always * go, even if the other server refuses to do the right thing. */ if ((target_p = hash_find_id(parv[8]))) { sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE, "ID collision on %s(%s <- %s)(both killed)", target_p->name, target_p->from->name, source_p->from->name); sendto_server(NULL, 0, 0, ":%s KILL %s :%s (ID collision)", me.id, target_p->id, me.name); ++ServerStats.is_kill; AddFlag(target_p, FLAGS_KILLED); exit_client(target_p, "ID Collision"); return 0; } if ((target_p = hash_find_client(parv[1])) == NULL) uid_from_server(source_p, parc, parv); else if (IsUnknown(target_p)) { exit_client(target_p, "Overridden by other sign on"); uid_from_server(source_p, parc, parv); } else if (perform_uid_introduction_collides(source_p, target_p, parc, parv)) uid_from_server(source_p, parc, parv); return 0; }
/*! \brief NICK command handler * * \param source_p Pointer to allocated Client struct from which the message * originally comes from. This can be a local or remote client. * \param parc Integer holding the number of supplied arguments. * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL * pointers. * \note Valid arguments for this command are: * - parv[0] = command * - parv[1] = nickname */ static int mr_nick(struct Client *source_p, int parc, char *parv[]) { char nick[NICKLEN + 1] = ""; struct Client *target_p = NULL; struct MaskItem *conf = NULL; if (parc < 2 || EmptyString(parv[1])) { sendto_one_numeric(source_p, &me, ERR_NONICKNAMEGIVEN); return 0; } /* Copy the nick and terminate it */ strlcpy(nick, parv[1], IRCD_MIN(sizeof(nick), ConfigServerInfo.max_nick_length + 1)); /* Check the nickname is ok */ if (!valid_nickname(nick, 1)) { sendto_one_numeric(source_p, &me, ERR_ERRONEUSNICKNAME, parv[1], "Erroneous Nickname"); return 0; } /* Check if the nick is resv'd */ if ((conf = find_matching_name_conf(CONF_NRESV, nick, NULL, NULL, 0))) { ++conf->count; sendto_one_numeric(source_p, &me, ERR_ERRONEUSNICKNAME, nick, conf->reason); sendto_realops_flags(UMODE_REJ, L_ALL, SEND_NOTICE, "Forbidding reserved nick %s from user %s", nick, get_client_name(source_p, HIDE_IP)); return 0; } if ((target_p = hash_find_client(nick)) == NULL || target_p == source_p) set_initial_nick(source_p, nick); else sendto_one_numeric(source_p, &me, ERR_NICKNAMEINUSE, target_p->name); return 0; }
/*! \brief NICK command handler (called by servers and remotely * connected clients) * * \param client_p Pointer to allocated Client struct with physical connection * to this server, i.e. with an open socket connected. * \param source_p Pointer to allocated Client struct from which the message * originally comes from. This can be a local or remote client. * \param parc Integer holding the number of supplied arguments. * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL * pointers. * \note Valid arguments for this command are: * * server -> server nick change * - parv[0] = sender prefix * - parv[1] = nickname * - parv[2] = TS when nick change * * server introducing new nick (without services support) * - parv[0] = sender prefix * - parv[1] = nickname * - parv[2] = hop count * - parv[3] = TS * - parv[4] = umode * - parv[5] = username * - parv[6] = hostname * - parv[7] = server * - parv[8] = ircname * * server introducing new nick (with services support) * - parv[0] = sender prefix * - parv[1] = nickname * - parv[2] = hop count * - parv[3] = TS * - parv[4] = umode * - parv[5] = username * - parv[6] = hostname * - parv[7] = server * - parv[8] = services id (timestamp) * - parv[9] = ircname */ static void ms_nick(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct Client *target_p = NULL; time_t newts = 0; const char *svsid = "0"; if (parc < 3 || EmptyString(parv[parc - 1])) return; if (parc >= 9) { struct Client *server_p = hash_find_server(parv[7]); if (server_p == NULL) { sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE, "Invalid server %s from %s for NICK %s", parv[7], source_p->name, parv[1]); sendto_one(client_p, ":%s KILL %s :%s (Server doesn't exist!)", me.name, parv[1], me.name); return; } if (check_clean_nick(client_p, source_p, parv[1], server_p) || check_clean_user(client_p, parv[1], parv[5], server_p) || check_clean_host(client_p, parv[1], parv[6], server_p)) return; if (IsServer(source_p)) newts = atol(parv[3]); if (IsServer(source_p) && parc == 10) svsid = parv[8]; } else if (parc == 3) { if (IsServer(source_p)) /* Servers can't change nicks.. */ return; if (check_clean_nick(client_p, source_p, parv[1], source_p->servptr)) return; newts = atol(parv[2]); } /* If the nick doesnt exist, allow it and process like normal */ if ((target_p = hash_find_client(parv[1])) == NULL) nick_from_server(client_p, source_p, parc, parv, newts, svsid, parv[1], parv[parc-1]); else if (IsUnknown(target_p)) { /* We're not living in the past anymore, an unknown client is local only. */ exit_client(target_p, &me, "Overridden"); nick_from_server(client_p, source_p, parc, parv, newts, svsid, parv[1], parv[parc-1]); } else if (target_p == source_p) { if (strcmp(target_p->name, parv[1])) nick_from_server(client_p, source_p, parc, parv, newts, svsid, parv[1], parv[parc-1]); } else perform_nick_collides(source_p, client_p, target_p, parc, parv, newts, svsid, parv[1], parv[parc-1], NULL); }
/*! \brief NICK command handler (called by already registered, * locally connected clients) * * \param client_p Pointer to allocated Client struct with physical connection * to this server, i.e. with an open socket connected. * \param source_p Pointer to allocated Client struct from which the message * originally comes from. This can be a local or remote client. * \param parc Integer holding the number of supplied arguments. * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL * pointers. * \note Valid arguments for this command are: * - parv[0] = sender prefix * - parv[1] = nickname */ static void m_nick(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { char nick[NICKLEN + 1] = { '\0' }; struct Client *target_p = NULL; struct MaskItem *conf = NULL; assert(source_p == client_p); if (parc < 2 || EmptyString(parv[1])) { sendto_one(source_p, form_str(ERR_NONICKNAMEGIVEN), me.name, source_p->name); return; } /* mark end of grace period, to prevent nickflooding */ if (!IsFloodDone(source_p)) flood_endgrace(source_p); /* terminate nick to NICKLEN */ strlcpy(nick, parv[1], IRCD_MIN(sizeof(nick), ServerInfo.max_nick_length + 1)); /* check the nickname is ok */ if (!valid_nickname(nick, 1)) { sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME), me.name, source_p->name, nick, "Erroneous Nickname"); return; } if (!IsExemptResv(source_p) && !(HasUMode(source_p, UMODE_OPER) && ConfigFileEntry.oper_pass_resv) && (conf = find_matching_name_conf(CONF_NRESV, nick, NULL, NULL, 0))) { ++conf->count; sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME), me.name, source_p->name, nick, conf->reason); sendto_realops_flags(UMODE_REJ, L_ALL, SEND_NOTICE, "Forbidding reserved nick [%s] from user %s", nick, get_client_name(client_p, HIDE_IP)); return; } if ((target_p = hash_find_client(nick)) == NULL) change_local_nick(source_p, nick); else if (target_p == source_p) { /* * If (target_p == source_p) the client is changing nicks between * equivalent nicknames ie: [nick] -> {nick} */ /* Check the nick isn't exactly the same */ if (strcmp(target_p->name, nick)) change_local_nick(source_p, nick); } else if (IsUnknown(target_p)) { /* * If the client that has the nick isn't registered yet (nick but no * user) then drop the unregged client */ exit_client(target_p, &me, "Overridden"); change_local_nick(source_p, nick); } else sendto_one(source_p, form_str(ERR_NICKNAMEINUSE), me.name, source_p->name, nick); }
int m_hash(struct Client *cptr, struct Client *sptr,int parc,char *parv[]) { register int l; register int i; register struct HashEntry* tab; struct HashEntry* table; struct tm* tmptr; int deepest = 0; int deeplink = 0; int showlist = 0; int tothits = 0; int mosthit = 0; int mosthits = 0; int used = 0; int used_now = 0; int totlink = 0; int size = U_MAX; char ch; int out = 0; int link_pop[10]; char result_buf[256]; char hash_log_file[256]; char timebuffer[MAX_DATE_STRING]; if (!MyClient(sptr) || !HasUmode(sptr,UMODE_DEBUG)) { sendto_one(sptr, form_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } if(parc > 1) { if(!irccmp(parv[1],"iphash")) { iphash_stats(cptr,sptr,parc,parv,-1); return 0; } else if(!irccmp(parv[1],"Diphash")) { tmptr = localtime(&CurrentTime); strftime(timebuffer, MAX_DATE_STRING, "%Y%m%d%H%M", tmptr); sprintf(hash_log_file, "%s.%s", hash_log_file_base, timebuffer); if ((out = open(hash_log_file, O_RDWR | O_APPEND | O_CREAT,0664))==-1) sendto_one(sptr, ":%s NOTICE %s :Problem opening %s", me.name, parv[0], hash_log_file); else sendto_one(sptr, ":%s NOTICE %s :Writing hash log to %s", me.name, parv[0], hash_log_file); iphash_stats(cptr,sptr,parc,parv,out); return 0; } ch = *parv[1]; if (IsLower(ch)) { table = clientTable; } else { table = channelTable; size = CH_MAX; } if (ch == 'L' || ch == 'l') { tmptr = localtime(&CurrentTime); strftime(timebuffer, MAX_DATE_STRING, "%Y%m%d%H%M", tmptr); sprintf(hash_log_file, "%s-%cdump.%s", hash_log_file_base, ch, timebuffer); showlist = 1; if ((out = open(hash_log_file, O_RDWR|O_APPEND|O_CREAT,0664))==-1) sendto_one(sptr, ":%s NOTICE %s :Problem opening %s ", me.name, parv[0], hash_log_file); else sendto_one(sptr, ":%s NOTICE %s :Writing hash log to %s ", me.name, parv[0], hash_log_file); } } else { ch = '\0'; table = clientTable; } for (i = 0; i < 10; i++) link_pop[i] = 0; for (i = 0; i < size; i++) { tab = &table[i]; l = tab->links; if (showlist) { /* sendto_one(sptr, "NOTICE %s :Hash Entry:%6d Hits:%7d Links:%6d", parv[0], i, tab->hits, l); */ if(out >= 0) { sprintf(result_buf,"Hash Entry:%6d Hits;%7d Links:%6d\n", i, tab->hits, l); write(out,result_buf,strlen(result_buf)); } } if (l > 0) { if (l < 10) link_pop[l]++; else link_pop[9]++; used_now++; totlink += l; if (l > deepest) { deepest = l; deeplink = i; } } else link_pop[0]++; l = tab->hits; if (l) { used++; tothits += l; if (l > mosthits) { mosthits = l; mosthit = i; } } } if(showlist && (out >= 0)) (void)close(out); switch((int)ch) { case 'V' : case 'v' : { register struct Client* acptr; int bad = 0, listlength = 0; for (acptr = GlobalClientList; acptr; acptr = acptr->next) { if (hash_find_client(acptr->name,acptr) != acptr) { if (ch == 'V') sendto_one(sptr, "NOTICE %s :Bad hash for %s", parv[0], acptr->name); bad++; } listlength++; } sendto_one(sptr,"NOTICE %s :List Length: %d Bad Hashes: %d", parv[0], listlength, bad); } case 'P' : case 'p' : for (i = 0; i < 10; i++) sendto_one(sptr,"NOTICE %s :Entires with %d links : %d", parv[0], i, link_pop[i]); return (0); case 'r' : { register struct Client *acptr; sendto_one(sptr,"NOTICE %s :Rehashing Client List.", parv[0]); clear_client_hash_table(); for (acptr = GlobalClientList; acptr; acptr = acptr->next) add_to_client_hash_table(acptr->name, acptr); break; } case 'R' : { register struct Channel *acptr; sendto_one(sptr,"NOTICE %s :Rehashing Channel List.", parv[0]); clear_channel_hash_table(); for (acptr = channel; acptr; acptr = acptr->nextch) (void)add_to_channel_hash_table(acptr->chname, acptr); break; } case 'H' : if (parc > 2) sendto_one(sptr,"NOTICE %s :%s hash to entry %d", parv[0], parv[2], hash_channel_name(parv[2])); return (0); case 'h' : if (parc > 2) sendto_one(sptr,"NOTICE %s :%s hash to entry %d", parv[0], parv[2], hash_nick_name(parv[2])); return (0); case 'n' : { struct Client *tmp; int max; if (parc <= 2) return (0); l = atoi(parv[2]) % U_MAX; if (parc > 3) max = atoi(parv[3]) % U_MAX; else max = l; for (;l <= max; l++) for (i = 0, tmp = (struct Client *)clientTable[l].list; tmp; i++, tmp = tmp->hnext) { if (parv[1][2] == '1' && tmp != tmp->from) continue; sendto_one(sptr,"NOTICE %s :Node: %d #%d %s", parv[0], l, i, tmp->name); } return (0); } case 'N' : { struct Channel *tmp; int max; if (parc <= 2) return (0); l = atoi(parv[2]) % CH_MAX; if (parc > 3) max = atoi(parv[3]) % CH_MAX; else max = l; for (;l <= max; l++) for (i = 0, tmp = (struct Channel*) channelTable[l].list; tmp; i++, tmp = tmp->hnextch) sendto_one(sptr,"NOTICE %s :Node: %d #%d %s", parv[0], l, i, tmp->chname); return (0); } #ifdef DEBUGMODE case 'S' : sendto_one(sptr,"NOTICE %s :Entries Hashed: %d NonEmpty: %d of %d", parv[0], totlink, used_now, size); if (!used_now) used_now = 1; sendto_one(sptr,"NOTICE %s :Hash Ratio (av. depth): %f %%Full: %f", parv[0], (float)((1.0 * totlink) / (1.0 * used_now)), (float)((1.0 * used_now) / (1.0 * size))); sendto_one(sptr,"NOTICE %s :Deepest Link: %d Links: %d", parv[0], deeplink, deepest); if (!used) used = 1; sendto_one(sptr,"NOTICE %s :Total Hits: %d Unhit: %d Av Hits: %f", parv[0], tothits, size-used, (float)((1.0 * tothits) / (1.0 * used))); sendto_one(sptr,"NOTICE %s :Entry Most Hit: %d Hits: %d", parv[0], mosthit, mosthits); sendto_one(sptr,"NOTICE %s :Client hits %d miss %d", parv[0], clhits, clmiss); sendto_one(sptr,"NOTICE %s :Channel hits %d miss %d", parv[0], chhits, chmiss); return 0; #endif } return 0; }
/* * parse a buffer. * * NOTE: parse() should not be called recusively by any other functions! */ void parse(struct Client *client_p, char *pbuffer, char *bufend) { struct Client *from = client_p; struct Message *message = NULL; char *para[MAXPARA + 2]; /* <command> + <parameters> + NULL */ char *ch = NULL; char *s = NULL; unsigned int numeric = 0; unsigned int parc = 0; unsigned int paramcount; if (IsDead(client_p)) return; assert(client_p->connection); assert(client_p->connection->fd); assert(client_p->connection->fd->flags.open); assert((bufend - pbuffer) < IRCD_BUFSIZE); for (ch = pbuffer; *ch == ' '; ++ch) /* Skip spaces */ ; if (*ch == ':') { /* * Copy the prefix to 'sender' assuming it terminates * with SPACE (or NULL, which is an error, though). */ const char *const sender = ++ch; if ((s = strchr(ch, ' '))) { *s = '\0'; ch = ++s; } if (*sender && IsServer(client_p)) { if ((from = hash_find_id(sender)) == NULL) from = hash_find_client(sender); /* * Hmm! If the client corresponding to the prefix is not found--what is * the correct action??? Now, I will ignore the message (old IRC just * let it through as if the prefix just wasn't there...) --msa */ if (from == NULL) { ++ServerStats.is_unpf; parse_remove_unknown(client_p, sender, pbuffer); return; } if (from->from != client_p) { ++ServerStats.is_wrdi; sendto_realops_flags(UMODE_DEBUG, L_ADMIN, SEND_NOTICE, "Fake direction: dropped message from %s[%s] via %s", from->name, from->from->name, client_get_name(client_p, SHOW_IP)); sendto_realops_flags(UMODE_DEBUG, L_OPER, SEND_NOTICE, "Fake direction: dropped message from %s[%s] via %s", from->name, from->from->name, client_get_name(client_p, MASK_IP)); return; } } while (*ch == ' ') ++ch; } if (*ch == '\0') { ++ServerStats.is_empt; return; } /* * Extract the command code from the packet. Point s to the end * of the command code and calculate the length using pointer * arithmetic. Note: only need length for numerics and *all* * numerics must have parameters and thus a space after the command * code. -avalon */ /* EOB is 3 characters long but is not a numeric */ if (*(ch + 3) == ' ' && /* Ok, let's see if it's a possible numeric */ IsDigit(*ch) && IsDigit(*(ch + 1)) && IsDigit(*(ch + 2))) { numeric = (*ch - '0') * 100 + (*(ch + 1) - '0') * 10 + (*(ch + 2) - '0'); paramcount = 2; /* Destination, and the rest of it */ ++ServerStats.is_num; s = ch + 3; /* I know this is ' ' from above if */ *s++ = '\0'; /* Blow away the ' ', and point s to next part */ } else { if ((s = strchr(ch, ' '))) *s++ = '\0'; if ((message = find_command(ch)) == NULL) { /* * Note: Give error message *only* to recognized * persons. It's a nightmare situation to have * two programs sending "Unknown command"'s or * equivalent to each other at full blast.... * If it has got to person state, it at least * seems to be well behaving. Perhaps this message * should never be generated, though... --msa * Hm, when is the buffer empty -- if a command * code has been found ?? -Armin */ if (*pbuffer) if (IsClient(from)) sendto_one_numeric(from, &me, ERR_UNKNOWNCOMMAND, ch); ++ServerStats.is_unco; return; } assert(message->cmd); paramcount = message->args_max; size_t length = bufend - ((s) ? s : ch); message->bytes += length; } /* * Must the following loop really be so devious? On surface it * splits the message to parameters from blank spaces. But, if * paramcount has been reached, the rest of the message goes into * this last parameter (about same effect as ":" has...) --msa */ /* Note initially true: s == NULL || *(s - 1) == '\0' !! */ para[parc] = ch; if (message && (message->flags & MFLG_EXTRA)) { /* * XXX: This will have to go away after the command handler rewrite */ para[++parc] = message->extra; } if (s) { if (paramcount > MAXPARA) paramcount = MAXPARA; while (true) { while (*s == ' ') *s++ = '\0'; if (*s == '\0') break; if (*s == ':') { /* The rest is single parameter--can include blanks also. */ para[++parc] = s + (numeric == 0); /* Keep the colon if it's a numeric */ break; } para[++parc] = s; if (parc >= paramcount) break; while (*s && *s != ' ') ++s; } } para[++parc] = NULL; if (message) parse_handle_command(message, from, parc, para); else parse_handle_numeric(numeric, from, parc, para); }
static void mo_chgident(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct Client *target_p = NULL; if (MyClient(source_p) && !HasUMode(source_p, UMODE_ADMIN)) { sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "CHGIDENT"); return; } if (EmptyString(parv[2])) { parv[2] = parv[1]; target_p = source_p; if (!IsClient(target_p)) return; } else { target_p = hash_find_client(parv[1]); if (target_p == NULL || !IsClient(target_p)) { sendto_one(source_p, form_str(ERR_NOSUCHNICK), me.name, source_p->name, parv[1]); return; } } if (strlen(parv[2]) > USERLEN || !*parv[2] || !valid_username(parv[2])) { sendto_one(source_p, ":%s NOTICE %s :Invalid username", me.name, source_p->name); return; } if (IsUserHostIp(target_p)) delete_user_host(target_p->username, target_p->host, !MyConnect(target_p)); strlcpy(target_p->username, parv[2], sizeof(target_p->username)); add_user_host(target_p->username, target_p->host, !MyConnect(target_p)); SetUserHost(target_p); if (MyClient(source_p)) { sendto_server(client_p, NOCAPS, NOCAPS, ":%s ENCAP * CHGIDENT %s %s", source_p->name, target_p->name, parv[2]); sendto_one(source_p, ":%s NOTICE %s :%s changed to %s@%s", me.name, source_p->name, target_p->name, target_p->username, target_p->host); } if (MyClient(target_p)) { if (IsClient(source_p)) sendto_one(target_p, ":%s NOTICE %s :You are now %s@%s", me.name, target_p->name, target_p->username, target_p->host); clear_ban_cache_client(target_p); } }
/*! \brief NICK command handler * * \param source_p Pointer to allocated Client struct from which the message * originally comes from. This can be a local or remote client. * \param parc Integer holding the number of supplied arguments. * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL * pointers. * \note Valid arguments for this command are: * - parv[0] = command * - parv[1] = nickname */ static int m_nick(struct Client *source_p, int parc, char *parv[]) { char nick[NICKLEN + 1] = ""; struct Client *target_p = NULL; struct MaskItem *conf = NULL; assert(MyClient(source_p)); if (parc < 2 || EmptyString(parv[1])) { sendto_one_numeric(source_p, &me, ERR_NONICKNAMEGIVEN); return 0; } /* Mark end of grace period, to prevent nickflooding */ if (!IsFloodDone(source_p)) flood_endgrace(source_p); /* Terminate nick to NICKLEN */ strlcpy(nick, parv[1], IRCD_MIN(sizeof(nick), ConfigServerInfo.max_nick_length + 1)); /* Check the nickname is ok */ if (!valid_nickname(nick, 1)) { sendto_one_numeric(source_p, &me, ERR_ERRONEUSNICKNAME, nick, "Erroneous Nickname"); return 0; } if (!HasFlag(source_p, FLAGS_EXEMPTRESV) && !(HasUMode(source_p, UMODE_OPER) && HasOFlag(source_p, OPER_FLAG_NICK_RESV)) && (conf = find_matching_name_conf(CONF_NRESV, nick, NULL, NULL, 0))) { ++conf->count; sendto_one_numeric(source_p, &me, ERR_ERRONEUSNICKNAME, nick, conf->reason); sendto_realops_flags(UMODE_REJ, L_ALL, SEND_NOTICE, "Forbidding reserved nick %s from user %s", nick, get_client_name(source_p, HIDE_IP)); return 0; } if ((target_p = hash_find_client(nick)) == NULL) change_local_nick(source_p, nick); else if (target_p == source_p) { /* * If (target_p == source_p) the client is changing nicks between * equivalent nicknames ie: [nick] -> {nick} */ /* Check the nick isn't exactly the same */ if (strcmp(target_p->name, nick)) change_local_nick(source_p, nick); } else if (IsUnknown(target_p)) { /* * If the client that has the nick isn't registered yet (nick but no * user) then drop the unregged client */ exit_client(target_p, "Overridden by other sign on"); change_local_nick(source_p, nick); } else sendto_one_numeric(source_p, &me, ERR_NICKNAMEINUSE, target_p->name); return 0; }
/* ** m_whois ** parv[0] = sender prefix ** parv[1] = nickname masklist */ int m_whois(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { static anUser UnknownUser = { NULL, /* next */ NULL, /* channel */ NULL, /* invited */ NULL, /* silence */ NULL, /* away */ 0, /* last */ 1, /* refcount */ 0, /* joined */ "<Unknown>" /* server */ }; static char rpl_oper[] = "an IRC Operator"; static char rpl_locop[] = "an IRC Operator - Local IRC Operator"; static char rpl_sadmin[] = "an IRC Operator - Services Administrator"; static char rpl_admin[] = "an IRC Operator - Server Administrator"; static char rpl_tadmin[] = "an IRC Operator - Technical Administrator"; static char rpl_nadmin[] = "an IRC Operator - Network Administrator"; Link *lp; anUser *user; struct Client *acptr, *a2cptr; aChannel *chptr; char *nick, *name; /* char *tmp; */ char *p = NULL; int found, len, mlen; static time_t last_used=0L; char *nick_match=NULL, *user_match=NULL, *host_match=NULL, *server_match=NULL; char *name_match=NULL; int found_mode; int hits = 0; char *mename = me.name; if(sptr->user && sptr->user->vlink) mename = sptr->user->vlink->name; if (parc < 2) { sendto_one(sptr, form_str(ERR_NONICKNAMEGIVEN), mename, parv[0]); return 0; } if(parc > 2) { if (hunt_server(cptr,sptr,":%s WHOIS %s :%s", 1,parc,parv) != HUNTED_ISME) return 0; parv[1] = parv[2]; } if(!IsAnOper(sptr) && !MyConnect(sptr)) /* pace non local requests */ { if((last_used + WHOIS_WAIT) > CurrentTime) { /* Unfortunately, returning anything to a non local * request =might= increase sendq to be usable in a split hack * Sorry gang ;-( - Dianora */ return 0; } else { last_used = CurrentTime; } } /* Multiple whois from remote hosts, can be used * to flood a server off. One could argue that multiple whois on * local server could remain. Lets think about that, for now * removing it totally. * -Dianora */ /* for (tmp = parv[1]; (nick = strtoken(&p, tmp, ",")); tmp = NULL) */ nick = parv[1]; p = strchr(parv[1],','); if(p) *p = '\0'; { int invis, member, wilds; found = 0; (void)collapse(nick); wilds = (nick[0]=='$' || strchr(nick, '?') || strchr(nick, '*')); /* ** We're no longer allowing remote users to generate ** requests with wildcards. */ if (wilds && !IsAnOper(sptr)) { sendto_one(sptr, form_str(ERR_NOSUCHNICK), mename, parv[0], nick); return 0; } /* continue; */ /* If the nick doesn't have any wild cards in it, * then just pick it up from the hash table * - Dianora */ if(!wilds) { acptr = hash_find_client(nick,(struct Client *)NULL); if(!acptr) { sendto_one(sptr, form_str(ERR_NOSUCHNICK), mename, parv[0], nick); sendto_one(sptr, form_str(RPL_ENDOFWHOIS), mename, parv[0], parv[1]); return 0; /* continue; */ } if(IsStealth(acptr)) { sendto_one(sptr, form_str(ERR_NOSUCHNICK), mename, parv[0], nick); return 0; // Add by ^Stinger^ after the idea of Soldier (: } if(!IsPerson(acptr)) { sendto_one(sptr, form_str(RPL_ENDOFWHOIS), mename, parv[0], parv[1]); return 0; } /* continue; */ user = acptr->user ? acptr->user : &UnknownUser; name = (!*acptr->name) ? "?" : acptr->name; invis = IsInvisible(acptr); member = (user->channel) ? 1 : 0; a2cptr = find_server(user->server); sendto_one(sptr, form_str(RPL_WHOISUSER), mename, parv[0], name, acptr->username, acptr->host, acptr->info); if((IsOper(sptr) || (acptr == sptr)) && WhoisExtension) { sendto_one(sptr, form_str(RPL_WHOISREALHOST), mename, parv[0], name, acptr->realhost); } mlen = strlen(mename) + strlen(parv[0]) + 6 + strlen(name); *buf = '\0'; if (IsSsl(acptr)) { sendto_one(sptr, form_str(RPL_WHOISSECURE), mename, parv[0], parv[1]); } if(((!IsPrivate(acptr) || IsOper(sptr)) || (acptr==sptr)) && !IsStealth(acptr)) for (len = 0, *buf = '\0', lp = user->channel; lp; lp = lp->next) { chptr = lp->value.chptr; if (ShowChannel(sptr, chptr)) { if (len + strlen(chptr->chname) > (size_t) BUFSIZE - 4 - mlen) { sendto_one(sptr, ":%s %d %s %s :%s", mename, RPL_WHOISCHANNELS, parv[0], name, buf); *buf = '\0'; len = 0; } found_mode = user_channel_mode(acptr, chptr); #ifdef HIDE_OPS if(is_chan_op(sptr,chptr)) #endif { if(found_mode & CHFL_CHANOP) *(buf + len++) = '@'; #ifdef HALFOPS else if (found_mode & CHFL_HALFOP) *(buf + len++) = '%'; #endif else if (found_mode & CHFL_VOICE) *(buf + len++) = '+'; } if (len) *(buf + len) = '\0'; (void)strcpy(buf + len, chptr->chname); len += strlen(chptr->chname); (void)strcat(buf + len, " "); len++; } } if (buf[0] != '\0') sendto_one(sptr, form_str(RPL_WHOISCHANNELS), mename, parv[0], name, buf); if(IsAnOper(sptr) || !HideServerOnWhois) { #ifdef SERVERHIDE if (!(IsAnOper(sptr) || acptr == sptr)) sendto_one(sptr, form_str(RPL_WHOISSERVER), mename, parv[0], name, NetworkName, NetworkDesc); else #endif if(acptr->user && acptr->user->vlink) sendto_one(sptr, form_str(RPL_WHOISSERVER), mename, parv[0], name, user->vlink->name, user->vlink->passwd); else { if(!IsService(acptr) || IsAnOper(sptr) || !HideServicesServer) sendto_one(sptr, form_str(RPL_WHOISSERVER), mename, parv[0], name, user->server, a2cptr?a2cptr->info:"*Not On This Net*"); } } /* if(IsAnOper(sptr) || HideServerOnWhois) */ if (IsIdentified(acptr)) sendto_one(sptr, form_str(RPL_WHOISIDENTIFIED), mename, parv[0], name); if (IsHelper(acptr)) sendto_one(sptr, form_str(RPL_WHOISHELPOP), mename, parv[0], name); if(IsOper(sptr) && WhoisExtension) { sendto_one(sptr, form_str(RPL_WHOISMODE), mename, parv[0], name, get_mode_string(acptr)); } if (user->away) sendto_one(sptr, form_str(RPL_AWAY), mename, parv[0], name, user->away); if(!IsHideOper(acptr) || IsOper(sptr)) { if (IsNetAdmin(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_nadmin); else if (IsTechAdmin(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_tadmin); else if (IsSAdmin(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_sadmin); else if (IsAdmin(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_admin); else if (IsOper(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_oper); else if (IsLocOp(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_locop); } #ifdef WHOIS_NOTICE if ((IsOper(acptr)) && ((acptr)->umodes & UMODE_SPY) && (MyConnect(sptr)) && (IsPerson(sptr)) && (acptr != sptr) && !is_silenced(sptr, acptr)) sendto_one(acptr, ":%s NOTICE %s :*** Notice -- %s (%s@%s) is doing a /whois on you.", me.name, acptr->name, parv[0], sptr->username, sptr->realhost); #endif /* #ifdef WHOIS_NOTICE */ if ((acptr->user #ifdef SERVERHIDE && IsAnOper(sptr) #endif && MyConnect(acptr))) sendto_one(sptr, form_str(RPL_WHOISIDLE), mename, parv[0], name, CurrentTime - user->last, acptr->firsttime); sendto_one(sptr, form_str(RPL_ENDOFWHOIS), mename, parv[0], parv[1]); return 0; /* continue; */ } /* wild is true so here we go */ if(nick[0]==':') /* real name match */ { name_match = &nick[1]; nick_match = NULL; } else if(nick[0]=='$') /* server name match */ { server_match = &nick[1]; nick_match = NULL; } else { host_match = strchr(nick,'@'); if(host_match) { if(*host_match) *(host_match++) = '\0'; user_match=nick; if(host_match=='\0') host_match="*"; if(user_match=='\0') user_match="*"; } else nick_match = nick; } for (acptr = GlobalClientList; acptr; acptr = acptr->next) { if (IsServer(acptr)) continue; /* * I'm always last :-) and acptr->next == NULL!! */ if (IsMe(acptr)) break; /* * 'Rules' established for sending a WHOIS reply: * * * - if wildcards are being used dont send a reply if * the querier isnt any common channels and the * client in question is invisible and wildcards are * in use (allow exact matches only); * * - only send replies about common or public channels * the target user(s) are on; */ /* If its an unregistered client, ignore it, it can be "seen" on a /trace anyway -Dianora */ if(!IsRegistered(acptr)) continue; user = acptr->user ? acptr->user : &UnknownUser; name = (!*acptr->name) ? "?" : acptr->name; if( (server_match && !match(server_match, user->server)) || (nick_match && !match(nick, name)) || (host_match && !match(host_match, acptr->realhost) && !match(host_match, acptr->host)) || (user_match && !match(user_match, acptr->username)) || (name_match && !match(name_match, acptr->info)) ) continue; ++hits; a2cptr = find_server(user->server); sendto_one(sptr, form_str(RPL_WHOISUSER), mename, parv[0], name, acptr->username, IsOper(sptr) ? acptr->realhost : acptr->host, acptr->info); found = 1; mlen = strlen(mename) + strlen(parv[0]) + 6 + strlen(name); for (len = 0, *buf = '\0', lp = user->channel; lp; lp = lp->next) { chptr = lp->value.chptr; if (ShowChannel(sptr, chptr)) { if (len + strlen(chptr->chname) > (size_t) BUFSIZE - 4 - mlen) { sendto_one(sptr, ":%s %d %s %s :%s", mename, RPL_WHOISCHANNELS, parv[0], name, buf); *buf = '\0'; len = 0; } found_mode = user_channel_mode(acptr, chptr); #ifdef HIDE_OPS if(is_chan_op(sptr,chptr)) #endif { if (found_mode & CHFL_CHANOP) *(buf + len++) = '@'; #ifdef HALFOPS else if (found_mode & CHFL_HALFOP) *(buf + len++) = '%'; #endif else if (found_mode & CHFL_VOICE) *(buf + len++) = '+'; } if (len) *(buf + len) = '\0'; (void)strcpy(buf + len, chptr->chname); len += strlen(chptr->chname); (void)strcat(buf + len, " "); len++; } } if (buf[0] != '\0') sendto_one(sptr, form_str(RPL_WHOISCHANNELS), mename, parv[0], name, buf); #ifdef SERVERHIDE if (!(IsAnOper(sptr) || acptr == sptr)) sendto_one(sptr, form_str(RPL_WHOISSERVER), mename, parv[0], name, NetworkName, NetworkDesc); else #endif sendto_one(sptr, form_str(RPL_WHOISSERVER), mename, parv[0], name, user->server, a2cptr?a2cptr->info:"*Not On This Net*"); if (user->away) sendto_one(sptr, form_str(RPL_AWAY), mename, parv[0], name, user->away); if (IsNetAdmin(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_nadmin); else if (IsTechAdmin(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_tadmin); else if (IsSAdmin(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_sadmin); else if (IsAdmin(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_admin); else if (IsAnOper(acptr)) sendto_one(sptr, form_str(RPL_WHOISOPERATOR), mename, parv[0], name, rpl_oper); #ifdef WHOIS_NOTICE if ((MyOper(acptr)) && ((acptr)->umodes & UMODE_SPY) && (MyConnect(sptr)) && (IsPerson(sptr)) && (acptr != sptr)) sendto_one(acptr, ":%s NOTICE %s :*** Notice -- %s (%s@%s) is doing a /whois on you.", mename, acptr->name, parv[0], sptr->username, sptr->realhost); #endif /* #ifdef WHOIS_NOTICE */ if ((acptr->user #ifdef SERVERHIDE && IsAnOper(sptr) #endif && MyConnect(acptr))) sendto_one(sptr, form_str(RPL_WHOISIDLE), mename, parv[0], name, CurrentTime - user->last, acptr->firsttime); if(hits>50) { sendto_one(sptr,":%s NOTICE %s :Aborting /whois output as flood prevention", mename, sptr->name); break; } } if (!found) sendto_one(sptr, form_str(ERR_NOSUCHNICK), mename, parv[0], nick); else sendto_one(sptr,":%s NOTICE %s :This /whois matched \2%i\2 user(s)", mename, sptr->name,hits); /* if (p) p[-1] = ','; */ } sendto_one(sptr, form_str(RPL_ENDOFWHOIS), mename, parv[0], parv[1]); return 0; }
/* ** m_ltrace - LimitedTRACE... like m_trace() but doesn't return TRACEUSER, TRACEUNKNOWN, or TRACECLASS ** parv[0] = sender prefix ** parv[1] = servername */ int m_ltrace(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { int i; struct Client *acptr = NULL; char *tname; int doall, link_s[MAXCONNECTIONS], link_u[MAXCONNECTIONS]; int cnt = 0, wilds, dow; static time_t now; if (check_registered(sptr)) return 0; #ifdef SERVERHIDE if (!IsAnOper(sptr)) return 0; #endif if (parc > 2) if (hunt_server(cptr, sptr, ":%s LTRACE %s :%s", 2, parc, parv)) return 0; if (parc > 1) tname = parv[1]; else tname = me.name; switch (hunt_server(cptr, sptr, ":%s LTRACE :%s", 1, parc, parv)) { case HUNTED_PASS: /* note: gets here only if parv[1] exists */ { struct Client *ac2ptr; ac2ptr = next_client(GlobalClientList, tname); if (ac2ptr) sendto_one(sptr, form_str(RPL_TRACELINK), me.name, parv[0], ircd_version, debugmode, tname, ac2ptr->from->name); else sendto_one(sptr, form_str(RPL_TRACELINK), me.name, parv[0], ircd_version, debugmode, tname, "ac2ptr_is_NULL!!"); return 0; } case HUNTED_ISME: break; default: return 0; } if(MyClient(sptr)) sendto_realops_flags(FLAGS_SPY, "ltrace requested by %s (%s@%s) [%s]", sptr->name, sptr->username, sptr->host, sptr->user->server); doall = (parv[1] && (parc > 1)) ? match(tname, me.name): TRUE; wilds = !parv[1] || strchr(tname, '*') || strchr(tname, '?'); dow = wilds || doall; if(!IsAnOper(sptr) || !dow) /* non-oper traces must be full nicks */ /* lets also do this for opers tracing nicks */ { const char* name; const char* ip; int c_class; acptr = hash_find_client(tname,(struct Client *)NULL); if(!acptr || !IsPerson(acptr)) { /* this should only be reached if the matching target is this server */ sendto_one(sptr, form_str(RPL_ENDOFTRACE),me.name, parv[0], tname); return 0; } name = get_client_name(acptr, FALSE); ip = inetntoa((char*) &acptr->ip); c_class = get_client_class(acptr); if (IsAnOper(acptr)) { sendto_one(sptr, form_str(RPL_TRACEOPERATOR), me.name, parv[0], c_class, name, IsAnOper(sptr)?ip:(IsIPHidden(acptr)?"255.255.255.255":ip), now - acptr->lasttime, (acptr->user)?(now - acptr->user->last):0); } sendto_one(sptr, form_str(RPL_ENDOFTRACE),me.name, parv[0], tname); return 0; } for (i = 0; i < MAXCONNECTIONS; i++) link_s[i] = 0, link_u[i] = 0; if (dow && LIFESUX && !IsOper(sptr)) { sendto_one(sptr,form_str(RPL_LOAD2HI),me.name,parv[0]); return 0; } /* * Count up all the servers and clients in a downlink. */ if (doall) { for (acptr = GlobalClientList; acptr; acptr = acptr->next) { if (IsServer(acptr)) ++link_s[acptr->from->fd]; } } /* report all direct connections */ now = time(NULL); for (i = 0; i <= highest_fd; i++) { const char* name; const char* ip; int c_class; if (!(acptr = local[i])) /* Local Connection? */ continue; if (IsInvisible(acptr) && dow && !(MyConnect(sptr) && IsAnOper(sptr)) && !IsAnOper(acptr) && (acptr != sptr)) continue; if (!doall && wilds && !match(tname, acptr->name)) continue; if (!dow && irccmp(tname, acptr->name)) continue; name = get_client_name(acptr, FALSE); ip = inetntoa((const char*) &acptr->ip); c_class = get_client_class(acptr); switch(acptr->status) { case STAT_HANDSHAKE: #ifdef HIDE_SERVERS_IPS name=get_client_name(acptr, MASK_IP); #endif sendto_one(sptr, form_str(RPL_TRACEHANDSHAKE), me.name, parv[0], c_class, name); cnt++; break; case STAT_CONNECTING: #ifdef HIDE_SERVERS_IPS name=get_client_name(acptr, MASK_IP); #endif sendto_one(sptr, form_str(RPL_TRACECONNECTING), me.name, parv[0], c_class, name); cnt++; break; case STAT_ME: break; case STAT_CLIENT: /* Well, most servers don't have a LOT of OPERs... let's show them too */ if ((IsAnOper(sptr) && (MyClient(sptr) || !(dow && IsInvisible(acptr)))) || !dow || IsAnOper(acptr)) { if (IsAnOper(acptr)) sendto_one(sptr, form_str(RPL_TRACEOPERATOR), me.name, parv[0], c_class, name, IsAnOper(sptr)?ip:(IsIPHidden(acptr)?"255.255.255.255":ip), now - acptr->lasttime, (acptr->user)?(now - acptr->user->last):0); cnt++; } break; case STAT_SERVER: #if 0 if (acptr->serv->user) sendto_one(sptr, form_str(RPL_TRACESERVER), me.name, parv[0], c_class, link_s[i], link_u[i], name, acptr->serv->by, acptr->serv->user->username, acptr->serv->user->host, now - acptr->lasttime); else #endif #ifdef HIDE_SERVERS_IPS name=get_client_name(acptr, MASK_IP); #endif sendto_one(sptr, form_str(RPL_TRACESERVER), me.name, parv[0], c_class, link_s[i], link_u[i], name, *(acptr->serv->by) ? acptr->serv->by : "*", "*", me.name, now - acptr->lasttime); cnt++; break; default: /* ...we actually shouldn't come here... --msa */ sendto_one(sptr, form_str(RPL_TRACENEWTYPE), me.name, parv[0], name); cnt++; break; } } /* * Add these lines to summarize the above which can get rather long * and messy when done remotely - Avalon */ if (!IsAnOper(sptr) || !cnt) { if (cnt) return 0; /* let the user have some idea that its at the end of the * trace */ sendto_one(sptr, form_str(RPL_TRACESERVER), me.name, parv[0], 0, link_s[me.fd], link_u[me.fd], me.name, "*", "*", me.name); sendto_one(sptr, form_str(RPL_ENDOFTRACE),me.name, parv[0],tname); return 0; } sendto_one(sptr, form_str(RPL_ENDOFTRACE),me.name, parv[0],tname); return 0; }
/*! \brief SVSNICK command handler * * \param source_p Pointer to allocated Client struct from which the message * originally comes from. This can be a local or remote client. * \param parc Integer holding the number of supplied arguments. * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL * pointers. * \note Valid arguments for this command are: * - parv[0] = command * - parv[1] = old nickname * - parv[2] = new nickname * - parv[3] = timestamp */ static int ms_svsnick(struct Client *source_p, int parc, char *parv[]) { struct Client *target_p = NULL, *exists_p = NULL; if (!HasFlag(source_p, FLAGS_SERVICE) || !valid_nickname(parv[2], 1)) return 0; if ((target_p = find_person(source_p, parv[1])) == NULL) return 0; if (!MyConnect(target_p)) { if (target_p->from == source_p->from) { sendto_realops_flags(UMODE_DEBUG, L_ALL, SEND_NOTICE, "Received wrong-direction SVSNICK " "for %s (behind %s) from %s", target_p->name, source_p->from->name, get_client_name(source_p, HIDE_IP)); return 0; } sendto_one(target_p, ":%s SVSNICK %s %s %s", source_p->id, target_p->id, parv[2], parv[3]); return 0; } if ((exists_p = hash_find_client(parv[2]))) { if (target_p == exists_p) { if (!strcmp(target_p->name, parv[2])) return 0; } else if (IsUnknown(exists_p)) exit_client(exists_p, "SVSNICK Override"); else { exit_client(target_p, "SVSNICK Collide"); return 0; } } target_p->tsinfo = strtoimax(parv[3], NULL, 10); clear_ban_cache_client(target_p); watch_check_hash(target_p, RPL_LOGOFF); if (HasUMode(target_p, UMODE_REGISTERED)) { const unsigned int oldmodes = target_p->umodes; char modebuf[IRCD_BUFSIZE] = ""; DelUMode(target_p, UMODE_REGISTERED); send_umode(target_p, target_p, oldmodes, modebuf); } sendto_common_channels_local(target_p, 1, 0, 0, ":%s!%s@%s NICK :%s", target_p->name, target_p->username, target_p->host, parv[2]); whowas_add_history(target_p, 1); sendto_server(NULL, 0, 0, ":%s NICK %s :%ju", target_p->id, parv[2], target_p->tsinfo); hash_del_client(target_p); strlcpy(target_p->name, parv[2], sizeof(target_p->name)); hash_add_client(target_p); watch_check_hash(target_p, RPL_LOGON); fd_note(&target_p->connection->fd, "Nick: %s", target_p->name); return 0; }