/** Send a server notice to all users with the indicated \a mode except * for \a one. * @param[in] one Client direction to skip (or NULL). * @param[in] mode One mode character. * @param[in] pattern Format string for server notice. * @param[in] vl Argument list for format string. */ void vsendto_mode_butone(struct Client *one, struct Client *from, const char *mode, const char *pattern, va_list vl) { struct VarData vd; struct MsgBuf *mb; struct Client* acptr = 0; vd.vd_format = pattern; va_copy(vd.vd_args, vl); /* send to local users */ mb = msgq_make(0, ":%s " MSG_NOTICE " * :*** Notice -- %v", cli_name(from), &vd); for (acptr = &me; acptr; acptr = cli_prev(acptr)) { if (IsUser(acptr)) { switch (*mode) { case 'O': if (IsLocOp(acptr)) send_buffer(acptr, mb, 0); break; case 'o': if (IsOper(acptr)) send_buffer(acptr, mb, 0); break; default: break; /* ignore, should only happen if incorrectly injected via raw */ } } } msgq_clean(mb); }
/* * mo_squit (oper) * * parv[0] = sender prefix * parv[1] = server name * parv[2] = comment (optional) * */ int mo_squit(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { const char* server; struct Client *acptr; struct Client *acptr2; char *comment; if (parc < 2) return need_more_params(sptr, "SQUIT"); if (parc < 3 || BadPtr(parv[2])) comment = cli_name(sptr); else comment = parv[2]; server = parv[1]; /* * The following allows wild cards in SQUIT. Only useful * when the command is issued by an oper. */ for (acptr = GlobalClientList; (acptr = next_client(acptr, server)); acptr = cli_next(acptr)) { if (IsServer(acptr) || IsMe(acptr)) break; } /* Not found? Bugger. */ if (!acptr || IsMe(acptr)) return send_reply(sptr, ERR_NOSUCHSERVER, server); /* * Look for a matching server that is closer, * that way we won't accidentally squit two close * servers like davis.* and davis-r.* when typing * /SQUIT davis* */ for (acptr2 = cli_serv(acptr)->up; acptr2 != &me; acptr2 = cli_serv(acptr2)->up) if (!match(server, cli_name(acptr2))) acptr = acptr2; /* Disallow local opers to squit remote servers */ if (IsLocOp(sptr) && !MyConnect(acptr)) return send_reply(sptr, ERR_NOPRIVILEGES); return exit_client(cptr, acptr, sptr, comment); }
DLLFUNC int m_chghost(aClient *cptr, aClient *sptr, int parc, char *parv[]) { aClient *acptr; if (MyClient(sptr) && !IsAnOper(sptr)) { sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } #ifdef DISABLE_USERMOD if (MyClient(sptr)) { sendto_one(sptr, err_str(ERR_DISABLED), me.name, sptr->name, "CHGHOST", "This command is disabled on this server"); return 0; } #endif if ((parc < 3) || !*parv[2]) { sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, sptr->name, "CHGHOST"); return 0; } if (strlen(parv[2]) > (HOSTLEN)) { sendnotice(sptr, "*** ChgName Error: Requested hostname too long -- rejected."); return 0; } if (!valid_host(parv[2])) { sendnotice(sptr, "*** /ChgHost Error: A hostname may contain a-z, A-Z, 0-9, '-' & '.' - Please only use them"); return 0; } if (parv[2][0] == ':') { sendnotice(sptr, "*** A hostname cannot start with ':'"); return 0; } if ((acptr = find_person(parv[1], NULL))) { if (MyClient(sptr) && (IsLocOp(sptr) && !MyClient(acptr))) { sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } if (!strcmp(GetHost(acptr), parv[2])) { sendnotice(sptr, "*** /ChgHost Error: requested host is same as current host."); return 0; } switch (UHOST_ALLOWED) { case UHALLOW_NEVER: if (MyClient(sptr)) { sendto_one(sptr, err_str(ERR_DISABLED), me.name, sptr->name, "CHGHOST", "This command is disabled on this server"); return 0; } break; case UHALLOW_ALWAYS: break; case UHALLOW_NOCHANS: if (IsPerson(acptr) && MyClient(sptr) && acptr->user->joined) { sendnotice(sptr, "*** /ChgHost can not be used while %s is on a channel", acptr->name); return 0; } break; case UHALLOW_REJOIN: rejoin_doquits(acptr); /* join sent later when the host has been changed */ break; } if (!IsULine(sptr)) { sendto_snomask(SNO_EYES, "%s changed the virtual hostname of %s (%s@%s) to be %s", sptr->name, acptr->name, acptr->user->username, acptr->user->realhost, parv[2]); /* Logging added by XeRXeS */ ircd_log(LOG_CHGCMDS, "CHGHOST: %s changed the virtual hostname of %s (%s@%s) to be %s", sptr->name, acptr->name, acptr->user->username, acptr->user->realhost, parv[2]); } acptr->umodes |= UMODE_HIDE; acptr->umodes |= UMODE_SETHOST; sendto_server(cptr, 0, 0, ":%s CHGHOST %s %s", sptr->name, acptr->name, parv[2]); if (acptr->user->virthost) { MyFree(acptr->user->virthost); acptr->user->virthost = 0; } acptr->user->virthost = strdup(parv[2]); if (UHOST_ALLOWED == UHALLOW_REJOIN) rejoin_dojoinandmode(acptr); return 0; } else { sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, sptr->name, parv[1]); return 0; } return 0; }
/* * m_squit - SQUIT message handler * parv[0] = sender prefix * parv[1] = server name * parv[2] = comment */ int m_squit(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { struct ConfItem* aconf; char* server; struct Client* acptr; char *comment = (parc > 2 && parv[2]) ? parv[2] : cptr->name; if (!IsPrivileged(sptr)) { sendto_one(sptr, form_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } if (parc > 1) { server = parv[1]; /* ** To accomodate host masking, a squit for a masked server ** name is expanded if the incoming mask is the same as ** the server name for that link to the name of link. */ while ((*server == '*') && IsServer(cptr)) { aconf = cptr->serv->nline; if (!aconf) break; if (!irccmp(server, my_name_for_link(me.name, aconf))) server = cptr->name; break; /* WARNING is normal here */ /* NOTREACHED */ } /* ** The following allows wild cards in SQUIT. Only useful ** when the command is issued by an oper. */ for (acptr = GlobalClientList; (acptr = next_client(acptr, server)); acptr = acptr->next) if (IsServer(acptr) || IsMe(acptr)) break; if (acptr && IsMe(acptr)) { acptr = cptr; server = cptr->name; } } else { /* ** This is actually protocol error. But, well, closing ** the link is very proper answer to that... ** ** Closing the client's connection probably wouldn't do much ** good.. any oper out there should know that the proper way ** to disconnect is /QUIT :) ** ** its still valid if its not a local client, its then ** a protocol error for sure -Dianora */ if(MyClient(sptr)) { sendto_one(sptr, form_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "SQUIT"); return 0; } else { server = cptr->host; acptr = cptr; } } /* ** SQUIT semantics is tricky, be careful... ** ** The old (irc2.2PL1 and earlier) code just cleans away the ** server client from the links (because it is never true ** "cptr == acptr". ** ** This logic here works the same way until "SQUIT host" hits ** the server having the target "host" as local link. Then it ** will do a real cleanup spewing SQUIT's and QUIT's to all ** directions, also to the link from which the orinal SQUIT ** came, generating one unnecessary "SQUIT host" back to that ** link. ** ** One may think that this could be implemented like ** "hunt_server" (e.g. just pass on "SQUIT" without doing ** nothing until the server having the link as local is ** reached). Unfortunately this wouldn't work in the real life, ** because either target may be unreachable or may not comply ** with the request. In either case it would leave target in ** links--no command to clear it away. So, it's better just ** clean out while going forward, just to be sure. ** ** ...of course, even better cleanout would be to QUIT/SQUIT ** dependant users/servers already on the way out, but ** currently there is not enough information about remote ** clients to do this... --msa */ if (!acptr) { sendto_one(sptr, form_str(ERR_NOSUCHSERVER), me.name, parv[0], server); return 0; } if (IsLocOp(sptr) && !MyConnect(acptr)) { sendto_one(sptr, form_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } if (MyClient(sptr) && !IsOperRemote(sptr) && !MyConnect(acptr)) { sendto_one(sptr,":%s NOTICE %s :You have no R flag",me.name,parv[0]); return 0; } /* ** Notify all opers, if my local link is remotely squitted */ if (MyConnect(acptr) && !IsAnOper(cptr)) { sendto_ops_butone(NULL, &me, ":%s WALLOPS :Received SQUIT %s from %s (%s)", me.name, server, get_client_name(sptr,FALSE), comment); log(L_TRACE, "SQUIT From %s : %s (%s)", parv[0], server, comment); } else if (MyConnect(acptr)) sendto_ops("Received SQUIT %s from %s (%s)", acptr->name, get_client_name(sptr,FALSE), comment); return exit_client(cptr, acptr, sptr, comment); }
/** 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; }
int m_chgident(aClient *cptr, aClient *sptr, int parc, char *parv[]) { aClient *acptr; char *s; int legalident = 1; if (MyClient(sptr) && !IsAnOper(sptr)) { sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } #ifdef DISABLE_USERMOD if (MyClient(sptr)) { sendto_one(sptr, err_str(ERR_DISABLED), me.name, sptr->name, "CHGIDENT", "This command is disabled on this server"); return 0; } #endif if ((parc < 3) || !*parv[2]) { sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, sptr->name, "CHGIDENT"); return 0; } if (strlen(parv[2]) > (USERLEN)) { sendnotice(sptr, "*** ChgIdent Error: Requested ident too long -- rejected."); return 0; } /* illegal?! */ for (s = parv[2]; *s; s++) { if ((*s == '~') && (s == parv[2])) continue; if (!isallowed(*s)) { legalident = 0; } } if (legalident == 0) { sendnotice(sptr, "*** /ChgIdent Error: A ident may contain a-z, A-Z, 0-9, '-' & '.' - Please only use them"); return 0; } if ((acptr = find_person(parv[1], NULL))) { DYN_LOCAL(char, did_parts, acptr->user->joined); if (MyClient(sptr) && (IsLocOp(sptr) && !MyClient(acptr))) { sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); DYN_FREE(did_parts); return 0; } switch (UHOST_ALLOWED) { case UHALLOW_NEVER: if (MyClient(sptr)) { sendto_one(sptr, err_str(ERR_DISABLED), me.name, sptr->name, "CHGIDENT", "This command is disabled on this server"); DYN_FREE(did_parts); return 0; } break; case UHALLOW_ALWAYS: break; case UHALLOW_NOCHANS: if (IsPerson(acptr) && MyClient(sptr) && acptr->user->joined) { sendnotice(sptr, "*** /ChgIdent can not be used while %s is on a channel", acptr->name); DYN_FREE(did_parts); return 0; } break; case UHALLOW_REJOIN: rejoin_doparts(acptr, did_parts); /* join sent later when the ident has been changed */ break; } if (!IsULine(sptr)) { sendto_snomask(SNO_EYES, "%s changed the virtual ident of %s (%s@%s) to be %s", sptr->name, acptr->name, acptr->user->username, GetHost(acptr), parv[2]); /* Logging ability added by XeRXeS */ ircd_log(LOG_CHGCMDS, "CHGIDENT: %s changed the virtual ident of %s (%s@%s) to be %s", sptr->name, acptr->name, acptr->user->username, GetHost(acptr), parv[2]); } sendto_serv_butone_token(cptr, sptr->name, MSG_CHGIDENT, TOK_CHGIDENT, "%s %s", acptr->name, parv[2]); ircsprintf(acptr->user->username, "%s", parv[2]); if (UHOST_ALLOWED == UHALLOW_REJOIN) rejoin_dojoinandmode(acptr, did_parts); DYN_FREE(did_parts); 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_connect - CONNECT command handler * * Added by Jto 11 Feb 1989 * * m_connect * parv[0] = sender prefix * parv[1] = servername * parv[2] = port number * parv[3] = remote server */ int m_connect(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { int port; int tmpport; struct ConfItem* aconf; struct Client* acptr; if (!IsPrivileged(sptr)) { sendto_one(sptr, form_str(ERR_NOPRIVILEGES), me.name, parv[0]); return -1; } if (IsLocOp(sptr) && parc > 3) { /* * Only allow LocOps to make local CONNECTS --SRB */ return 0; } if (MyConnect(sptr) && !IsOperRemote(sptr) && parc > 3) { sendto_one(sptr,":%s NOTICE %s :You have no R flag", me.name, parv[0]); return 0; } if (hunt_server(cptr, sptr, ":%s CONNECT %s %s :%s", 3, parc, parv) != HUNTED_ISME) return 0; if (parc < 2 || *parv[1] == '\0') { sendto_one(sptr, form_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "CONNECT"); return -1; } if ((acptr = find_server(parv[1]))) { sendto_one(sptr, ":%s NOTICE %s :Connect: Server %s %s %s.", me.name, parv[0], parv[1], "already exists from", acptr->from->name); return 0; } /* * try to find the name, then host, if both fail notify ops and bail */ if (!(aconf = find_conf_by_name(parv[1], CONF_CONNECT_SERVER))) { #ifndef HIDE_SERVERS_IPS if (!(aconf = find_conf_by_host(parv[1], CONF_CONNECT_SERVER))) { #endif sendto_one(sptr, "NOTICE %s :Connect: Host %s not listed in ircd.conf", parv[0], parv[1]); return 0; #ifndef HIDE_SERVERS_IPS } #endif } assert(0 != aconf); /* * Get port number from user, if given. If not specified, * use the default form configuration structure. If missing * from there, then use the precompiled default. */ tmpport = port = aconf->port; if (parc > 2 && !EmptyString(parv[2])) { #ifdef NEG_PORT if ((port = atoi(parv[2])) < 0) #else if ((port = atoi(parv[2])) <= 0) #endif { sendto_one(sptr, "NOTICE %s :Connect: Illegal port number", parv[0]); return 0; } } #ifdef NEG_PORT else if (port < 0 && (port = PORTNUM) <= 0) #else else if (port <= 0 && (port = PORTNUM) <= 0) #endif { sendto_one(sptr, ":%s NOTICE %s :Connect: missing port number", me.name, parv[0]); return 0; } #ifdef NEG_PORT if (port == 0) port = tmpport; /* From conf */ if (port == 0) port = PORTNUM; /* Default if there wasn't one set in conf */ #endif /* * Notify all operators about remote connect requests */ if (!IsAnOper(cptr)) { sendto_ops_butone(NULL, &me, ":%s WALLOPS :Remote CONNECT %s %s from %s", me.name, parv[1], parv[2] ? parv[2] : "", get_client_name(sptr, FALSE)); irclog(L_TRACE, "CONNECT From %s : %s %s", parv[0], parv[1], parv[2] ? parv[2] : ""); } aconf->port = port; /* * at this point we should be calling connect_server with a valid * C:line and a valid port in the C:line */ if (connect_server(aconf, sptr, 0)) #if (defined SERVERHIDE) || (defined HIDE_SERVERS_IPS) sendto_one(sptr, ":%s NOTICE %s :*** Connecting to %s[%s].%d", me.name, parv[0], "255.255.255.255", aconf->name, aconf->port); else sendto_one(sptr, ":%s NOTICE %s :*** Couldn't connect to %s.%d", me.name, parv[0], "255.255.255.255",aconf->port); #else sendto_one(sptr, ":%s NOTICE %s :*** Connecting to %s[%s].%d", me.name, parv[0], aconf->host, aconf->name, aconf->port); else