/* * mo_rehash - oper message handler * * parv[1] = 'm' flushes the MOTD cache and returns * parv[1] = 'l' reopens the log files and returns * parv[1] = 'q' to not rehash the resolver (optional) * parv[1] = 's' to reload SSL certificates * parv[1] = 'a' to restart the IAuth program */ int mo_rehash(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { int flag = 0; if (!HasPriv(sptr, PRIV_REHASH) || ((parc == 3) && !HasPriv(sptr, PRIV_REMOTEREHASH))) return send_reply(sptr, ERR_NOPRIVILEGES); if ((parc == 3) && (hunt_server_cmd(sptr, CMD_REHASH, cptr, 1, "%s %C", 2, parc, parv) != HUNTED_ISME)) return 0; if (parc == 2) { /* special processing */ if (parv[1][1] == '\0') { /* one character server name */ if (*parv[1] == 'm') { send_reply(sptr, SND_EXPLICIT | RPL_REHASHING, ":Flushing MOTD cache"); motd_recache(); /* flush MOTD cache */ return 0; } else if (*parv[1] == 'l') { send_reply(sptr, SND_EXPLICIT | RPL_REHASHING, ":Reopening log files"); log_reopen(); /* reopen log files */ return 0; } else if (*parv[1] == 'a') { send_reply(sptr, SND_EXPLICIT | RPL_REHASHING, ":Restarting IAuth"); auth_restart(); /* Restart IAuth program */ return 0; #ifdef USE_SSL } else if (*parv[1] == 's') { send_reply(sptr, SND_EXPLICIT | RPL_REHASHING, ":Reloading SSL certificates"); ssl_reinit(); return 0; #endif } else if (*parv[1] == 'q') flag = 2; } /* * Maybe the user wants to rehash another server with no parameters. * NOTE: Here we assume that there are no servers named * 'm', 'l', 's', or 'q'. */ else if (HasPriv(sptr, PRIV_REMOTEREHASH)) { if (hunt_server_cmd(sptr, CMD_REHASH, cptr, 1, "%C", 1, parc, parv) != HUNTED_ISME) return 0; } else return send_reply(sptr, ERR_NOPRIVILEGES); } send_reply(sptr, RPL_REHASHING, configfile); sendto_opmask_butone(0, SNO_OLDSNO, "%C is rehashing Server config file", sptr); log_write(LS_SYSTEM, L_INFO, 0, "REHASH From %#C", sptr); return rehash(cptr, flag); }
int ms_rehash(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { int flag = 0; if ((parc > 2) && (hunt_server_cmd(sptr, CMD_REHASH, cptr, 1, "%s %C", 2, parc, parv) != HUNTED_ISME)) return 0; /* OK, the message has been forwarded, but before we can act... */ if (!feature_bool(FEAT_NETWORK_REHASH)) return 0; if (parc > 1) { /* special processing */ if (parv[1][1] == '\0') { /* one character server name */ if (*parv[1] == 'm') { send_reply(sptr, SND_EXPLICIT | RPL_REHASHING, ":Flushing MOTD cache"); motd_recache(); /* flush MOTD cache */ return 0; } else if (*parv[1] == 'l') { send_reply(sptr, SND_EXPLICIT | RPL_REHASHING, ":Reopening log files"); log_reopen(); /* reopen log files */ return 0; } else if (*parv[1] == 'a') { send_reply(sptr, SND_EXPLICIT | RPL_REHASHING, ":Restarting IAuth"); auth_restart(); /* Restart IAuth program */ return 0; #ifdef USE_SSL } else if (*parv[1] == 's') { send_reply(sptr, SND_EXPLICIT | RPL_REHASHING, ":Reloading SSL certificates"); ssl_reinit(); return 0; #endif } else if (*parv[1] == 'q') flag = 2; } /* * Maybe the user wants to rehash another server with no parameters. * NOTE: Here we assume that there are no servers named * 'm', 'l', 's', or 'q'. */ else if ((parc == 2) && (hunt_server_cmd(sptr, CMD_REHASH, cptr, 1, "%C", 1, parc, parv) != HUNTED_ISME)) return 0; } send_reply(sptr, RPL_REHASHING, configfile); sendto_opmask_butone(0, SNO_OLDSNO, "%C [%s] is remotely rehashing Server config file", sptr, cli_name(cli_user(sptr)->server)); log_write(LS_SYSTEM, L_INFO, 0, "Remote REHASH From %#C [%s]", sptr, cli_name(cli_user(sptr)->server)); return rehash(cptr, flag); }
/** Handle a RESTART message from a server connection. * * \a parv has the following elements: * \li \a parv[1] is the target server, or "*" for all. * \li \a parv[2] is either "cancel" or a time interval in seconds * \li \a parv[\a parc - 1] is the reason * * All fields must be present. Additionally, the time interval should * not be 0 for messages sent to "*", as that may not function * reliably due to buffering in the server. * * See @ref m_functions for discussion of the arguments. * @param[in] cptr Client that sent us the message. * @param[in] sptr Original source of message. * @param[in] parc Number of arguments. * @param[in] parv Argument vector. */ int ms_restart(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { const char *target, *when, *reason; if (parc < 4) return need_more_params(sptr, "RESTART"); target = parv[1]; when = parv[2]; reason = parv[parc - 1]; /* is it a message we should pay attention to? */ if (target[0] != '*' || target[1] != '\0') { if (hunt_server_cmd(sptr, CMD_RESTART, cptr, 0, "%C %s :%s", 1, parc, parv) != HUNTED_ISME) return 0; } else /* must forward the message */ sendcmdto_serv(sptr, CMD_RESTART, cptr, "* %s :%s", when, reason); /* OK, the message has been forwarded, but before we can act... */ if (!feature_bool(FEAT_NETWORK_RESTART)) return 0; /* is it a cancellation? */ if (!ircd_strcmp(when, "cancel")) exit_cancel(sptr); /* cancel a pending exit */ else /* schedule an exit */ exit_schedule(1, atoi(when), sptr, reason); return 0; }
/* * mo_info - oper message handler * * parv[0] = sender prefix * parv[1] = servername */ int mo_info(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { const char **text = infotext; if (hunt_server_cmd(sptr, CMD_INFO, cptr, 1, ":%C", 1, parc, parv) == HUNTED_ISME) { while (text[212]) { if (!IsOper(sptr)) send_reply(sptr, RPL_INFO, *text); text++; } if (IsOper(sptr) && (NULL != parv[1])) { while (*text) send_reply(sptr, RPL_INFO, *text++); send_reply(sptr, RPL_INFO, ""); } send_reply(sptr, SND_EXPLICIT | RPL_INFO, ":Birth Date: %s, compile # %s", creation, generation); send_reply(sptr, SND_EXPLICIT | RPL_INFO, ":On-line since %s", myctime(cli_firsttime(&me))); send_reply(sptr, RPL_ENDOFINFO); } return 0; }
/* * mo_version - oper message handler * * parv[0] = sender prefix * parv[1] = servername */ int mo_version(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Client *acptr; if (MyConnect(sptr) && parc > 1) { if (!(acptr = find_match_server(parv[1]))) { send_reply(sptr, ERR_NOSUCHSERVER, parv[1]); return 0; } parv[1] = cli_name(acptr); } if (hunt_server_cmd(sptr, CMD_VERSION, cptr, feature_int(FEAT_HIS_REMOTE), ":%C", 1, parc, parv) == HUNTED_ISME) { send_reply(sptr, RPL_VERSION, version, debugmode, cli_name(&me), debug_serveropts()); send_supported(sptr); } return 0; }
/* * ms_links - server message handler * * parv[0] = sender prefix * parv[1] = servername mask * * or * * parv[0] = sender prefix * parv[1] = server to query * parv[2] = servername mask */ int ms_links(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { char *mask; struct Client *acptr; if (parc > 2) { if (hunt_server_cmd(sptr, CMD_LINKS, cptr, 1, "%C :%s", 1, parc, parv) != HUNTED_ISME) return 0; mask = parv[2]; } else mask = parc < 2 ? 0 : parv[1]; for (acptr = GlobalClientList, collapse(mask); acptr; acptr = cli_next(acptr)) { if (!IsServer(acptr) && !IsMe(acptr)) continue; if (!BadPtr(mask) && match(mask, cli_name(acptr))) continue; send_reply(sptr, RPL_LINKS, cli_name(acptr), cli_name(cli_serv(acptr)->up), cli_hopcount(acptr), cli_serv(acptr)->prot, ((cli_info(acptr))[0] ? cli_info(acptr) : "(Unknown Location)")); } send_reply(sptr, RPL_ENDOFLINKS, BadPtr(mask) ? "*" : mask); return 0; }
/* * ms_motd - server message handler * * parv[0] - sender prefix * parv[1] - servername * * modified 30 mar 1995 by flux ([email protected]) * T line patch - display motd based on hostmask * modified again 7 sep 97 by Ghostwolf with code and ideas * stolen from comstud & Xorath. All motd files are read into * memory in read_motd() in s_conf.c * * Now using the motd_* family of functions defined in motd.c */ int ms_motd(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { if (hunt_server_cmd(sptr, CMD_MOTD, cptr, 0, "%C", 1, parc, parv) != HUNTED_ISME) return 0; return motd_send(sptr); }
/* * ms_rules - server message handler * * parv[0] - sender prefix * parv[1] - servername */ int ms_rules(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { if (hunt_server_cmd(sptr, CMD_RULES, cptr, 0, "%C", 1, parc, parv) != HUNTED_ISME) return 0; return motd_send_type(sptr, MOTD_RULES); }
/* * m_motd - generic message handler * * parv[0] - sender prefix * parv[1] - servername * * modified 30 mar 1995 by flux ([email protected]) * T line patch - display motd based on hostmask * modified again 7 sep 97 by Ghostwolf with code and ideas * stolen from comstud & Xorath. All motd files are read into * memory in read_motd() in s_conf.c * * Now using the motd_* family of functions defined in motd.c */ int m_motd(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { if (hunt_server_cmd(sptr, CMD_MOTD, cptr, feature_int(FEAT_HIS_REMOTE), "%C", 1, parc, parv) != HUNTED_ISME) return 0; return motd_send(sptr); }
/* * ms_whois - server message handler * * parv[0] = sender prefix * parv[1] = nickname masklist * * or * * parv[1] = target server, or a nickname representing a server to target. * parv[2] = nickname masklist */ int ms_whois(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { char* nick; char* tmp; char* p = 0; int found = 0; int total = 0; if (parc < 2) { send_reply(sptr, ERR_NONICKNAMEGIVEN); return 0; } if (parc > 2) { if (hunt_server_cmd(sptr, CMD_WHOIS, cptr, 0, "%C :%s", 1, parc, parv) != HUNTED_ISME) return 0; parv[1] = parv[2]; } total = 0; for (tmp = parv[1]; (nick = ircd_strtok(&p, tmp, ",")); tmp = 0) { struct Client *acptr = 0; found = 0; collapse(nick); acptr = FindUser(nick); if (acptr && !IsServer(acptr)) { found++; do_whois(sptr, acptr, parc); } if (!found) send_reply(sptr, ERR_NOSUCHNICK, nick); total+=found; if (total >= MAX_WHOIS_LINES) { send_reply(sptr, ERR_QUERYTOOLONG, parv[1]); break; } if (p) p[-1] = ','; } /* of tokenised parm[1] */ send_reply(sptr, RPL_ENDOFWHOIS, parv[1]); return 0; }
/* * ms_rping - server message handler * -- by Run * * parv[0] = sender (sptr->name thus) * if sender is a person: (traveling towards start server) * parv[1] = pinged server[mask] * parv[2] = start server (current target) * parv[3] = optional remark * if sender is a server: (traveling towards pinged server) * parv[1] = pinged server (current target) * parv[2] = original sender (person) * parv[3] = start time in s * parv[4] = start time in us * parv[5] = the optional remark */ int ms_rping(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Client* destination = 0; assert(0 != cptr); assert(0 != sptr); assert(IsServer(cptr)); /* * shouldn't happen */ if (!IsPrivileged(sptr)) return 0; if (IsServer(sptr)) { if (parc < 6) { /* * PROTOCOL ERROR */ return need_more_params(sptr, "RPING"); } if ((destination = FindNServer(parv[1]))) { /* * if it's not for me, pass it on */ if (IsMe(destination)) sendcmdto_one(&me, CMD_RPONG, sptr, "%s %s %s %s :%s", cli_name(sptr), parv[2], parv[3], parv[4], parv[5]); else sendcmdto_one(sptr, CMD_RPING, destination, "%C %s %s %s :%s", destination, parv[2], parv[3], parv[4], parv[5]); } } else { if (parc < 3) { return need_more_params(sptr, "RPING"); } /* * Haven't made it to the start server yet, if I'm not the start server * pass it on. */ if (hunt_server_cmd(sptr, CMD_RPING, cptr, 1, "%s %C :%s", 2, parc, parv) != HUNTED_ISME) return 0; /* * otherwise ping the destination from here */ if ((destination = find_match_server(parv[1]))) { assert(IsServer(destination) || IsMe(destination)); sendcmdto_one(&me, CMD_RPING, destination, "%C %C %s :%s", destination, sptr, militime(0, 0), parv[3]); } else send_reply(sptr, ERR_NOSUCHSERVER, parv[1]); } return 0; }
/** Handle an ADMIN message from an oper's connection. * * \a parv has the following elements: * \li \a parv[1] (optional) is the server name being interrogated. * * See @ref m_functions for discussion of the arguments. * @param[in] cptr Client that sent us the message. * @param[in] sptr Original source of message. * @param[in] parc Number of arguments. * @param[in] parv Argument vector. */ int mo_admin(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { assert(0 != cptr); assert(cptr == sptr); if (hunt_server_cmd(sptr, CMD_ADMIN, cptr, feature_int(FEAT_HIS_REMOTE), ":%C", 1, parc, parv) != HUNTED_ISME) return 0; return send_admin_info(sptr); }
/* * m_time - generic message handler * * parv[0] = sender prefix * parv[1] = servername */ int m_time(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { if (hunt_server_cmd(sptr, CMD_TIME, cptr, feature_int(FEAT_HIS_REMOTE), ":%C", 1, parc, parv) != HUNTED_ISME) return 0; send_reply(sptr, RPL_TIME, cli_name(&me), TStime(), TSoffset, date((long)0)); return 0; }
/* * m_whowas - generic message handler * * parv[0] = sender prefix * parv[1] = nickname queried * parv[2] = maximum returned items (optional, default is unlimited) * parv[3] = remote server target (Opers only, max returned items 20) */ int m_whowas(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Whowas *temp; int cur = 0; int max = -1, found = 0; char *p, *nick, *s; if (parc < 2) { send_reply(sptr, ERR_NONICKNAMEGIVEN); return 0; } if (parc > 2) max = atoi(parv[2]); if (parc > 3) if (hunt_server_cmd(sptr, CMD_WHOWAS, cptr, 1, "%s %s :%C", 3, parc, parv)) return 0; parv[1] = canonize(parv[1]); if (!MyConnect(sptr) && (max > 20)) max = 20; /* Set max replies at 20 */ for (s = parv[1]; (nick = ircd_strtok(&p, s, ",")); s = 0) { /* Search through bucket, finding all nicknames that match */ found = 0; for (temp = whowashash[hash_whowas_name(nick)]; temp; temp = temp->hnext) { if (0 == ircd_strcmp(nick, temp->name)) { send_reply(sptr, RPL_WHOWASUSER, temp->name, temp->username, temp->hostname, temp->realname); if (IsAnOper(sptr) && temp->realhost) send_reply(sptr, RPL_WHOISACTUALLY, temp->name, temp->username, temp->realhost, "<untracked>"); send_reply(sptr, RPL_WHOISSERVER, temp->name, (feature_bool(FEAT_HIS_WHOIS_SERVERNAME) && !IsOper(sptr)) ? feature_str(FEAT_HIS_SERVERNAME) : temp->servername, myctime(temp->logoff)); if (temp->away) send_reply(sptr, RPL_AWAY, temp->name, temp->away); cur++; found++; } if (max >= 0 && cur >= max) break; } if (!found) send_reply(sptr, ERR_WASNOSUCHNICK, nick); /* To keep parv[1] intact for ENDOFWHOWAS */ if (p) p[-1] = ','; } send_reply(sptr, RPL_ENDOFWHOWAS, parv[1]); return 0; }
/* * m_rules - generic message handler * * parv[0] - sender prefix * parv[1] - servername */ int m_rules(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { if (!feature_bool(FEAT_RULES)) return send_reply(sptr, ERR_DISABLED, "RULES"); if (hunt_server_cmd(sptr, CMD_RULES, cptr, feature_int(FEAT_HIS_REMOTE), "%C", 1, parc, parv) != HUNTED_ISME) return 0; return motd_send_type(sptr, MOTD_RULES); }
/** Handle an ADMIN message from a server connection. * * \a parv has the following elements: * \li \a parv[1] is the server name being interrogated. * * See @ref m_functions for discussion of the arguments. * @param[in] cptr Client that sent us the message. * @param[in] sptr Original source of message. * @param[in] parc Number of arguments. * @param[in] parv Argument vector. */ int ms_admin(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { assert(0 != cptr); assert(0 != sptr); if (parc < 2) return 0; if (hunt_server_cmd(sptr, CMD_ADMIN, cptr, 0, ":%C", 1, parc, parv) != HUNTED_ISME) return 0; return send_admin_info(sptr); }
/** Handle a STATS message from some connection. * * \a parv has the following elements: * \li \a parv[1] is the statistics selector * \li \a parv[2] (optional) is server to query * \li \a parv[3] (optional) is a mask to filter the results * * If \a parv[1] is "l" (or "links"), \a parv[3] is a mask of servers. * If \a parv[1] is "p" (or "P" or "ports"), \a parv[3] is a mask of * ports. If \a parv[1] is "k" (or "K" or "klines" or "i" or "I" or * "access"), \a parv[3] is a hostname with optional username@ prefix * (for opers, hostmasks are allowed). * * See @ref m_functions for discussion of the arguments. * @param[in] cptr Client that sent us the message. * @param[in] sptr Original source of message. * @param[in] parc Number of arguments. * @param[in] parv Argument vector. */ int m_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { const struct StatDesc *sd; char *param; /* If we didn't find a descriptor, send them help */ if ((parc < 2) || !(sd = stats_find(parv[1]))) parv[1] = "*", sd = stats_find("*"); assert(sd != 0); /* Check whether the client can issue this command. If source is * not privileged (server or an operator), then the STAT_FLAG_OPERONLY * flag must not be set, and if the STAT_FLAG_OPERFEAT flag is set, * then the feature given by sd->sd_control must be off. * * This checks cptr rather than sptr so that a local oper may send * /stats queries to other servers. */ if (!IsPrivileged(cptr) && ((sd->sd_flags & STAT_FLAG_OPERONLY) || ((sd->sd_flags & STAT_FLAG_OPERFEAT) && feature_bool(sd->sd_control)))) return send_reply(sptr, ERR_NOPRIVILEGES); /* Check for extra parameter */ if ((sd->sd_flags & STAT_FLAG_VARPARAM) && parc > 3 && !EmptyString(parv[3])) param = parv[3]; else param = NULL; /* Ok, track down who's supposed to get this... */ if (hunt_server_cmd(sptr, CMD_STATS, cptr, feature_int(FEAT_HIS_REMOTE), param ? "%s %C :%s" : "%s :%C", 2, parc, parv) != HUNTED_ISME) return 0; /* Someone else--cool :) */ /* Check if they are a local user */ if ((sd->sd_flags & STAT_FLAG_LOCONLY) && !MyUser(sptr)) return send_reply(sptr, ERR_NOPRIVILEGES); assert(sd->sd_func != 0); /* Ok, dispatch the stats function */ (*sd->sd_func)(sptr, sd, param); /* Done sending them the stats */ return send_reply(sptr, RPL_ENDOFSTATS, parv[1]); }
/* * ms_uping - server message handler * * m_uping -- by Run * * parv[0] = sender prefix * parv[1] = pinged server * parv[2] = port * parv[3] = hunted server * parv[4] = number of requested pings */ int ms_uping(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct ConfItem *aconf; int port; int count; assert(0 != cptr); assert(0 != sptr); if (!IsAnOper(sptr)) { send_reply(sptr, ERR_NOPRIVILEGES); return 0; } if (parc < 5) { send_reply(sptr, ERR_NEEDMOREPARAMS, "UPING"); return 0; } if (hunt_server_cmd(sptr, CMD_UPING, cptr, 1, "%s %s %C %s", 3, parc, parv) != HUNTED_ISME) return 0; /* * Determine port: First user supplied, then default : 7007 */ if (EmptyString(parv[2]) || (port = atoi(parv[2])) <= 0) port = atoi(UDP_PORT); if (EmptyString(parv[4]) || (count = atoi(parv[4])) <= 0) { sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :UPING : Illegal number of " "packets: %s", sptr, parv[4]); return 0; } /* * Check if a CONNECT would be possible at all (adapted from m_connect) */ if ((aconf = conf_find_server(parv[1]))) uping_server(sptr, aconf, port, count); else sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :UPING: Host %s not listed in " "ircd.conf", sptr, parv[1]); return 0; }
/* * m_copyright - generic message handler * * parv[0] - sender prefix * parv[1] - servername * */ int m_copyright(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { const char **text = copyrighttext; if (hunt_server_cmd(sptr, CMD_COPYRIGHT, cptr, 1, ":%C", 1, parc, parv) != HUNTED_ISME) return 0; while (text[0]) { send_reply(sptr, RPL_INFO, *text); text++; } send_reply(sptr, RPL_INFO, ""); send_reply(sptr, RPL_ENDOFINFO); return 0; }
/* * mo_rping - oper message handler * -- by Run * * * Receive: * RPING blah.* * RPING blah.* :<start time> * RPING blah.* server.* :<start time> * * parv[0] = sender (sptr->name thus) * parv[1] = pinged server name or mask (required) * parv[2] = start server name or mask (optional, defaults to me) * parv[3] = client start time (optional) * * Send: NumNick(sptr) RPING blah.* server.net :<start time> (hunt_server) * NumServ(&me) RPING NumServ(blah.bar.net) NumNick(sptr) :<start time> (here) */ int mo_rping(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Client* acptr = 0; const char* start_time = "<No client start time>"; assert(0 != cptr); assert(0 != sptr); assert(cptr == sptr); assert(IsAnOper(sptr)); if (parc < 2) return need_more_params(sptr, "RPING"); if (parc > 2) { if ((acptr = find_match_server(parv[2])) && !IsMe(acptr)) { parv[2] = cli_name(acptr); if (3 == parc) { /* * const_cast<char*>(start_time); */ parv[parc++] = (char*) start_time; } hunt_server_cmd(sptr, CMD_RPING, cptr, 1, "%s %C :%s", 2, parc, parv); return 0; } else start_time = parv[2]; } if ((acptr = find_match_server(parv[1]))) { assert(IsServer(acptr) || IsMe(acptr)); sendcmdto_one(&me, CMD_RPING, acptr, "%C %C %s :%s", acptr, sptr, militime(0, 0), start_time); } else send_reply(sptr, ERR_NOSUCHSERVER, parv[1]); return 0; }
/* * m_links - generic message handler * * parv[0] = sender prefix * parv[1] = servername mask * * or * * parv[0] = sender prefix * parv[1] = server to query * parv[2] = servername mask */ int m_links(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { char *mask; struct Client *acptr; if (feature_bool(FEAT_HIS_LINKS) && !IsAnOper(sptr)) { send_reply(sptr, RPL_ENDOFLINKS, parc < 2 ? "*" : parv[1]); sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s %s", sptr, "/LINKS has been disabled, from CFV-165. Visit ", feature_str(FEAT_HIS_URLSERVERS)); return 0; } if (parc > 2) { if (hunt_server_cmd(sptr, CMD_LINKS, cptr, 1, "%C :%s", 1, parc, parv) != HUNTED_ISME) return 0; mask = parv[2]; } else mask = parc < 2 ? 0 : parv[1]; for (acptr = GlobalClientList, collapse(mask); acptr; acptr = cli_next(acptr)) { if (!IsServer(acptr) && !IsMe(acptr)) continue; if (!BadPtr(mask) && match(mask, cli_name(acptr))) continue; send_reply(sptr, RPL_LINKS, cli_name(acptr), cli_name(cli_serv(acptr)->up), cli_hopcount(acptr), cli_serv(acptr)->prot, ((cli_info(acptr))[0] ? cli_info(acptr) : "(Unknown Location)")); } send_reply(sptr, RPL_ENDOFLINKS, BadPtr(mask) ? "*" : mask); return 0; }
/* * mo_version - oper message handler * * parv[0] = sender prefix * parv[1] = servername */ int mo_version(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Client *acptr; if (MyConnect(sptr) && parc > 1) { if (!(acptr = find_match_server(parv[1]))) { send_reply(sptr, ERR_NOSUCHSERVER, parv[1]); return 0; } parv[1] = cli_name(acptr); } if (hunt_server_cmd(sptr, CMD_VERSION, cptr, feature_int(FEAT_HIS_REMOTE), ":%C", 1, parc, parv) == HUNTED_ISME) { send_reply(sptr, RPL_VERSION, version, cvs_version, debugmode, cli_name(&me), debug_serveropts()); #ifdef USE_SSL #ifdef DEBUGMODE sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Headers: %s", sptr, OPENSSL_VERSION_TEXT); #endif sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Library: %s", sptr, SSLeay_version(SSLEAY_VERSION)); #endif #ifdef USE_GEOIP sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :GeoIP %s", sptr, geoip_version()); #endif #ifdef USE_MMDB sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :MaxMindDB %s", sptr, geoip_libmmdb_version()); #endif send_supported(sptr); } return 0; }
static void do_trace(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { int i; struct Client *acptr; struct Client *acptr2; const struct ConnectionClass* cl; char* tname; int doall; int *link_s; int *link_u; int cnt = 0; int wilds; int dow; if (parc < 2 || BadPtr(parv[1])) { /* just "TRACE" without parameters. Must be from local client */ parc = 1; acptr = &me; tname = cli_name(&me); i = HUNTED_ISME; } else if (parc < 3 || BadPtr(parv[2])) { /* No target specified. Make one before propagating. */ parc = 2; tname = parv[1]; if ((acptr = find_match_server(parv[1])) || ((acptr = FindClient(parv[1])) && !MyUser(acptr))) { if (IsUser(acptr)) parv[2] = cli_name(cli_user(acptr)->server); else parv[2] = cli_name(acptr); parc = 3; parv[3] = 0; if ((i = hunt_server_cmd(sptr, CMD_TRACE, cptr, IsServer(acptr), "%s :%C", 2, parc, parv)) == HUNTED_NOSUCH) return; } else i = HUNTED_ISME; } else { /* Got "TRACE <tname> :<target>" */ parc = 3; if (MyUser(sptr) || Protocol(cptr) < 10) acptr = find_match_server(parv[2]); else acptr = FindNServer(parv[2]); if ((i = hunt_server_cmd(sptr, CMD_TRACE, cptr, 0, "%s :%C", 2, parc, parv)) == HUNTED_NOSUCH) return; tname = parv[1]; } if (i == HUNTED_PASS) { if (!acptr) acptr = next_client(GlobalClientList, tname); else acptr = cli_from(acptr); send_reply(sptr, RPL_TRACELINK, version, debugmode, tname, acptr ? cli_name(cli_from(acptr)) : "<No_match>"); return; } doall = (parv[1] && (parc > 1)) ? !match(tname, cli_name(&me)) : 1; wilds = !parv[1] || strchr(tname, '*') || strchr(tname, '?'); dow = wilds || doall; /* Don't give (long) remote listings to lusers */ if (dow && !MyConnect(sptr) && !IsAnOper(sptr)) { send_reply(sptr, RPL_TRACEEND); return; } link_s = MyCalloc(2 * maxconnections, sizeof(link_s[0])); link_u = link_s + maxconnections; if (doall) { for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr)) { if (IsUser(acptr)) link_u[cli_fd(cli_from(acptr))]++; else if (IsServer(acptr)) link_s[cli_fd(cli_from(acptr))]++; } } /* report all direct connections */ for (i = 0; i <= HighestFd; i++) { const char *conClass; if (!(acptr = LocalClientArray[i])) /* Local Connection? */ continue; if (IsInvisible(acptr) && dow && !(MyConnect(sptr) && IsOper(sptr)) && !IsAnOper(acptr) && (acptr != sptr)) continue; if (!doall && wilds && match(tname, cli_name(acptr))) continue; if (!dow && 0 != ircd_strcmp(tname, cli_name(acptr))) continue; conClass = get_client_class(acptr); switch (cli_status(acptr)) { case STAT_CONNECTING: send_reply(sptr, RPL_TRACECONNECTING, conClass, cli_name(acptr)); cnt++; break; case STAT_HANDSHAKE: send_reply(sptr, RPL_TRACEHANDSHAKE, conClass, cli_name(acptr)); cnt++; break; case STAT_ME: break; case STAT_UNKNOWN: case STAT_UNKNOWN_USER: send_reply(sptr, RPL_TRACEUNKNOWN, conClass, get_client_name(acptr, HIDE_IP)); cnt++; break; case STAT_UNKNOWN_SERVER: send_reply(sptr, RPL_TRACEUNKNOWN, conClass, "Unknown Server"); cnt++; break; case STAT_USER: /* Only opers see users if there is a wildcard but anyone can see all the opers. */ if ((IsAnOper(sptr) && (MyUser(sptr) || !(dow && IsInvisible(acptr)))) || !dow || IsAnOper(acptr)) { if (IsAnOper(acptr)) send_reply(sptr, RPL_TRACEOPERATOR, conClass, get_client_name(acptr, SHOW_IP), CurrentTime - cli_lasttime(acptr)); else send_reply(sptr, RPL_TRACEUSER, conClass, get_client_name(acptr, SHOW_IP), CurrentTime - cli_lasttime(acptr)); cnt++; } break; /* * Connection is a server * * Serv <class> <nS> <nC> <name> <ConnBy> <last> <age> * * class Class the server is in * nS Number of servers reached via this link * nC Number of clients reached via this link * name Name of the server linked * ConnBy Who established this link * last Seconds since we got something from this link * age Seconds this link has been alive * * Additional comments etc...... -Cym-<*****@*****.**> */ case STAT_SERVER: if (cli_serv(acptr)->user) { if (!cli_serv(acptr)->by[0] || !(acptr2 = findNUser(cli_serv(acptr)->by)) || (cli_user(acptr2) != cli_serv(acptr)->user)) acptr2 = NULL; send_reply(sptr, RPL_TRACESERVER, conClass, link_s[i], link_u[i], cli_name(acptr), acptr2 ? cli_name(acptr2) : "*", cli_serv(acptr)->user->username, cli_serv(acptr)->user->host, CurrentTime - cli_lasttime(acptr), CurrentTime - cli_serv(acptr)->timestamp); } else send_reply(sptr, RPL_TRACESERVER, conClass, link_s[i], link_u[i], cli_name(acptr), (*(cli_serv(acptr))->by) ? cli_serv(acptr)->by : "*", "*", cli_name(&me), CurrentTime - cli_lasttime(acptr), CurrentTime - cli_serv(acptr)->timestamp); cnt++; break; default: /* We actually shouldn't come here, -msa */ send_reply(sptr, RPL_TRACENEWTYPE, get_client_name(acptr, HIDE_IP)); cnt++; break; } } /* * Add these lines to summarize the above which can get rather long * and messy when done remotely - Avalon */ if (IsAnOper(sptr) && doall) { for (cl = get_class_list(); cl; cl = cl->next) { if (Links(cl) > 1) send_reply(sptr, RPL_TRACECLASS, ConClass(cl), Links(cl) - 1); } } send_reply(sptr, RPL_TRACEEND); MyFree(link_s); }
/** Handle a CONNECT message from a server. * * \a parv has the following elements: * \li \a parv[1] is the server that should initiate the connection * \li \a parv[2] is the port number to connect on (zero for the default) * \li \a parv[3] is the server to connect to * * See @ref m_functions for discussion of the arguments. * @param[in] cptr Client that sent us the message. * @param[in] sptr Original source of message. * @param[in] parc Number of arguments. * @param[in] parv Argument vector. */ int ms_connect(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { unsigned short port; unsigned short tmpport; const char* rule; struct ConfItem* aconf; struct Client* acptr; struct Jupe* ajupe; assert(0 != cptr); assert(0 != sptr); if (!IsPrivileged(sptr)) return send_reply(sptr, ERR_NOPRIVILEGES); if (parc < 4) { /* * this is coming from a server which should have already * checked it's args, if we don't have parc == 4, something * isn't right. */ protocol_violation(sptr, "Too few parameters to connect"); return need_more_params(sptr, "CONNECT"); } if (hunt_server_cmd(sptr, CMD_CONNECT, cptr, 1, "%s %s :%C", 3, parc, parv) != HUNTED_ISME) return 0; /* * need to find the conf entry first so we can use the server name from * the conf entry instead of parv[1] to find out if the server is already * present below. --Bleep */ if (0 == (aconf = conf_find_server(parv[1]))) { sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Connect: Host %s not listed " "in ircd.conf", sptr, parv[1]); return 0; } /* * use aconf->name to look up the server */ if ((acptr = FindServer(aconf->name))) { sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Connect: Server %s already " "exists from %s", sptr, parv[1], cli_name(cli_from(acptr))); return 0; } /* * Evaluate connection rules... If no rules found, allow the * connect. Otherwise stop with the first true rule (ie: rules * are ored together. Oper connects are effected only by D * lines (CRULEALL) not d lines (CRULEAUTO). */ if ((rule = conf_eval_crule(aconf->name, CRULE_ALL))) { sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Connect: Disallowed by rule: %s", sptr, rule); return 0; } /* * Check to see if the server is juped; if it is, disallow the connect */ if ((ajupe = jupe_find(aconf->name)) && JupeIsActive(ajupe)) { sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Connect: Server %s is juped: %s", sptr, JupeServer(ajupe), JupeReason(ajupe)); return 0; } /* * Allow opers to /connect foo.* 0 bah.* to connect foo and bah * using the conf's configured port */ port = atoi(parv[2]); /* * save the old port */ tmpport = aconf->address.port; if (port) aconf->address.port = port; else port = aconf->address.port; /* * Notify all operators about remote connect requests */ sendwallto_group(&me, WALL_WALLOPS, 0, "Remote CONNECT %s %s from %s", parv[1], parv[2] ? parv[2] : "", get_client_name(sptr, HIDE_IP)); log_write(LS_NETWORK, L_INFO, 0, "CONNECT From %C : %s %s", sptr, parv[1], parv[2] ? parv[2] : ""); if (connect_server(aconf, sptr)) { sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :*** Connecting to %s.", sptr, aconf->name); } else { sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :*** Connection to %s failed", sptr, aconf->name); } aconf->address.port = tmpport; return 0; }
/** Handle a CONNECT message from an operator. * * \a parv has the following elements: * \li \a parv[1] is the server that should initiate the connection * \li \a parv[2] is the port number to connect on (zero for the default) * \li \a parv[3] is the server to connect to * * See @ref m_functions for discussion of the arguments. * @param[in] cptr Client that sent us the message. * @param[in] sptr Original source of message. * @param[in] parc Number of arguments. * @param[in] parv Argument vector. */ int mo_connect(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { unsigned short port; unsigned short tmpport; const char* rule; struct ConfItem* aconf; struct Client* acptr; struct Jupe* ajupe; assert(0 != cptr); assert(cptr == sptr); assert(IsAnOper(sptr)); if (parc < 2) return need_more_params(sptr, "CONNECT"); if (parc > 3) { /* * if parc > 3, we are trying to connect two remote * servers to each other */ if (IsLocOp(sptr)) { /* * Only allow LocOps to make local CONNECTS --SRB */ return send_reply(cptr, ERR_NOPRIVILEGES); } else { struct Client* acptr2; struct Client* acptr3; if (!(acptr3 = find_match_server(parv[3]))) { return send_reply(sptr, ERR_NOSUCHSERVER, parv[3]); } /* * Look for closest matching server * needed for "/connect blah 4400 *"? */ for (acptr2 = acptr3; acptr2 != &me; acptr2 = cli_serv(acptr2)->up) { if (!match(parv[3], cli_name(acptr2))) acptr3 = acptr2; } parv[3] = cli_name(acptr3); if (hunt_server_cmd(sptr, CMD_CONNECT, cptr, 1, "%s %s :%C", 3, parc, parv) != HUNTED_ISME) return 0; } } /* * need to find the conf entry first so we can use the server name from * the conf entry instead of parv[1] to find out if the server is already * present below. --Bleep */ if (0 == (aconf = conf_find_server(parv[1]))) { sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Connect: Host %s not listed " "in ircd.conf", sptr, parv[1]); return 0; } /* * use aconf->name to look up the server, see above */ if ((acptr = FindServer(aconf->name))) { sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Connect: Server %s already " "exists from %s", sptr, parv[1], cli_name(cli_from(acptr))); return 0; } /* * Evaluate connection rules... If no rules found, allow the * connect. Otherwise stop with the first true rule (ie: rules * are ored together. Oper connects are effected only by D * lines (CRULEALL) not d lines (CRULEAUTO). */ if ((rule = conf_eval_crule(aconf->name, CRULE_ALL))) { sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Connect: Disallowed by rule: %s", sptr, rule); return 0; } /* * Check to see if the server is juped; if it is, disallow the connect */ if ((ajupe = jupe_find(aconf->name)) && JupeIsActive(ajupe)) { sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Connect: Server %s is juped: %s", sptr, JupeServer(ajupe), JupeReason(ajupe)); return 0; } /* * Get port number from user, if given. If not specified, * use the default from configuration structure. If missing * from there, then use the precompiled default. */ port = aconf->address.port; if (parc > 2) { assert(0 != parv[2]); if (0 == (port = atoi(parv[2]))) { sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Connect: Invalid port number", sptr); return 0; } } if (0 == port && 0 == (port = feature_int(FEAT_SERVER_PORT))) { sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Connect: missing port number", sptr); return 0; } tmpport = aconf->address.port; aconf->address.port = port; if (connect_server(aconf, sptr)) { sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :*** Connecting to %s.", sptr, aconf->name); } else { sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :*** Connection to %s failed", sptr, aconf->name); } aconf->address.port = tmpport; return 0; }
/* * m_whois - generic message handler * * parv[0] = sender prefix * parv[1] = nickname masklist * * or * * parv[1] = target server, or a nickname representing a server to target. * parv[2] = nickname masklist */ int m_whois(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { char* nick; char* tmp; char* p = 0; int found = 0; int total = 0; int wildscount = 0; if (parc < 2) { send_reply(sptr, ERR_NONICKNAMEGIVEN); return 0; } if (parc > 2) { /* For convenience: Accept a nickname as first parameter, by replacing * it with the correct servername - as is needed by hunt_server(). * This is the secret behind the /whois nick nick trick. */ if (feature_int(FEAT_HIS_REMOTE)) { /* If remote queries are disabled, then use the *second* parameter of * of whois, so /whois nick nick still works. */ if (!IsAnOper(sptr)) { if (!FindUser(parv[2])) { send_reply(sptr, ERR_NOSUCHNICK, parv[2]); send_reply(sptr, RPL_ENDOFWHOIS, parv[2]); return 0; } parv[1] = parv[2]; } } if (hunt_server_cmd(sptr, CMD_WHOIS, cptr, 0, "%C :%s", 1, parc, parv) != HUNTED_ISME) return 0; parv[1] = parv[2]; } for (tmp = parv[1]; (nick = ircd_strtok(&p, tmp, ",")); tmp = 0) { int wilds; found = 0; collapse(nick); wilds = (strchr(nick, '?') || strchr(nick, '*')); if (!wilds) { struct Client *acptr = 0; /* No wildcards */ acptr = FindUser(nick); if (acptr && !IsServer(acptr)) { do_whois(sptr, acptr, parc); found = 1; } } else /* wilds */ { if (++wildscount > 3) { send_reply(sptr, ERR_QUERYTOOLONG, parv[1]); break; } found=do_wilds(sptr, nick, total, parc); } if (!found) send_reply(sptr, ERR_NOSUCHNICK, nick); total+=found; if (total >= MAX_WHOIS_LINES) { send_reply(sptr, ERR_QUERYTOOLONG, parv[1]); break; } if (p) p[-1] = ','; } /* of tokenised parm[1] */ send_reply(sptr, RPL_ENDOFWHOIS, parv[1]); return 0; }
int m_names(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Channel *chptr; struct Channel *ch2ptr; struct Client *c2ptr; struct Membership* member; char* s; char* para = parc > 1 ? parv[1] : 0; int showingdelayed = 0; if (parc > 1 && !ircd_strcmp(parv[1], "-D")) { para = (parc > 2) ? parv[2] : 0; showingdelayed = NAMES_DEL; if (parc > 3 && hunt_server_cmd(sptr, CMD_NAMES, cptr, 1, "%s %s %C", 3, parc, parv)) return 0; } else if (parc > 2 && hunt_server_cmd(sptr, CMD_NAMES, cptr, 1, "%s %C", 2, parc, parv)) return 0; if (EmptyString(para)) { send_reply(sptr, RPL_ENDOFNAMES, "*"); return 0; } do { s = strchr(para, ','); if (s) *s++ = '\0'; /* * Special Case 1: "/names 0". * Full list as per RFC. */ if ((*para == '0') || (*para == '\0')) { int idx; int mlen; int flag; struct Channel *ch3ptr; char buf[BUFSIZE]; mlen = strlen(cli_name(&me)) + 10 + strlen(cli_name(sptr)); /* List all visible channels/visible members */ for (ch2ptr = GlobalChannelList; ch2ptr; ch2ptr = ch2ptr->next) { if (!ShowChannel(sptr, ch2ptr)) continue; /* Don't show secret chans. */ else if (find_channel_member(sptr, ch2ptr)) do_names(sptr, ch2ptr, showingdelayed|NAMES_ALL); /* Full list if we're in this chan. */ else do_names(sptr, ch2ptr, showingdelayed|NAMES_VIS); } /* List all remaining users on channel '*' */ strcpy(buf, "* * :"); idx = 5; flag = 0; for (c2ptr = GlobalClientList; c2ptr; c2ptr = cli_next(c2ptr)) { int showflag = 0; if (!IsUser(c2ptr) || (sptr != c2ptr && IsInvisible(c2ptr))) continue; member = cli_user(c2ptr)->channel; while (member) { ch3ptr = member->channel; if (PubChannel(ch3ptr) || find_channel_member(sptr, ch3ptr)) showflag = 1; member = member->next_channel; } if (showflag) /* Have we already shown them? */ continue; strcpy(buf + idx, cli_name(c2ptr)); idx += strlen(cli_name(c2ptr)); buf[idx++] = ' '; flag = 1; if (mlen + idx + NICKLEN + 3 > BUFSIZE) /* space, \r\n\0 */ { send_reply(sptr, RPL_NAMREPLY, buf); strcpy(buf, "* * :"); idx = 5; flag = 0; } } if (flag) send_reply(sptr, RPL_NAMREPLY, buf); send_reply(sptr, RPL_ENDOFNAMES, "*"); } else if ((chptr = FindChannel(para)) != NULL) { member = find_member_link(chptr, sptr); if (member) { /* * Special Case 2: User is on this channel, requesting full names list. * (As performed with each /join) - ** High frequency usage ** */ do_names(sptr, chptr, showingdelayed|NAMES_ALL|NAMES_EON); } else { /* * Special Case 3: User isn't on this channel, show all visible users, in * non secret channels. */ do_names(sptr, chptr, showingdelayed|NAMES_VIS|NAMES_EON); } } else send_reply(sptr, RPL_ENDOFNAMES, para); } while ((para = s) != NULL); return 1; }
/* * Syntax: CHECK <channel|nick|server|hostmask> [-flags] * * Where valid flags are: * -c: Show channels when checking a hostmask. * -i: Show IPs instead of hostnames when displaying results. * -o: Only show channel operators when checking a channel. * -u: Hide users when checking a channel. * * <hostmask> can be of the form host, user@host, nick!user@host, * with host being host.domain.cc, 127.0.0.1 or 127.0.0.0/24. * Wildcards are supported. */ int mo_check(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { struct Channel *chptr; struct Client *acptr; int flags = CHECK_SHOWUSERS, i; if (!HasPriv(sptr, PRIV_CHECK)) return send_reply(sptr, ERR_DISABLED, "CHECK"); if (parc < 2) { send_reply(sptr, ERR_NEEDMOREPARAMS, "CHECK"); return 0; } if ( parc>=4 || (parc==3 && parv[2][0] != '-')) { /* remote query */ if (hunt_server_cmd(sptr, CMD_CHECK, cptr, 0, parc==4 ? "%C %s %s" : "%C %s", 1, parc, parv) != HUNTED_ISME) return 0; parv++; parc--; } /* This checks to see if any flags have been supplied */ if ((parc >= 3) && (parv[2][0] == '-')) { for (i = 0; parv[2][i]; i++) { switch (parv[2][i]) { case 'c': flags |= CHECK_CHECKCHAN; break; case 'o': flags |= CHECK_OPSONLY; /* fall through */ case 'u': flags &= ~(CHECK_SHOWUSERS); break; case 'i': flags |= CHECK_SHOWIPS; break; default: /* might want to raise some sort of error here? */ break; } } } if (IsChannelName(parv[1])) /* channel */ { if ((chptr = FindChannel(parv[1]))) { checkChannel(sptr, chptr); checkUsers(sptr, chptr, flags); } else { send_reply(sptr, ERR_SEARCHNOMATCH, "CHECK", parv[1]); } } else if ((acptr = FindClient(parv[1])) && !(FindServer(parv[1]))) /* client and not a server */ { if (!IsRegistered(acptr)) { send_reply(sptr, ERR_SEARCHNOMATCH, "CHECK", parv[1]); return 0; } checkClient(sptr, acptr); } else if ((acptr = FindServer(parv[1]))) { /* server */ checkServer(sptr, acptr); } else if (checkHostmask(sptr, parv[1], flags) > 0) /* hostmask */ return 1; else /* no match */ send_reply(sptr, ERR_SEARCHNOMATCH, "CHECK", parv[1]); return 1; }