/* * 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 OPMODE message from a server connection. * * \a parv has the same elements as for ms_mode(). * * 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_opmode(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Channel *chptr = 0; struct ModeBuf mbuf; if (parc < 3) return need_more_params(sptr, "OPMODE"); if (IsLocalChannel(parv[1])) return 0; if ('#' != *parv[1] || !(chptr = FindChannel(parv[1]))) return send_reply(sptr, ERR_NOSUCHCHANNEL, parv[1]); modebuf_init(&mbuf, sptr, cptr, chptr, (MODEBUF_DEST_CHANNEL | /* Send MODE to channel */ MODEBUF_DEST_SERVER | /* And to server */ MODEBUF_DEST_OPMODE | /* Use OPMODE */ MODEBUF_DEST_HACK4 | /* Generate a HACK(4) notice */ MODEBUF_DEST_LOG)); /* Log the mode changes to OPATH */ mode_parse(&mbuf, cptr, sptr, chptr, parc - 2, parv + 2, (MODE_PARSE_SET | /* Set the modes on the channel */ MODE_PARSE_STRICT | /* Be strict about it */ MODE_PARSE_FORCE), /* And force them to be accepted */ NULL); modebuf_flush(&mbuf); /* flush the modes */ return 0; }
/** Report the value of a log setting. * @param[in] from &Client asking for details. * @param[in] fields Array of parameters to get. * @param[in] count Number of fields in \a fields. */ static void feature_log_get(struct Client* from, const char* const* fields, int count) { struct LogTypes *desc; char *value, *subsys; assert(0 != from); /* never called by .conf parser */ if (count < 1) /* return default facility */ send_reply(from, SND_EXPLICIT | RPL_FEATURE, ":Log facility: %s", log_get_default()); else if (count < 2) need_more_params(from, "GET"); else if (!(subsys = log_canon(fields[0]))) { /* no such subsystem */ send_reply(from, ERR_BADLOGSYS, fields[0]); } else if ((desc = feature_log_desc(from, fields[1]))) { if ((value = (*desc->get)(fields[0]))) /* send along value */ send_reply(from, SND_EXPLICIT | RPL_FEATURE, ":Log %s for subsystem %s: %s", desc->type, subsys, (*desc->get)(subsys)); else send_reply(from, SND_EXPLICIT | RPL_FEATURE, ":No log %s is set for subsystem %s", desc->type, subsys); } }
/* * mo_asll - oper message handler */ int mo_asll(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { char *mask; struct Client *acptr; int hits; int i; if (parc < 2) return need_more_params(sptr, "ASLL"); if (parc == 2 && MyUser(sptr)) parv[parc++] = cli_name(&me); if (hunt_server_prio_cmd(sptr, CMD_ASLL, cptr, 1, "%s %C", 2, parc, parv) != HUNTED_ISME) return 0; mask = parv[1]; for (i = hits = 0; i <= HighestFd; i++) { acptr = LocalClientArray[i]; if (!acptr || !IsServer(acptr) || !MyConnect(acptr) || match(mask, cli_name(acptr))) continue; send_asll_reply(&me, sptr, cli_name(acptr), cli_serv(acptr)->asll_rtt, cli_serv(acptr)->asll_to, cli_serv(acptr)->asll_from); hits++; } sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :AsLL for %s: %d local servers matched", sptr, mask, hits); return 0; }
/** 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; }
/* * mr_pass - registration message handler */ int mr_pass(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { char password[BUFSIZE]; int arg, len; assert(0 != cptr); assert(cptr == sptr); assert(!IsRegistered(sptr)); /* Some clients (brokenly) send "PASS x y" rather than "PASS :x y" * when the user enters "x y" as the password. Unsplit arguments to * work around this. */ for (arg = 1, len = 0; arg < parc; ++arg) { ircd_strncpy(password + len, parv[arg], sizeof(password) - len); len += strlen(parv[arg]); password[len++] = ' '; } if (len > 0) --len; password[len] = '\0'; if (EmptyString(password)) return need_more_params(cptr, "PASS"); ircd_strncpy(cli_passwd(cptr), password, PASSWDLEN); return cli_auth(cptr) ? auth_set_password(cli_auth(cptr), password) : 0; }
/* * ms_fakehost - fakehost server message handler * * parv[0] = sender prefix * parv[1] = target user numeric * parv[2] = target user's new fake host */ int ms_fakehost(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Client *target; if (parc < 3) return need_more_params(sptr, "FAKEHOST"); /* Locate our target user; ignore the message if we can't */ if(!(target = findNUser(parv[1]))) return 0; /* Ignore the assignment if it changes nothing */ if (HasFakeHost(target) && ircd_strcmp(cli_user(target)->fakehost, parv[2]) == 0) { return 0; } /* Assign and propagate the fakehost */ SetFakeHost(target); ircd_strncpy(cli_user(target)->fakehost, parv[2], HOSTLEN); hide_hostmask(target); sendcmdto_serv_butone(sptr, CMD_FAKEHOST, cptr, "%C %s", target, cli_user(target)->fakehost); return 0; }
/** Reset a feature to its default values. * @param[in] from Client trying to reset the feature, or NULL. * @param[in] fields Parameters to set, starting with feature name. * @param[in] count Number of fields in \a fields. * @return Zero (or, theoretically, CPTR_KILLED). */ int feature_reset(struct Client* from, const char* const* fields, int count) { int i, change = 0; struct FeatureDesc *feat; assert(0 != from); if (!HasPriv(from, PRIV_SET)) return send_reply(from, ERR_NOPRIVILEGES); if (count < 1) /* check arguments */ need_more_params(from, "RESET"); else if ((feat = feature_desc(from, fields[0]))) { /* get descriptor */ if (from && feat->flags & FEAT_READ) return send_reply(from, ERR_NOFEATURE, fields[0]); switch (feat->flags & FEAT_MASK) { case FEAT_NONE: /* None... */ if (feat->reset && (i = (*feat->reset)(from, fields + 1, count - 1))) { change++; /* feature handler wants a change recorded */ if (i > 0) /* call reset callback and parse mark return */ feat->flags |= FEAT_MARK; else /* i < 0 */ feat->flags &= ~FEAT_MARK; } break; case FEAT_INT: /* Integer... */ case FEAT_BOOL: /* Boolean... */ if (feat->v_int != feat->def_int) change++; /* change will be made */ feat->v_int = feat->def_int; /* set the default */ feat->flags &= ~FEAT_MARK; /* unmark it */ break; case FEAT_STR: /* string! */ if (feat->v_str != feat->def_str) { change++; /* change has been made */ if (feat->v_str) MyFree(feat->v_str); /* free old value */ } feat->v_str = feat->def_str; /* set it to default */ feat->flags &= ~FEAT_MARK; /* unmark it */ break; } if (change && feat->notify) /* call change notify function */ (*feat->notify)(); if (from) return feature_get(from, fields, count); } return 0; }
/** Handle a JOIN message from a client connection. * 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_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { struct JoinBuf join; struct JoinBuf create; char *p = 0; char *chanlist; char *name; char *keys; if (parc < 2 || *parv[1] == '\0') return need_more_params(sptr, "JOIN"); if (!IsAnOper(sptr) && IsRestrictJoin(sptr)) { send_reply(sptr, ERR_BANNEDFROMCHAN, parv[1]); return 0; } joinbuf_init(&join, sptr, cptr, JOINBUF_TYPE_JOIN, 0, 0); joinbuf_init(&create, sptr, cptr, JOINBUF_TYPE_CREATE, 0, TStime()); chanlist = last0(cptr, sptr, parv[1]); /* find last "JOIN 0" */ keys = parv[2]; /* remember where keys are */ for (name = ircd_strtok(&p, chanlist, ","); name; name = ircd_strtok(&p, 0, ",")) { char *key = 0; /* If we have any more keys, take the first for this channel. */ if (!BadPtr(keys) && (keys = strchr(key = keys, ','))) *keys++ = '\0'; /* Empty keys are the same as no keys. */ if (key && !key[0]) key = 0; if (!IsChannelName(name) || !strIsIrcCh(name)) { /* bad channel name */ send_reply(sptr, ERR_NOSUCHCHANNEL, name); continue; } if (cli_user(sptr)->joined >= get_client_maxchans(sptr) && !HasPriv(sptr, PRIV_CHAN_LIMIT)) { send_reply(sptr, ERR_TOOMANYCHANNELS, name); break; /* no point processing the other channels */ } do_join(cptr, sptr, &join, &create, name, key, 0); } joinbuf_flush(&join); /* must be first, if there's a JOIN 0 */ joinbuf_flush(&create); return 0; }
int ms_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { struct Channel *chptr = 0; struct ModeBuf mbuf; struct Membership *member = 0; if (parc < 3) return need_more_params(sptr, "MODE"); if (IsLocalChannel(parv[1])) return 0; if (!(chptr = FindChannel(parv[1]))) return set_user_mode(cptr, sptr, parc, parv); ClrFlag(sptr, FLAG_TS8); if (IsServer(sptr)) { if (cli_uworld(sptr)) modebuf_init(&mbuf, sptr, cptr, chptr, (MODEBUF_DEST_CHANNEL | /* Send mode to clients */ MODEBUF_DEST_SERVER | /* Send mode to servers */ MODEBUF_DEST_HACK4)); /* Send a HACK(4) message */ else modebuf_init(&mbuf, sptr, cptr, chptr, (MODEBUF_DEST_CHANNEL | /* Send mode to clients */ MODEBUF_DEST_SERVER | /* Send mode to servers */ MODEBUF_DEST_HACK3)); /* Send a HACK(3) message */ mode_parse(&mbuf, cptr, sptr, chptr, parc - 2, parv + 2, (MODE_PARSE_SET | /* Set the mode */ MODE_PARSE_STRICT | /* Interpret it strictly */ MODE_PARSE_FORCE), NULL); /* And force it to be accepted */ } else { if (!IsChannelService(sptr) && (!(member = find_member_link(chptr, sptr)) || (!IsChanOp(member) && !IsHalfOp(member)))) { modebuf_init(&mbuf, sptr, cptr, chptr, (MODEBUF_DEST_SERVER | /* Send mode to server */ MODEBUF_DEST_HACK2 | /* Send a HACK(2) message */ MODEBUF_DEST_DEOP | /* Deop the source */ MODEBUF_DEST_BOUNCE)); /* And bounce the MODE */ mode_parse(&mbuf, cptr, sptr, chptr, parc - 2, parv + 2, (MODE_PARSE_STRICT | /* Interpret it strictly */ MODE_PARSE_BOUNCE), member); /* And bounce the MODE */ } else { modebuf_init(&mbuf, sptr, cptr, chptr, (MODEBUF_DEST_CHANNEL | /* Send mode to clients */ MODEBUF_DEST_SERVER)); /* Send mode to servers */ mode_parse(&mbuf, cptr, sptr, chptr, parc - 2, parv + 2, (MODE_PARSE_SET | /* Set the mode */ MODE_PARSE_STRICT | /* Interpret it strictly */ MODE_PARSE_FORCE), member); /* And force it to be accepted */ } } return modebuf_flush(&mbuf); }
/* * ms_desynch - server message handler * * Writes to all +g users; for sending wall type debugging/anti-hack info. * Added 23 Apr 1998 --Run * * parv[0] - sender prefix * parv[parc-1] - message text */ int ms_desynch(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { if (parc >= 2) sendwallto_group_butone(sptr, WALL_DESYNCH, cptr, "%s", parv[parc - 1]); else need_more_params(sptr,"DESYNCH"); return 0; }
/* * m_cprivmsg - generic message handler * * parv[0] = sender prefix * parv[1] = nick * parv[2] = #channel * parv[3] = Private message text */ int m_cprivmsg(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { assert(0 != cptr); assert(cptr == sptr); if (parc < 4 || EmptyString(parv[3])) return need_more_params(sptr, "CPRIVMSG"); return whisper(sptr, parv[1], parv[2], parv[3], 0); }
/* * m_cnotice - generic message handler * * parv[0] = sender prefix * parv[1] = nick * parv[2] = #channel * parv[3] = Private message text */ int m_cnotice(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { assert(0 != cptr); assert(cptr == sptr); if (parc < 4 || EmptyString(parv[3])) return need_more_params(sptr, "CNOTICE"); return whisper(sptr, parv[1], parv[2], parv[3], 1); }
/* * m_userip - generic message handler */ int m_userip(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { assert(0 != cptr); assert(cptr == sptr); if (parc < 2) return need_more_params(sptr, "USERIP"); send_user_info(sptr, parv[1], RPL_USERIP, userip_formatter); return 0; }
/* * ms_kill - server message handler * * NOTE: IsServer(cptr) == true; * * parv[0] = sender prefix * parv[1] = kill victim * parv[parc-1] = kill path */ int ms_kill(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Client* victim; char* path; char* msg; assert(0 != cptr); assert(0 != sptr); assert(IsServer(cptr)); /* * XXX - a server sending less than 3 params could really desync * things */ if (parc < 3) { protocol_violation(sptr,"Too few arguments for KILL"); return need_more_params(sptr, "KILL"); } path = parv[parc - 1]; /* Either defined or NULL (parc >= 3) */ if (!(msg = strchr(path, ' '))) /* Extract out the message */ msg = "(No reason supplied)"; else *(msg++) = '\0'; /* Remove first character (space) and terminate path */ if (!(victim = findNUser(parv[1]))) { if (IsUser(sptr)) sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :KILL target disconnected " "before I got him :(", sptr); return 0; } /* * We *can* have crossed a NICK with this numeric... --Run * * Note the following situation: * KILL SAA --> X * <-- S NICK ... SAA | <-- SAA QUIT <-- S NICK ... SAA <-- SQUIT S * Where the KILL reaches point X before the QUIT does. * This would then *still* cause an orphan because the KILL doesn't reach S * (because of the SQUIT), the QUIT is ignored (because of the KILL) * and the second NICK ... SAA causes an orphan on the server at the * right (which then isn't removed when the SQUIT arrives). * Therefore we still need to detect numeric nick collisions too. * * Bounce the kill back to the originator, if the client can't be found * by the next hop (short lag) the bounce won't propagate further. */ if (MyConnect(victim)) { sendcmdto_one(&me, CMD_KILL, cptr, "%C :%s (Ghost 5 Numeric Collided)", victim, path); } return do_kill(cptr, sptr, victim, cli_name(cptr), path, msg); }
/* * ms_smo * * parv[1] = mask * parv[2] = msg */ int ms_smo(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { char *message = parc > 2 ? parv[2] : 0; const char *mask = parc > 1 ? parv[1] : "o"; /* default to opers only if not specified */ if (EmptyString(message) || !mask) return need_more_params(sptr, "SMO"); sendto_allusers_butserv(cptr, sptr, mask, "%s", message); return 0; }
/** Handle a SILENCE command from a server. * See @ref m_functions for general discussion of parameters. * * \a parv[1] may be one of the following: * \li "*" to indicate a broadcast update (removing a SILENCE) * \li A client numnick that should be specifically SILENCEd. * * \a parv[2] is a comma-separated list of silence updates. * * @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_silence(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { if (IsServer(sptr)) return protocol_violation(sptr, "Server trying to silence a user"); if (parc < 3 || EmptyString(parv[2])) return need_more_params(sptr, "SILENCE"); /* Figure out which silences can be forwarded. */ forward_silences(sptr, parv[2], findNUser(parv[1])); return 0; (void)cptr; }
/** Handle a local user's attempt to get or set a channel topic. * * \a parv has the following elements: * \li \a parv[1] is the channel name * \li \a parv[\a parc - 1] is the topic (if \a parc > 2) * * 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_topic(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Channel *chptr; char *topic = 0, *name, *p = 0; if (parc < 2) return need_more_params(sptr, "TOPIC"); if (parc > 2) topic = parv[parc - 1]; for (; (name = ircd_strtok(&p, parv[1], ",")); parv[1] = 0) { chptr = 0; /* Does the channel exist */ if (!IsChannelName(name) || !(chptr = FindChannel(name))) { send_reply(sptr,ERR_NOSUCHCHANNEL,name); continue; } /* Trying to check a topic outside a secret channel */ if ((topic || SecretChannel(chptr)) && !find_channel_member(sptr, chptr)) { send_reply(sptr, ERR_NOTONCHANNEL, chptr->chname); continue; } /* only asking for topic */ if (!topic) { if (chptr->topic[0] == '\0') send_reply(sptr, RPL_NOTOPIC, chptr->chname); else { send_reply(sptr, RPL_TOPIC, chptr->chname, chptr->topic); send_reply(sptr, RPL_TOPICWHOTIME, chptr->chname, chptr->topic_nick, chptr->topic_time); } } #if defined(DDB) || defined(SERVICES) else if ((chptr->mode.mode & MODE_TOPICLIMIT) && !(is_chan_owner(sptr, chptr) || is_chan_op(sptr, chptr))) #else else if ((chptr->mode.mode & MODE_TOPICLIMIT) && !is_chan_op(sptr, chptr)) #endif send_reply(sptr, ERR_CHANOPRIVSNEEDED, chptr->chname); else if (!client_can_send_to_channel(sptr, chptr, 1)) send_reply(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname); else do_settopic(sptr,cptr,chptr,topic,0); } return 0; }
/** Handle a WALLOPS message from an operator. * * \a parv has the following elements: * \li \a parv[\a parc - 1] is the message to send * * 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_wallops(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { char *message; message = parc > 1 ? parv[parc - 1] : 0; if (EmptyString(message)) return need_more_params(sptr, "WALLOPS"); sendwallto_group(sptr, WALL_WALLOPS, 0, "%s", message); return 0; }
/* * mo_kill - oper message handler * * NOTE: IsPrivileged(sptr), IsAnOper(sptr) == true * IsServer(cptr), IsServer(sptr) == false * * parv[0] = sender prefix * parv[1] = kill victim * parv[parc-1] = kill path */ int mo_kill(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Client* victim; char* user; char msg[TOPICLEN + 3]; /* (, ), and \0 */ assert(0 != cptr); assert(0 != sptr); /* * oper connection to this server, cptr is always sptr */ assert(cptr == sptr); assert(IsAnOper(sptr)); if (parc < 3 || EmptyString(parv[parc - 1])) return need_more_params(sptr, "KILL"); user = parv[1]; ircd_snprintf(0, msg, sizeof(msg), "(%.*s)", TOPICLEN, parv[parc - 1]); if (!(victim = FindClient(user))) { /* * If the user has recently changed nick, we automaticly * rewrite the KILL for this new nickname--this keeps * servers in synch when nick change and kill collide */ if (!(victim = get_history(user, (long)15))) return send_reply(sptr, ERR_NOSUCHNICK, user); sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Changed KILL %s into %s", sptr, user, cli_name(victim)); } if (!HasPriv(sptr, MyConnect(victim) ? PRIV_LOCAL_KILL : PRIV_KILL)) return send_reply(sptr, ERR_NOPRIVILEGES); if (IsServer(victim) || IsMe(victim)) { return send_reply(sptr, ERR_CANTKILLSERVER); } /* * if the user is +k, prevent a kill from local user */ if (IsChannelService(victim)) return send_reply(sptr, ERR_ISCHANSERVICE, "KILL", cli_name(victim)); if (!MyConnect(victim) && !HasPriv(sptr, PRIV_KILL)) { sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Nick %s isnt on your server", sptr, cli_name(victim)); return 0; } return do_kill(cptr, sptr, victim, cli_user(sptr)->host, cli_name(sptr), msg); }
/* * m_part - generic message handler * * parv[0] = sender prefix * parv[1] = channel * parv[parc - 1] = comment */ int m_part(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Channel *chptr; struct Membership *member; struct JoinBuf parts; unsigned int flags = 0; char *p = 0; char *name; ClrFlag(sptr, FLAG_TS8); /* check number of arguments */ if (parc < 2 || parv[1][0] == '\0') return need_more_params(sptr, "PART"); /* init join/part buffer */ joinbuf_init(&parts, sptr, cptr, JOINBUF_TYPE_PART, (parc > 2 && !EmptyString(parv[parc - 1])) ? parv[parc - 1] : 0, 0); /* scan through channel list */ for (name = ircd_strtok(&p, parv[1], ","); name; name = ircd_strtok(&p, 0, ",")) { chptr = get_channel(sptr, name, CGT_NO_CREATE); /* look up channel */ if (!chptr) { /* complain if there isn't such a channel */ send_reply(sptr, ERR_NOSUCHCHANNEL, name); continue; } if (!(member = find_member_link(chptr, sptr))) { /* complain if not on */ send_reply(sptr, ERR_NOTONCHANNEL, chptr->chname); continue; } assert(!IsZombie(member)); /* Local users should never zombie */ if (!member_can_send_to_channel(member, 0)) { flags |= CHFL_BANNED; /* Remote clients don't want to see a comment either. */ parts.jb_comment = 0; } if (IsDelayedJoin(member)) flags |= CHFL_DELAYED; joinbuf_join(&parts, chptr, flags); /* part client from channel */ } return joinbuf_flush(&parts); /* flush channel parts */ }
/* * mo_wallusers - oper message handler */ int mo_wallusers(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { char *message; message = parc > 1 ? parv[1] : 0; if (EmptyString(message)) return need_more_params(sptr, "WALLUSERS"); sendwallto_group_butone(sptr, WALL_WALLUSERS, 0, "%s", message); return 0; }
/* * ms_jupe - server message handler * * parv[0] = Send prefix * * From server: * * parv[1] = Target: server numeric or * * parv[2] = (+|-)<server name> * parv[3] = Expiration offset * parv[4] = Last modification time * parv[5] = Comment * */ int ms_jupe(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Client *acptr = 0; struct Jupe *ajupe; unsigned int flags = 0; time_t expire_off, lastmod; char *server = parv[2], *target = parv[1], *reason = parv[5]; if (parc < 6) return need_more_params(sptr, "JUPE"); if (!(target[0] == '*' && target[1] == '\0')) { if (!(acptr = FindNServer(target))) return 0; /* no such server */ if (!IsMe(acptr)) { /* manually propagate, since we don't set it */ sendcmdto_one(sptr, CMD_JUPE, acptr, "%s %s %s %s :%s", target, server, parv[3], parv[4], reason); return 0; } flags |= JUPE_LOCAL; } if (*server == '-') server++; else if (*server == '+') { flags |= JUPE_ACTIVE; server++; } expire_off = atoi(parv[3]); lastmod = atoi(parv[4]); ajupe = jupe_find(server); if (ajupe) { if (JupeIsLocal(ajupe) && !(flags & JUPE_LOCAL)) /* global over local */ jupe_free(ajupe); else if (JupeLastMod(ajupe) < lastmod) { /* new modification */ if (flags & JUPE_ACTIVE) return jupe_activate(cptr, sptr, ajupe, lastmod, flags); else return jupe_deactivate(cptr, sptr, ajupe, lastmod, flags); } else if (JupeLastMod(ajupe) == lastmod || IsBurstOrBurstAck(cptr)) return 0; else return jupe_resend(cptr, ajupe); /* other server desynched WRT jupes */ } return jupe_add(cptr, sptr, server, reason, expire_off, lastmod, flags); }
/* * m_sethost - generic message handler * * mimic old lain syntax: * * (Oper) /SETHOST ident host.cc [quit-message] * (User) /SETHOST host.cc password * (Both) /SETHOST undo * * check for undo, prepend parv w. <nick> -h or +h */ int m_sethost(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { char hostmask[512]; struct Flags setflags; /* Back up the flags first */ setflags = cli_flags(sptr); if (parc < 2) return need_more_params(sptr, "SETHOST"); if (0 == ircd_strcmp("undo", parv[1])) { set_hostmask(sptr, sptr, NULL, NULL); } else { if (parc<3) return need_more_params(sptr, "SETHOST"); if (IsAnOper(sptr)) { ircd_snprintf(0, hostmask, USERLEN + HOSTLEN + 1, "%s@%s", parv[1], parv[2]); if (!is_hostmask(hostmask)) { send_reply(sptr, ERR_BADHOSTMASK, hostmask); return 0; } if (set_hostmask(sptr, sptr, hostmask, NULL)) FlagClr(&setflags, FLAG_SETHOST); } else { if (!is_hostmask(parv[1])) { send_reply(sptr, ERR_BADHOSTMASK, parv[1]); return 0; } if (set_hostmask(sptr, sptr, parv[1], parv[2])) FlagClr(&setflags, FLAG_SETHOST); } } send_umode_out(cptr, sptr, &setflags, 0); return 0; }
/** Handle an OPMODE message from an operator. * * \a parv has the same elements as for m_mode(). * * 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_opmode(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Channel *chptr = 0; struct ModeBuf mbuf; char *chname; const char *qreason; int force = 0; if (!feature_bool(FEAT_CONFIG_OPERCMDS)) return send_reply(sptr, ERR_DISABLED, "OPMODE"); if (parc < 3) return need_more_params(sptr, "OPMODE"); chname = parv[1]; if (*chname == '!') { chname++; if (!HasPriv(sptr, IsLocalChannel(chname) ? PRIV_FORCE_LOCAL_OPMODE : PRIV_FORCE_OPMODE)) return send_reply(sptr, ERR_NOPRIVILEGES); force = 1; } if (!HasPriv(sptr, IsLocalChannel(chname) ? PRIV_LOCAL_OPMODE : PRIV_OPMODE)) return send_reply(sptr, ERR_NOPRIVILEGES); if (!IsChannelName(chname) || !(chptr = FindChannel(chname))) return send_reply(sptr, ERR_NOSUCHCHANNEL, chname); if (!force && (qreason = find_quarantine(chptr->chname))) return send_reply(sptr, ERR_QUARANTINED, chptr->chname, qreason); modebuf_init(&mbuf, sptr, cptr, chptr, (MODEBUF_DEST_CHANNEL | /* Send MODE to channel */ MODEBUF_DEST_SERVER | /* And to server */ MODEBUF_DEST_OPMODE | /* Use OPMODE */ MODEBUF_DEST_HACK4 | /* Generate a HACK(4) notice */ MODEBUF_DEST_LOG)); /* Log the mode changes to OPATH */ mode_parse(&mbuf, cptr, sptr, chptr, parc - 2, parv + 2, (MODE_PARSE_SET | /* set the modes on the channel */ MODE_PARSE_FORCE), /* And force them to be accepted */ NULL); modebuf_flush(&mbuf); /* flush the modes */ return 0; }
int ms_set(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Client *acptr; if (parc < 4) return need_more_params(sptr, "SET"); if (!(acptr = FindNServer(parv[1]))) return 0; if (!IsMe(acptr)) { sendcmdto_serv_butone(sptr, CMD_SET, cptr, "%C %s :%s", acptr, parv[2], parv[3]); return 0; } return feature_set(sptr, (const char* const*)parv + 2, parc - 2); }
/** Gets the value of a specific feature and reports it to the user. * @param[in] from Client trying to get the feature. * @param[in] fields Parameters to set, starting with feature name. * @param[in] count Number of fields in \a fields. * @return Zero (or, theoretically, CPTR_KILLED). */ int feature_get(struct Client* from, const char* const* fields, int count) { struct FeatureDesc *feat; assert(0 != from); if (count < 1) /* check parameters */ need_more_params(from, "GET"); else if ((feat = feature_desc(from, fields[0]))) { if ((feat->flags & FEAT_NODISP) || (feat->flags & FEAT_MYOPER && !MyOper(from)) || (feat->flags & FEAT_OPER && !IsAnOper(from))) /* check privs */ return send_reply(from, ERR_NOPRIVILEGES); switch (feat_type(feat)) { case FEAT_NONE: /* none, call the callback... */ if (feat->get) /* if there's a callback, use it */ (*feat->get)(from, fields + 1, count - 1); break; case FEAT_INT: /* integer, report integer value */ send_reply(from, SND_EXPLICIT | RPL_FEATURE, ":Integer value of %s: %d", feat->type, feat->v_int); break; case FEAT_UINT: /* unsigned integer, report its value */ send_reply(from, SND_EXPLICIT | RPL_FEATURE, ":Unsigned value of %s: %u", feat->type, feat->v_int); break; case FEAT_BOOL: /* boolean, report boolean value */ send_reply(from, SND_EXPLICIT | RPL_FEATURE, ":Boolean value of %s: %s", feat->type, feat->v_int ? "TRUE" : "FALSE"); break; case FEAT_STR: /* string, report string value */ if (feat->v_str) /* deal with null case */ send_reply(from, SND_EXPLICIT | RPL_FEATURE, ":String value of %s: %s", feat->type, feat->v_str); else send_reply(from, SND_EXPLICIT | RPL_FEATURE, ":String value for %s not set", feat->type); break; } } return 0; }
/** Seed the PRNG with a string. * @param[in] from Client setting the seed (may be NULL). * @param[in] fields Input arguments (fields[0] is used). * @param[in] count Number of input arguments. * @return Non-zero on success, zero on error. */ int random_seed_set(struct Client* from, const char* const* fields, int count) { if (count < 1) { if (from) /* send an error */ return need_more_params(from, "SET"); else { log_write(LS_CONFIG, L_ERROR, 0, "Not enough fields in F line"); return 0; } } random_add_entropy(fields[0], strlen(fields[0])); return 1; }
/* * ms_wallusers - server message handler */ int ms_wallusers(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { char *message; message = parc > 1 ? parv[1] : 0; /* * XXX - PROTOCOL ERROR (shouldn't happen) */ if (EmptyString(message)) return need_more_params(sptr, "WALLUSERS"); sendwallto_group_butone(sptr, WALL_WALLUSERS, cptr, "%s", message); return 0; }
/** Handle a PASS message from an unregistered connection. * * \a parv[1..\a parc-1] is a possibly broken-up password. Since some * clients do not prefix the password with ':', this functions stitches * the elements back together before using it. * * 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 mr_pass(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { char password[BUFSIZE]; int arg, len; assert(0 != cptr); assert(cptr == sptr); assert(!IsRegistered(sptr)); /* Some clients (brokenly) send "PASS x y" rather than "PASS :x y" * when the user enters "x y" as the password. Unsplit arguments to * work around this. */ for (arg = 1, len = 0; arg < parc; ++arg) { ircd_strncpy(password + len, parv[arg], sizeof(password) - len); len += strlen(parv[arg]); password[len++] = ' '; } if (len > 0) --len; password[len] = '\0'; if (EmptyString(password)) return need_more_params(cptr, "PASS"); #if defined(DDB) if (IsUserPort(cptr)) { /* * PASS :server_pass[:ddb_pass] * PASS :ddb_pass */ char *ddb_pwd; ddb_pwd = strchr(password, ':'); if (ddb_pwd) *ddb_pwd++ = '\0'; else ddb_pwd = password; ircd_strncpy(cli_ddb_passwd(cptr), ddb_pwd, DDBPWDLEN); } #endif ircd_strncpy(cli_passwd(cptr), password, PASSWDLEN); return cli_auth(cptr) ? auth_set_password(cli_auth(cptr), password) : 0; }