/* * 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); }
/* * 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); }
/** 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; }
/* * 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) */ int mo_rehash(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { int flag = 0; if (!HasPriv(sptr, PRIV_REHASH)) return send_reply(sptr, ERR_NOPRIVILEGES); if (parc > 1) { /* special processing */ 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] == 'q') flag = 2; } 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); }
static bool HasPriv(const AccessGroup &ag, const ChanAccess *access, const Anope::string &name) { EventReturn MOD_RESULT; FOREACH_RESULT(OnCheckPriv, MOD_RESULT, (access, name)); if (MOD_RESULT == EVENT_ALLOW || access->HasPriv(name)) { typedef std::multimap<const ChanAccess *, const ChanAccess *> path; std::pair<path::const_iterator, path::const_iterator> it = ag.path.second.equal_range(access); if (it.first != it.second) /* check all of the paths for this entry */ for (; it.first != it.second; ++it.first) { const ChanAccess *a = it.first->second; /* if only one path fully matches then we are ok */ if (HasPriv(ag, a, name)) return true; } else /* entry is the end of a chain, all entries match, ok */ return true; } /* entry does not match or none of the chains fully match */ return false; }
/** 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; }
static void userhost_formatter(struct Client* cptr, struct Client *sptr, struct MsgBuf* mb) { assert(IsUser(cptr)); msgq_append(0, mb, "%s%s=%c%s@%s", cli_name(cptr), HasPriv(cptr, PRIV_DISPLAY) ? "*" : "", cli_user(cptr)->away ? '-' : '+', cli_user(cptr)->username, (sptr == cptr) ? get_realhost(cptr) : get_virtualhost(cptr)); }
/** 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; }
/* * mo_restart - oper message handler */ int mo_restart(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { if (!HasPriv(sptr, PRIV_RESTART)) return send_reply(sptr, ERR_NOPRIVILEGES); log_write(LS_SYSTEM, L_NOTICE, 0, "Server RESTART by %#C", sptr); server_restart("received RESTART"); return 0; }
/* * mo_clearmode - oper message handler * * parv[0] = Send prefix * parv[1] = Channel name * parv[2] = Control string */ int mo_clearmode(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Channel *chptr; char *control = "ovpsmikbl"; /* default control string */ const char *chname, *qreason; int force = 0; if (!feature_bool(FEAT_CONFIG_OPERCMDS)) return send_reply(sptr, ERR_DISABLED, "CLEARMODE"); if (parc < 2) return need_more_params(sptr, "CLEARMODE"); if (parc > 2) control = parv[2]; 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 (('#' != *chname && '&' != *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); return do_clearmode(cptr, sptr, chptr, control); }
void do_give(dbref player, dbref cause, int key, char *who, char *amnt) { dbref recipient; /* check recipient */ init_match(player, who, TYPE_PLAYER); match_neighbor(); match_possession(); match_me(); if (Privilaged(player) || HasPriv(player,NOTHING,POWER_LONG_FINGERS,POWER3,NOTHING)) { match_player(); match_absolute(); } recipient = match_result(); switch (recipient) { case NOTHING: notify(player, "Give to whom?"); return; case AMBIGUOUS: notify(player, "I don't know who you mean!"); return; } if (DePriv(player,recipient,DP_GIVE,POWER7,POWER_LEVEL_SPC)) { notify(player, "Permission denied."); return; } if (DePriv(recipient,player,DP_RECEIVE,POWER7,POWER_LEVEL_SPC)) { notify(player, "Permission denied."); return; } if (is_number(amnt)) { give_money(player, recipient, key, atoi(amnt)); } else if(Guest(recipient)) { notify(player, "Guest really doesn't need money or anything."); return; } else { if ( Typeof(player) != TYPE_ROOM ) give_thing(player, recipient, key, amnt); else notify(player, "Command incompatible with invoker type."); } }
/** Report privileges of \a client to \a to. * @param[in] to Client requesting privilege list. * @param[in] client Client whos privileges should be listed. * @return Zero. */ int client_report_privs(struct Client *to, struct Client *client) { struct MsgBuf *mb; int found1 = 0; int i; mb = msgq_make(to, rpl_str(RPL_PRIVS), cli_name(&me), cli_name(to), cli_name(client)); for (i = 0; privtab[i].name; i++) if (HasPriv(client, privtab[i].priv)) msgq_append(0, mb, "%s%s", found1++ ? " " : "", privtab[i].name); send_buffer(to, mb, 0); /* send response */ msgq_clean(mb); return 0; }
/** Handle a RESTART message from an operator connection. * * \a parv has the following elements: * \li \a parv[1] is either "cancel" or a time interval in seconds * \li \a parv[\a parc - 1] is the reason * * Either the time interval or the reason (or both) may be omitted. * * 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_restart(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { time_t when = 0; const char *reason = 0; if (!HasPriv(sptr, PRIV_RESTART)) return send_reply(sptr, ERR_NOPRIVILEGES); if (parc > 1 && !ircd_strcmp(parv[1], "cancel")) { exit_cancel(sptr); /* cancel a pending exit */ return 0; } else if (parc > 2) { /* have both time and reason */ when = atoi(parv[1]); reason = parv[parc - 1]; } else if (parc > 1 && !(when = atoi(parv[1]))) reason = parv[parc - 1]; /* now, let's schedule the exit */ exit_schedule(1, when, sptr, reason); return 0; }
/* * m_fakehost - fakehost user message handler * * parv[0] = sender prefix * parv[1] = new fake host */ int m_fakehost(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { if (!HasPriv(sptr, PRIV_SET_FAKEHOST)) return send_reply(sptr, ERR_NOPRIVILEGES); if (parc < 2) return need_more_params(sptr, "FAKEHOST"); /* Ignore the assignment if it changes nothing */ if (HasFakeHost(cptr) && ircd_strcmp(cli_user(cptr)->fakehost, parv[1]) == 0) { return 0; } /* Assign and propagate the fakehost */ SetFakeHost(cptr); ircd_strncpy(cli_user(cptr)->fakehost, parv[1], HOSTLEN); hide_hostmask(cptr); sendcmdto_serv_butone(sptr, CMD_FAKEHOST, cptr, "%C %s", sptr, cli_user(cptr)->fakehost); 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 Channel *chptr; struct JoinBuf join; struct JoinBuf create; struct Gline *gline; char *p = 0; char *chanlist; char *name; char *keys; if (parc < 2 || *parv[1] == '\0') return need_more_params(sptr, "JOIN"); 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 >= feature_int(FEAT_MAXCHANNELSPERUSER) && !HasPriv(sptr, PRIV_CHAN_LIMIT)) { send_reply(sptr, ERR_TOOMANYCHANNELS, name); break; /* no point processing the other channels */ } /* BADCHANed channel */ if ((gline = gline_find(name, GLINE_BADCHAN | GLINE_EXACT)) && GlineIsActive(gline) && !IsAnOper(sptr)) { send_reply(sptr, ERR_BANNEDFROMCHAN, name); continue; } if (!(chptr = FindChannel(name))) { if (((name[0] == '&') && !feature_bool(FEAT_LOCAL_CHANNELS)) || strlen(name) > IRCD_MIN(CHANNELLEN, feature_int(FEAT_CHANNELLEN))) { send_reply(sptr, ERR_NOSUCHCHANNEL, name); continue; } if (!(chptr = get_channel(sptr, name, CGT_CREATE))) continue; /* Try to add the new channel as a recent target for the user. */ if (check_target_limit(sptr, chptr, chptr->chname, 0)) { chptr->members = 0; destruct_channel(chptr); continue; } joinbuf_join(&create, chptr, CHFL_CHANOP | CHFL_CHANNEL_MANAGER); } else if (find_member_link(chptr, sptr)) { continue; /* already on channel */ } else if (check_target_limit(sptr, chptr, chptr->chname, 0)) { continue; } else { int flags = CHFL_DEOPPED; int err = 0; /* Check Apass/Upass -- since we only ever look at a single * "key" per channel now, this hampers brute force attacks. */ if (key && !strcmp(key, chptr->mode.apass)) flags = CHFL_CHANOP | CHFL_CHANNEL_MANAGER; else if (key && !strcmp(key, chptr->mode.upass)) flags = CHFL_CHANOP; else if (chptr->users == 0 && !chptr->mode.apass[0]) { /* Joining a zombie channel (zannel): give ops and increment TS. */ flags = CHFL_CHANOP; chptr->creationtime++; } else if (IsInvited(sptr, chptr)) { /* Invites bypass these other checks. */ } else if (chptr->mode.mode & MODE_INVITEONLY) err = ERR_INVITEONLYCHAN; else if (chptr->mode.limit && (chptr->users >= chptr->mode.limit)) err = ERR_CHANNELISFULL; else if ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(sptr)) err = ERR_NEEDREGGEDNICK; else if (find_ban(sptr, chptr->banlist)) err = ERR_BANNEDFROMCHAN; else if (*chptr->mode.key && (!key || strcmp(key, chptr->mode.key))) err = ERR_BADCHANNELKEY; /* An oper with WALK_LCHAN privilege can join a local channel * he otherwise could not join by using "OVERRIDE" as the key. * This will generate a HACK(4) notice, but fails if the oper * could normally join the channel. */ if (IsLocalChannel(chptr->chname) && HasPriv(sptr, PRIV_WALK_LCHAN) && !(flags & CHFL_CHANOP) && key && !strcmp(key, "OVERRIDE")) { switch (err) { case 0: if (strcmp(chptr->mode.key, "OVERRIDE") && strcmp(chptr->mode.apass, "OVERRIDE") && strcmp(chptr->mode.upass, "OVERRIDE")) { send_reply(sptr, ERR_DONTCHEAT, chptr->chname); continue; } break; case ERR_INVITEONLYCHAN: err = 'i'; break; case ERR_CHANNELISFULL: err = 'l'; break; case ERR_BANNEDFROMCHAN: err = 'b'; break; case ERR_BADCHANNELKEY: err = 'k'; break; case ERR_NEEDREGGEDNICK: err = 'r'; break; default: err = '?'; break; } /* send accountability notice */ if (err) sendto_opmask_butone(0, SNO_HACK4, "OPER JOIN: %C JOIN %H " "(overriding +%c)", sptr, chptr, err); err = 0; } /* Is there some reason the user may not join? */ if (err) { switch(err) { case ERR_NEEDREGGEDNICK: send_reply(sptr, ERR_NEEDREGGEDNICK, chptr->chname, feature_str(FEAT_URLREG)); break; default: send_reply(sptr, err, chptr->chname); break; } continue; } joinbuf_join(&join, chptr, flags); if (flags & CHFL_CHANOP) { struct ModeBuf mbuf; /* Always let the server op him: this is needed on a net with older servers because they 'destruct' channels immediately when they become empty without sending out a DESTRUCT message. As a result, they would always bounce a mode (as HACK(2)) when the user ops himself. (There is also no particularly good reason to have the user op himself.) */ modebuf_init(&mbuf, &me, cptr, chptr, MODEBUF_DEST_SERVER); modebuf_mode_client(&mbuf, MODE_ADD | MODE_CHANOP, sptr, chptr->mode.apass[0] ? ((flags & CHFL_CHANNEL_MANAGER) ? 0 : 1) : MAXOPLEVEL); modebuf_flush(&mbuf); } } del_invite(sptr, chptr); if (chptr->topic[0]) { send_reply(sptr, RPL_TOPIC, chptr->chname, chptr->topic); send_reply(sptr, RPL_TOPICWHOTIME, chptr->chname, chptr->topic_nick, chptr->topic_time); } do_names(sptr, chptr, NAMES_ALL|NAMES_EON); /* send /names list */ } joinbuf_flush(&join); /* must be first, if there's a JOIN 0 */ joinbuf_flush(&create); return 0; }
/* * mo_gline - oper message handler * * parv[0] = Sender prefix * parv[1] = [[+|-]<G-line mask>] * * Local (to me) style: * * parv[2] = [Expiration offset] * parv[3] = [Comment] * * Global (or remote local) style: * * parv[2] = [target] * parv[3] = [Expiration offset] * parv[4] = [Comment] * */ int mo_gline(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { struct Client *acptr = 0; struct Gline *agline; unsigned int flags = 0; time_t expire_off; char *mask = parv[1], *target = 0, *reason; if (parc < 2) return gline_list(sptr, 0); if (*mask == '!') { mask++; if (HasPriv(sptr, PRIV_WIDE_GLINE)) flags |= GLINE_OPERFORCE; } if (*mask == '+') { flags |= GLINE_ACTIVE; mask++; } else if (*mask == '-') mask++; else return gline_list(sptr, mask); if (parc == 4) { expire_off = atoi(parv[2]); reason = parv[3]; flags |= GLINE_LOCAL; } else if (parc > 4) { target = parv[2]; expire_off = atoi(parv[3]); reason = parv[4]; } else return need_more_params(sptr, "GLINE"); if (target) { if (!(target[0] == '*' && target[1] == '\0')) { if (!(acptr = find_match_server(target))) return send_reply(sptr, ERR_NOSUCHSERVER, target); /* manually propagate, since we don't set it */ if (!IsMe(acptr)) { if (!feature_bool(FEAT_CONFIG_OPERCMDS)) return send_reply(sptr, ERR_DISABLED, "GLINE"); if (!HasPriv(sptr, PRIV_GLINE)) return send_reply(sptr, ERR_NOPRIVILEGES); sendcmdto_one(sptr, CMD_GLINE, acptr, "%C %s%c%s %s %Tu :%s", acptr, flags & GLINE_OPERFORCE ? "!" : "", flags & GLINE_ACTIVE ? '+' : '-', mask, parv[3], TStime(), reason); return 0; } flags |= GLINE_LOCAL; } } if (!(flags & GLINE_LOCAL) && !feature_bool(FEAT_CONFIG_OPERCMDS)) return send_reply(sptr, ERR_DISABLED, "GLINE"); if (!HasPriv(sptr, (flags & GLINE_LOCAL ? PRIV_LOCAL_GLINE : PRIV_GLINE))) return send_reply(sptr, ERR_NOPRIVILEGES); agline = gline_find(mask, GLINE_ANY | GLINE_EXACT); if (agline) { if (GlineIsLocal(agline) && !(flags & GLINE_LOCAL)) /* global over local */ gline_free(agline); else { if (!GlineLastMod(agline)) /* force mods to Uworld-set G-lines local */ flags |= GLINE_LOCAL; if (flags & GLINE_ACTIVE) return gline_activate(cptr, sptr, agline, GlineLastMod(agline) ? TStime() : 0, flags); else return gline_deactivate(cptr, sptr, agline, GlineLastMod(agline) ? TStime() : 0, flags); } } return gline_add(cptr, sptr, mask, reason, expire_off, TStime(), flags); }
int m_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { struct Channel *chptr = 0; struct ModeBuf mbuf; struct Membership *member; if (parc < 2) return need_more_params(sptr, "MODE"); if (!IsChannelName(parv[1]) || !(chptr = FindChannel(parv[1]))) { struct Client *acptr; acptr = FindUser(parv[1]); if (!acptr) { send_reply(sptr, ERR_NOSUCHCHANNEL, parv[1]); return 0; } else if (sptr != acptr) { send_reply(sptr, ERR_USERSDONTMATCH); return 0; } return set_user_mode(cptr, sptr, parc, parv, ALLOWMODES_ANY); } ClrFlag(sptr, FLAG_TS8); member = find_member_link(chptr, sptr); if (parc < 3) { char modebuf[MODEBUFLEN]; char parabuf[MODEBUFLEN]; *modebuf = *parabuf = '\0'; modebuf[1] = '\0'; channel_modes(sptr, modebuf, parabuf, sizeof(parabuf), chptr, member); send_reply(sptr, RPL_CHANNELMODEIS, chptr->chname, modebuf, parabuf); send_reply(sptr, RPL_CREATIONTIME, chptr->chname, chptr->creationtime); return 0; } if (!member || !IsChanOp(member)) { if (IsLocalChannel(chptr->chname) && HasPriv(sptr, PRIV_MODE_LCHAN)) { modebuf_init(&mbuf, sptr, cptr, chptr, (MODEBUF_DEST_CHANNEL | /* Send mode to channel */ MODEBUF_DEST_HACK4)); /* Send HACK(4) notice */ mode_parse(&mbuf, cptr, sptr, chptr, parc - 2, parv + 2, (MODE_PARSE_SET | /* Set the mode */ MODE_PARSE_FORCE), /* Force it to take */ member); return modebuf_flush(&mbuf); } else mode_parse(0, cptr, sptr, chptr, parc - 2, parv + 2, (member ? MODE_PARSE_NOTOPER : MODE_PARSE_NOTMEMBER), member); return 0; } modebuf_init(&mbuf, sptr, cptr, chptr, (MODEBUF_DEST_CHANNEL | /* Send mode to channel */ MODEBUF_DEST_SERVER)); /* Send mode to servers */ mode_parse(&mbuf, cptr, sptr, chptr, parc - 2, parv + 2, MODE_PARSE_SET, member); return modebuf_flush(&mbuf); }
int m_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { struct Channel *chptr = 0; unsigned int hoflags = 0; struct ModeBuf mbuf; struct Membership *member = 0; if (parc < 2) return need_more_params(sptr, "MODE"); clean_channelname(parv[1]); if (!(chptr = FindChannel(parv[1]))) return set_user_mode(cptr, sptr, parc, parv); ClrFlag(sptr, FLAG_TS8); member = find_member_link(chptr, sptr); if (parc < 3) { char modebuf[MODEBUFLEN]; char parabuf[MODEBUFLEN]; *modebuf = *parabuf = '\0'; modebuf[1] = '\0'; channel_modes(sptr, modebuf, parabuf, sizeof(parabuf), chptr); send_reply(sptr, RPL_CHANNELMODEIS, chptr->chname, modebuf, parabuf); send_reply(sptr, RPL_CREATIONTIME, chptr->chname, chptr->creationtime); return 0; } if ((!member && !IsChannelService(sptr)) || (member && !IsChanOp(member) && !IsHalfOp(member))) { if (IsLocalChannel(chptr->chname) && HasPriv(sptr, PRIV_MODE_LCHAN)) { modebuf_init(&mbuf, sptr, cptr, chptr, (MODEBUF_DEST_CHANNEL | /* Send mode to channel */ MODEBUF_DEST_HACK4)); /* Send HACK(4) notice */ mode_parse(&mbuf, cptr, sptr, chptr, parc - 2, parv + 2, (MODE_PARSE_SET | /* Set the mode */ MODE_PARSE_FORCE), NULL); /* Force it to take */ return modebuf_flush(&mbuf); } else mode_parse(0, cptr, sptr, chptr, parc - 2, parv + 2, (member ? MODE_PARSE_NOTOPER : MODE_PARSE_NOTMEMBER), NULL); return 0; } modebuf_init(&mbuf, sptr, cptr, chptr, (MODEBUF_DEST_CHANNEL | /* Send mode to channel */ MODEBUF_DEST_SERVER)); /* Send mode to servers */ if (member && IsChanOp(member)) hoflags = MODE_PARSE_SET; /* set unconditionally */ else if (member && IsHalfOp(member)) hoflags = MODE_PARSE_ISHALFOP|MODE_PARSE_SET|MODE_PARSE_NOTOPER; /* allowed to +v */ else hoflags = MODE_PARSE_NOTOPER; mode_parse(&mbuf, cptr, sptr, chptr, parc - 2, parv + 2, hoflags, member); return modebuf_flush(&mbuf); }
/* * mo_zline - oper message handler * * parv[0] = Sender prefix * parv[1] = [[+|-]<Z-line mask>] * * For other parameters, see doc/readme.zline. */ int mo_zline(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { struct Client *acptr = 0; struct Zline *azline = 0; unsigned int flags = 0; enum ZlineAction action = ZLINE_MODIFY; time_t expire = 0; char *mask = parv[1], *target = 0, *reason = 0, *end; if (parc < 2) return zline_list(sptr, 0); if (*mask == '!') { mask++; if (HasPriv(sptr, PRIV_WIDE_ZLINE)) flags |= ZLINE_OPERFORCE; } switch (*mask) { /* handle +, -, <, and > */ case '+': /* activate the Z-line */ action = ZLINE_ACTIVATE; mask++; break; case '-': /* deactivate the Z-line */ action = ZLINE_DEACTIVATE; mask++; break; case '>': /* locally activate the Z-line */ action = ZLINE_LOCAL_ACTIVATE; mask++; break; case '<': /* locally deactivate the Z-line */ action = ZLINE_LOCAL_DEACTIVATE; mask++; break; } /* OK, let's figure out the parameters... */ switch (action) { case ZLINE_MODIFY: /* no specific action on the Z-line... */ if (parc == 2) /* user wants a listing of a specific Z-line */ return zline_list(sptr, mask); else if (parc < 4) /* must have target and expire, minimum */ return need_more_params(sptr, "ZLINE"); target = parv[2]; /* get the target... */ if (is_timestamp(parv[3])) { expire = strtol(parv[3], &end, 10) + TStime(); /* and the expiration */ if (*end != '\0') return send_reply(sptr, SND_EXPLICIT | ERR_BADEXPIRE, "%s :Bad expire time", parv[3]); } else expire = ParseInterval(parv[3]) + TStime(); flags |= ZLINE_EXPIRE; /* remember that we got an expire time */ if (parc > 4) { /* also got a reason... */ reason = parv[parc - 1]; flags |= ZLINE_REASON; } /* target is not global, interpolate action and require reason */ if (target[0] != '*' || target[1] != '\0') { if (!reason) /* have to have a reason for this */ return need_more_params(sptr, "ZLINE"); action = ZLINE_ACTIVATE; } break; case ZLINE_LOCAL_ACTIVATE: /* locally activate a Z-line */ case ZLINE_LOCAL_DEACTIVATE: /* locally deactivate a Z-line */ if (parc > 2) { /* if target is available, pick it */ target = parv[2]; if (target[0] == '*' && target[1] == '\0') return send_reply(sptr, ERR_NOSUCHSERVER, target); } break; case ZLINE_ACTIVATE: /* activating/adding a Z-line */ case ZLINE_DEACTIVATE: /* deactivating/removing a Z-line */ if (parc < 3) return need_more_params(sptr, "ZLINE"); if (parc > 3) { /* get expiration and target */ reason = parv[parc - 1]; if (is_timestamp(parv[parc - 2])) { expire = strtol(parv[parc - 2], &end, 10) + TStime(); if (*end != '\0') return send_reply(sptr, SND_EXPLICIT | ERR_BADEXPIRE, "%s :Bad expire time", parv[parc - 2]); } else expire = ParseInterval(parv[parc - 2]) + TStime(); flags |= ZLINE_EXPIRE | ZLINE_REASON; /* remember that we got 'em */ if (parc > 4) /* also have a target! */ target = parv[2]; } else { target = parv[2]; /* target has to be present, and has to be '*' */ if (target[0] != '*' || target[1] != '\0') return need_more_params(sptr, "ZLINE"); } break; } /* Is there no mask left? */ if (mask[0] == '\0') return need_more_params(sptr, "ZLINE"); /* Now let's figure out which is the target server */ if (!target) /* no target, has to be me... */ acptr = &me; /* if it's not '*', look up the server */ else if ((target[0] != '*' || target[1] != '\0') && !(acptr = find_match_server(target))) return send_reply(sptr, ERR_NOSUCHSERVER, target); /* Z-line deprecation notice */ sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Use of Z-line is deprecated. " " Please use G-line instead.", sptr); /* Now, is the Z-line local or global? */ if (action == ZLINE_LOCAL_ACTIVATE || action == ZLINE_LOCAL_DEACTIVATE || !acptr) flags |= ZLINE_GLOBAL; else /* it's some form of local Z-line */ flags |= ZLINE_LOCAL; /* If it's a local activate/deactivate and server isn't me, propagate it */ if ((action == ZLINE_LOCAL_ACTIVATE || action == ZLINE_LOCAL_DEACTIVATE) && !IsMe(acptr)) { /* check for permissions... */ if (!feature_bool(FEAT_CONFIG_OPERCMDS)) return send_reply(sptr, ERR_DISABLED, "ZLINE"); else if (!HasPriv(sptr, PRIV_ZLINE)) return send_reply(sptr, ERR_NOPRIVILEGES); Debug((DEBUG_DEBUG, "I am forwarding a local change to a global zline " "to a remote server; target %s, mask %s, operforce %s, action %c", cli_name(acptr), mask, flags & ZLINE_OPERFORCE ? "YES" : "NO", action == ZLINE_LOCAL_ACTIVATE ? '>' : '<')); sendcmdto_one(sptr, CMD_ZLINE, acptr, "%C %s%c%s", acptr, flags & ZLINE_OPERFORCE ? "!" : "", action == ZLINE_LOCAL_ACTIVATE ? '>' : '<', mask); return 0; /* all done */ } /* Next, try to find the Z-line... */ if ((flags & ZLINE_GLOBAL) || IsMe(acptr)) /* don't bother if it's not me! */ azline = zline_find(mask, flags | ZLINE_ANY | ZLINE_EXACT); /* We now have all the pieces to tell us what we've got; let's put * it all together and convert the rest of the arguments. */ /* Handle the local Z-lines first... */ if (flags & ZLINE_LOCAL) { assert(acptr); /* normalize the action, first */ if (action == ZLINE_LOCAL_ACTIVATE || action == ZLINE_MODIFY) action = ZLINE_ACTIVATE; else if (action == ZLINE_LOCAL_DEACTIVATE) action = ZLINE_DEACTIVATE; /* If it's not for us, forward */ /* UPDATE NOTE: Once all servers are updated to u2.10.12.11, the * format string in this sendcmdto_one() may be updated to omit * <lastmod> for ZLINE_ACTIVATE and to omit <expire>, <lastmod>, * and <reason> for ZLINE_DEACTIVATE. */ if (!IsMe(acptr)) { /* check for permissions... */ if (!feature_bool(FEAT_CONFIG_OPERCMDS)) return send_reply(sptr, ERR_DISABLED, "ZLINE"); else if (!HasPriv(sptr, PRIV_ZLINE)) return send_reply(sptr, ERR_NOPRIVILEGES); Debug((DEBUG_DEBUG, "I am forwarding a local Z-line to a remote " "server; target %s, mask %s, operforce %s, action %c, " "expire %Tu, reason %s", target, mask, flags & ZLINE_OPERFORCE ? "YES" : "NO", action == ZLINE_ACTIVATE ? '+' : '-', expire, reason)); sendcmdto_one(sptr, CMD_ZLINE, acptr, "%C %s%c%s %Tu %Tu :%s", acptr, flags & ZLINE_OPERFORCE ? "!" : "", action == ZLINE_ACTIVATE ? '+' : '-', mask, expire - TStime(), TStime(), reason); return 0; /* all done */ } /* check local Z-line permissions... */ if (!HasPriv(sptr, PRIV_LOCAL_ZLINE)) return send_reply(sptr, ERR_NOPRIVILEGES); /* let's handle activation... */ if (action == ZLINE_ACTIVATE) { if (azline) /* Z-line already exists, so let's ignore it... */ return 0; /* OK, create the local Z-line */ Debug((DEBUG_DEBUG, "I am creating a local Z-line here; target %s, " "mask %s, operforce %s, action %s, expire %Tu, reason: %s", target, mask, flags & ZLINE_OPERFORCE ? "YES" : "NO", action == ZLINE_ACTIVATE ? "+" : "-", expire, reason)); return zline_add(cptr, sptr, mask, reason, expire, 0, 0, flags | ZLINE_ACTIVE); } else { /* OK, it's a deactivation/destruction */ if (!azline) /* Z-line doesn't exist, so let's complain... */ return send_reply(sptr, ERR_NOSUCHZLINE, mask); /* Let's now destroy the Z-line */ Debug((DEBUG_DEBUG, "I am destroying a local Z-line here; target %s, " "mask %s, operforce %s, action %s", target, mask, flags & ZLINE_OPERFORCE ? "YES" : "NO", action == ZLINE_ACTIVATE ? "+" : "-")); return zline_destroy(cptr, sptr, azline); } } /* can't modify a Z-line that doesn't exist... * (and if we are creating a new one, we need a reason and expiration) */ if (!azline && (action == ZLINE_MODIFY || action == ZLINE_LOCAL_ACTIVATE || action == ZLINE_LOCAL_DEACTIVATE || !reason || !expire)) return send_reply(sptr, ERR_NOSUCHZLINE, mask); /* check for Z-line permissions... */ if (action == ZLINE_LOCAL_ACTIVATE || action == ZLINE_LOCAL_DEACTIVATE) { /* only need local privileges for locally-limited status changes */ if (!HasPriv(sptr, PRIV_LOCAL_ZLINE)) return send_reply(sptr, ERR_NOPRIVILEGES); } else { /* global privileges required */ if (!feature_bool(FEAT_CONFIG_OPERCMDS)) return send_reply(sptr, ERR_DISABLED, "ZLINE"); else if (!HasPriv(sptr, PRIV_ZLINE)) return send_reply(sptr, ERR_NOPRIVILEGES); } Debug((DEBUG_DEBUG, "I have a global Z-line I am acting upon now; " "target %s, mask %s, operforce %s, action %s, expire %Tu, " "reason: %s; zline %s! (fields present: %s %s)", target, mask, flags & ZLINE_OPERFORCE ? "YES" : "NO", action == ZLINE_ACTIVATE ? "+" : (action == ZLINE_DEACTIVATE ? "-" : (action == ZLINE_LOCAL_ACTIVATE ? ">" : (action == ZLINE_LOCAL_DEACTIVATE ? "<" : "(MODIFY)"))), expire, reason, azline ? "EXISTS" : "does not exist", flags & ZLINE_EXPIRE ? "expire" : "", flags & ZLINE_REASON ? "reason" : "")); if (azline) /* modifying an existing Z-line */ return zline_modify(cptr, sptr, azline, action, reason, expire, TStime(), 0, flags); assert(action != ZLINE_LOCAL_ACTIVATE); assert(action != ZLINE_LOCAL_DEACTIVATE); assert(action != ZLINE_MODIFY); /* create a new Z-line */ return zline_add(cptr, sptr, mask, reason, expire, TStime(), 0, flags | ((action == ZLINE_ACTIVATE) ? ZLINE_ACTIVE : 0)); }
/* * m_kick - generic message handler * * parv[0] = sender prefix * parv[1] = channel * parv[2] = client to kick * parv[parc-1] = kick comment */ int m_kick(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { struct Client *who; struct Channel *chptr; struct Membership *member = 0; struct Membership* member2; char *name, *comment; ClrFlag(sptr, FLAG_TS8); if (parc < 3 || *parv[1] == '\0') return need_more_params(sptr, "KICK"); name = parv[1]; /* simple checks */ if (!(chptr = get_channel(sptr, name, CGT_NO_CREATE))) return send_reply(sptr, ERR_NOSUCHCHANNEL, name); if (!(member2 = find_member_link(chptr, sptr)) || IsZombie(member2) || !IsChanOp(member2)) return send_reply(sptr, ERR_CHANOPRIVSNEEDED, name); if (!(who = find_chasing(sptr, parv[2], 0))) return 0; /* find_chasing sends the reply for us */ /* Don't allow the channel service to be kicked */ if (IsChannelService(who)) return send_reply(sptr, ERR_ISCHANSERVICE, cli_name(who), chptr->chname); /* Prevent kicking opers from local channels -DM- */ if (IsLocalChannel(chptr->chname) && HasPriv(who, PRIV_DEOP_LCHAN)) return send_reply(sptr, ERR_ISOPERLCHAN, cli_name(who), chptr->chname); /* check if kicked user is actually on the channel */ if (!(member = find_member_link(chptr, who)) || IsZombie(member)) return send_reply(sptr, ERR_USERNOTINCHANNEL, cli_name(who), chptr->chname); /* Don't allow to kick member with a higher op-level, * or members with the same op-level unless both are MAXOPLEVEL. */ if (OpLevel(member) < OpLevel(member2) || (OpLevel(member) == OpLevel(member2) && OpLevel(member) < MAXOPLEVEL)) return send_reply(sptr, ERR_NOTLOWEROPLEVEL, cli_name(who), chptr->chname, OpLevel(member2), OpLevel(member), "kick", OpLevel(member) == OpLevel(member2) ? "the same" : "a higher"); /* We rely on ircd_snprintf to truncate the comment */ comment = EmptyString(parv[parc - 1]) ? parv[0] : parv[parc - 1]; if (!IsLocalChannel(name)) sendcmdto_serv_butone(sptr, CMD_KICK, cptr, "%H %C :%s", chptr, who, comment); if (IsDelayedJoin(member)) { /* If it's a delayed join, only send the KICK to the person doing * the kicking and the victim */ if (MyUser(who)) sendcmdto_one(sptr, CMD_KICK, who, "%H %C :%s", chptr, who, comment); sendcmdto_one(who, CMD_JOIN, sptr, "%H", chptr); sendcmdto_one(sptr, CMD_KICK, sptr, "%H %C :%s", chptr, who, comment); CheckDelayedJoins(chptr); } else sendcmdto_channel_butserv_butone(sptr, CMD_KICK, chptr, NULL, 0, "%H %C :%s", chptr, who, comment); make_zombie(member, who, cptr, sptr, chptr); return 0; }
int m_challenge(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { #ifdef USE_SSL struct ConfItem *aconf; RSA *rsa_public_key; BIO *file = NULL; char *challenge = NULL; char *name; char *tmpname; char chan[CHANNELLEN-1]; char* join[2]; int nl; struct Flags old_mode = cli_flags(sptr); if (!MyUser(sptr)) return 0; if (parc < 2) return need_more_params(sptr, "CHALLENGE"); if (parc > 2) { /* This is a remote OPER Request */ struct Client *srv; if (!string_has_wildcards(parv[1])) srv = FindServer(parv[1]); else srv = find_match_server(parv[1]); if (!feature_bool(FEAT_REMOTE_OPER)) return send_reply(sptr, ERR_NOOPERHOST); if (!srv) return send_reply(sptr, ERR_NOOPERHOST); if (IsMe(srv)) { parv[1] = parv[2]; } else { sendcmdto_one(sptr, CMD_CHALLENGE, srv, "%C %s", srv, parv[2]); return 0; } } /* if theyre an oper, reprint oper motd and ignore */ if (IsOper(sptr)) { send_reply(sptr, RPL_YOUREOPER); if (feature_bool(FEAT_OPERMOTD)) m_opermotd(sptr, sptr, 1, parv); } if (*parv[1] == '+') { /* Ignore it if we aren't expecting this... -A1kmm */ if (cli_user(sptr)->response == NULL) return 0; if (ircd_strcmp(cli_user(sptr)->response, ++parv[1])) { send_reply(sptr, ERR_PASSWDMISMATCH); sendto_allops(&me, SNO_OLDREALOP, "Failed OPER attempt by %s (%s@%s) (Password Incorrect)", parv[0], cli_user(sptr)->realusername, cli_sockhost(sptr)); tmpname = strdup(cli_user(sptr)->auth_oper); failed_challenge_notice(sptr, tmpname, "challenge failed"); return 0; } name = strdup(cli_user(sptr)->auth_oper); aconf = find_conf_exact(cli_user(sptr)->auth_oper, cli_user(sptr)->realusername, MyUser(sptr) ? cli_sockhost(sptr) : cli_user(sptr)->realhost, CONF_OPS); if (!aconf) aconf = find_conf_exact(cli_user(sptr)->auth_oper, cli_user(sptr)->realusername, ircd_ntoa((const char*) &(cli_ip(sptr))), CONF_OPS); if (!aconf) aconf = find_conf_cidr(cli_user(sptr)->auth_oper, cli_user(sptr)->realusername, cli_ip(sptr), CONF_OPS); if (!aconf) { send_reply(sptr, ERR_NOOPERHOST); sendto_allops(&me, SNO_OLDREALOP, "Failed OPER attempt by %s (%s@%s) (No O:line)", parv[0], cli_user(sptr)->realusername, cli_sockhost(sptr)); return 0; } if (CONF_LOCOP == aconf->status) { ClearOper(sptr); SetLocOp(sptr); } else { /* * prevent someone from being both oper and local oper */ ClearLocOp(sptr); if (!feature_bool(FEAT_OPERFLAGS) || !(aconf->port & OFLAG_ADMIN)) { /* Global Oper */ SetOper(sptr); ClearAdmin(sptr); } else { /* Admin */ SetOper(sptr); OSetGlobal(sptr); SetAdmin(sptr); } ++UserStats.opers; } cli_handler(cptr) = OPER_HANDLER; if (!feature_bool(FEAT_OPERFLAGS) || (aconf->port & OFLAG_WHOIS)) { OSetWhois(sptr); } if (!feature_bool(FEAT_OPERFLAGS) || (aconf->port & OFLAG_IDLE)) { OSetIdle(sptr); } if (!feature_bool(FEAT_OPERFLAGS) || (aconf->port & OFLAG_XTRAOP)) { OSetXtraop(sptr); } if (!feature_bool(FEAT_OPERFLAGS) || (aconf->port & OFLAG_HIDECHANS)) { OSetHideChans(sptr); } SetFlag(sptr, FLAG_WALLOP); SetFlag(sptr, FLAG_SERVNOTICE); SetFlag(sptr, FLAG_DEBUG); if (!IsAdmin(sptr)) cli_oflags(sptr) = aconf->port; set_snomask(sptr, SNO_OPERDEFAULT, SNO_ADD); client_set_privs(sptr, aconf); cli_max_sendq(sptr) = 0; /* Get the sendq from the oper's class */ send_umode_out(cptr, sptr, &old_mode, HasPriv(sptr, PRIV_PROPAGATE)); send_reply(sptr, RPL_YOUREOPER); if (IsAdmin(sptr)) { sendto_allops(&me, SNO_OLDSNO, "%s (%s@%s) is now an IRC Administrator", parv[0], cli_user(sptr)->username, cli_sockhost(sptr)); /* Autojoin admins to admin channel and oper channel (if enabled) */ if (feature_bool(FEAT_AUTOJOIN_ADMIN)) { if (feature_bool(FEAT_AUTOJOIN_ADMIN_NOTICE)) sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s", sptr, feature_str(FEAT_AUTOJOIN_ADMIN_NOTICE_VALUE)); ircd_strncpy(chan, feature_str(FEAT_AUTOJOIN_ADMIN_CHANNEL), CHANNELLEN-1); join[0] = cli_name(sptr); join[1] = chan; m_join(sptr, sptr, 2, join); } if (feature_bool(FEAT_AUTOJOIN_OPER) && IsOper(sptr)) { if (feature_bool(FEAT_AUTOJOIN_OPER_NOTICE)) sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s", sptr, feature_str(FEAT_AUTOJOIN_OPER_NOTICE_VALUE)); ircd_strncpy(chan, feature_str(FEAT_AUTOJOIN_OPER_CHANNEL), CHANNELLEN-1); join[0] = cli_name(sptr); join[1] = chan; m_join(sptr, sptr, 2, join); } } else { sendto_allops(&me, SNO_OLDSNO, "%s (%s@%s) is now an IRC Operator (%c)", parv[0], cli_user(sptr)->username, cli_sockhost(sptr), IsOper(sptr) ? 'O' : 'o'); if (feature_bool(FEAT_AUTOJOIN_OPER) && IsOper(sptr)) { if (feature_bool(FEAT_AUTOJOIN_OPER_NOTICE)) sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s", sptr, feature_str(FEAT_AUTOJOIN_OPER_NOTICE_VALUE)); ircd_strncpy(chan, feature_str(FEAT_AUTOJOIN_OPER_CHANNEL), CHANNELLEN-1); join[0] = cli_name(sptr); join[1] = chan; m_join(sptr, sptr, 2, join); } } if (feature_bool(FEAT_OPERMOTD)) m_opermotd(sptr, sptr, 1, parv); log_write(LS_OPER, L_INFO, 0, "OPER (%s) by (%#C)", name, sptr); ircd_snprintf(0, cli_user(sptr)->response, BUFSIZE+1, "%s", ""); return 0; } ircd_snprintf(0, cli_user(sptr)->response, BUFSIZE+1, "%s", ""); ircd_snprintf(0, cli_user(sptr)->auth_oper, NICKLEN+1, "%s", ""); aconf = find_conf_exact(parv[1], cli_user(sptr)->realusername, cli_user(sptr)->realhost, CONF_OPS); if (!aconf) aconf = find_conf_exact(parv[1], cli_user(sptr)->realusername, ircd_ntoa((const char*) &(cli_ip(sptr))), CONF_OPS); if (!aconf) aconf = find_conf_cidr(parv[1], cli_user(sptr)->realusername, cli_ip(sptr), CONF_OPS); if (aconf == NULL) { send_reply(sptr, ERR_NOOPERHOST); failed_challenge_notice(sptr, parv[1], "No o:line"); sendto_allops(&me, SNO_OLDREALOP, "Failed OPER attempt by %s (%s@%s) (No O:line)", parv[0], cli_user(sptr)->realusername, cli_sockhost(sptr)); return 0; } if (!(aconf->port & OFLAG_RSA)) { send_reply(sptr, RPL_NO_CHALL); return 0; } if (!verify_sslclifp(sptr, aconf)) { sendto_allops(&me, SNO_OLDREALOP, "Failed OPER attempt by %s (%s@%s) (SSL Fingerprint Missmatch)", parv[0], cli_user(sptr)->realusername, cli_user(sptr)->realhost); send_reply(sptr, ERR_SSLCLIFP); return 0; } if ((file = BIO_new_file(aconf->passwd, "r")) == NULL) { send_reply(sptr, RPL_NO_KEY); return 0; } rsa_public_key = (RSA *)PEM_read_bio_RSA_PUBKEY(file, NULL, 0, NULL); if (rsa_public_key == NULL) return send_reply(sptr, RPL_INVALID_KEY); if (!generate_challenge(&challenge, rsa_public_key, sptr)) { Debug((DEBUG_DEBUG, "generating challenge sum (%s)", challenge)); send_reply(sptr, RPL_RSACHALLENGE, challenge); ircd_snprintf(0, cli_user(sptr)->auth_oper, NICKLEN + 1, "%s", aconf->name); } nl = BIO_set_close(file, BIO_CLOSE); BIO_free(file); return 1; #else return 1; #endif }
static void give_money (dbref giver, dbref recipient, int key, int amount) { dbref aowner; int cost, pcost, rcost, aflags, dpamount; char *str; /* do amount consistency check */ if (amount < 0 && ((!Builder(giver) && !HasPriv(giver,recipient,POWER_STEAL,POWER3,NOTHING)) || DePriv(giver,recipient,DP_STEAL,POWER6,NOTHING))) { notify(giver, unsafe_tprintf("You look through your pockets. Nope, no negative %s.", mudconf.many_coins)); return; } if (!amount) { notify(giver, unsafe_tprintf("You must specify a positive number of %s.", mudconf.many_coins)); return; } dpamount = 0; if (amount < 0) dpamount = DePriv(giver,NOTHING,DP_NOSTEAL,POWER7,POWER_LEVEL_NA); else dpamount = DePriv(giver,NOTHING,DP_NOGOLD,POWER7,POWER_LEVEL_NA); if (dpamount) { if (DPShift(giver)) dpamount--; dpamount = mudconf.money_limit[dpamount]; } else dpamount = -1; if (!Admin(Owner(giver))) { if ((Typeof(recipient) == TYPE_PLAYER) && (Pennies(recipient) + amount > mudconf.paylimit)) { notify(giver, unsafe_tprintf("That player doesn't need that many %s!", mudconf.many_coins)); return; } if ((Typeof(recipient) != TYPE_PLAYER) && (!could_doit(giver, recipient, A_LUSE,1))) { notify(giver, unsafe_tprintf("%s won't take your money.", Name(recipient))); return; } } str = atr_get(Owner(giver), A_PAYLIM, &aowner, &aflags); pcost = atoi(str); free_lbuf(str); if (!Immortal(Owner(giver)) && pcost) { if ((Typeof(recipient) == TYPE_PLAYER) && (amount > 0) && (Pennies(recipient) + amount > pcost)) { notify(giver, unsafe_tprintf("That player doesn't need that many %s!", mudconf.many_coins)); return; } else if (Pennies(recipient) + amount < (-pcost)) { notify(giver,"That player doesn't need that much debt!"); return; } } str = atr_get(Owner(recipient), A_RECEIVELIM, &aowner, &aflags); rcost = atoi(str); free_lbuf(str); if (!Immortal(Owner(giver)) && rcost) { if ((Typeof(recipient) == TYPE_PLAYER) && (amount > 0) && (Pennies(recipient) + amount > rcost)) { notify(giver, unsafe_tprintf("That player doesn't need that many %s!", mudconf.many_coins)); return; } else if (Pennies(recipient) + amount < (-rcost)) { notify(giver,"That player doesn't need that much debt!"); return; } } if (!Immortal(Owner(giver))) { if (dpamount >= 0) { if (amount > 0) { if ((Typeof(recipient) == TYPE_PLAYER) && (Pennies(recipient) + amount > dpamount)) { notify(giver, unsafe_tprintf("That player doesn't need that many %s!", mudconf.many_coins)); return; } else if (amount > dpamount) { notify(giver, "Permission denied."); return; } } else { if ((Typeof(recipient) == TYPE_PLAYER) && (Pennies(recipient) + amount < (-dpamount))) { notify(giver, unsafe_tprintf("That player doesn't need that many %s!", mudconf.many_coins)); return; } else if (amount < (-dpamount)) { notify(giver, "Permission denied."); return; } } } } /* try to do the give */ if (!payfor_give(giver, amount)) { notify(giver, unsafe_tprintf("You don't have that many %s to give!", mudconf.many_coins)); return; } /* Find out cost if an object */ if (Typeof(recipient) == TYPE_THING) { str = atr_pget(recipient, A_COST, &aowner, &aflags); cost = atoi(str); free_lbuf(str); /* Can't afford it? */ if (amount < cost) { notify(giver, "Feeling poor today?"); giveto(giver, amount, NOTHING); return; } /* Negative cost */ if (cost < 0) { return; } } else { cost = amount; } if (!(key & GIVE_QUIET)) { if (amount == 1) { notify(giver, unsafe_tprintf("You give a %s to %s.", mudconf.one_coin, Name(recipient))); notify_with_cause(recipient, giver, unsafe_tprintf("%s gives you a %s.", Name(giver), mudconf.one_coin)); } else { notify(giver, unsafe_tprintf("You give %d %s to %s.", amount, mudconf.many_coins, Name(recipient))); notify_with_cause(recipient, giver, unsafe_tprintf("%s gives you %d %s.", Name(giver), amount, mudconf.many_coins)); } } else { if (amount == 1) { notify(giver, unsafe_tprintf("You give a %s to %s. (quiet)", mudconf.one_coin, Name(recipient))); } else { notify(giver, unsafe_tprintf("You give %d %s to %s. (quiet)", amount, mudconf.many_coins, Name(recipient))); } } /* Report change given */ if((amount - cost) == 1) { notify(giver, unsafe_tprintf("You get 1 %s in change.", mudconf.one_coin)); giveto(giver, 1, NOTHING); } else if (amount != cost) { notify(giver, unsafe_tprintf("You get %d %s in change.", (amount - cost), mudconf.many_coins)); giveto(giver, (amount - cost), NOTHING); } if (pcost && (Pennies(Owner(recipient)) + cost > pcost)) { pcost = pcost - Pennies(Owner(recipient)); if (pcost < 0) pcost = 0; } else pcost = cost; if (!giveto(recipient, pcost, giver)) giveto(giver, cost, NOTHING); /* Transfer the money and run PAY attributes */ /* Rooms should not kick off the PAY attribute */ if ( !isRoom(giver) ) did_it(giver, recipient, A_PAY, NULL, A_OPAY, NULL, A_APAY, (char **)NULL, 0); return; }
/* * m_who - generic message handler * * parv[0] = sender prefix * parv[1] = nickname mask list * parv[2] = additional selection flag, only 'o' for now. * and %flags to specify what fields to output * plus a ,querytype if the t flag is specified * so the final thing will be like o%tnchu,777 * parv[3] = _optional_ parameter that overrides parv[1] * This can be used as "/quote who foo % :The Black Hacker * to find me, parv[3] _can_ contain spaces !. */ int m_who(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { char *mask; /* The mask we are looking for */ char ch; /* Scratch char register */ struct Channel *chptr; /* Channel to show */ struct Client *acptr; /* Client to show */ int bitsel; /* Mask of selectors to apply */ int matchsel; /* Wich fields the match should apply on */ int counter; /* Query size counter, initially used to count fields */ int commas; /* Does our mask contain any comma ? If so is a list.. */ int fields; /* Mask of fields to show */ int isthere = 0; /* When this set the user is member of chptr */ char *nick; /* Single element extracted from the mask list */ char *p; /* Scratch char pointer */ char *qrt; /* Pointer to the query type */ static char mymask[512]; /* To save the mask before corrupting it */ unsigned int who_marker; /* Used to mark clients we've touched */ /* Let's find where is our mask, and if actually contains something */ mask = ((parc > 1) ? parv[1] : 0); if (parc > 3 && parv[3]) mask = parv[3]; if (mask && ((mask[0] == '\0') || (mask[1] == '\0' && ((mask[0] == '0') || (mask[0] == '*'))))) mask = 0; /* Evaluate the flags now, we consider the second parameter as "matchFlags%fieldsToInclude,querytype" */ bitsel = fields = counter = matchsel = 0; qrt = 0; if (parc > 2 && parv[2] && *parv[2]) { p = parv[2]; while (((ch = *(p++))) && (ch != '%') && (ch != ',')) switch (ch) { case 'o': case 'O': bitsel |= WHOSELECT_OPER; continue; case 'x': case 'X': if (HasPriv(sptr, PRIV_WHOX)) { log_write(LS_WHO, L_INFO, LOG_NOSNOTICE, "%#C WHO %s %s", sptr, (BadPtr(parv[3]) ? parv[1] : parv[3]), parv[2]); bitsel |= WHOSELECT_EXTRA; } continue; case 'n': case 'N': matchsel |= WHO_FIELD_NIC; continue; case 'u': case 'U': matchsel |= WHO_FIELD_UID; continue; case 'h': case 'H': matchsel |= WHO_FIELD_HOS; continue; case 'i': case 'I': matchsel |= WHO_FIELD_NIP; continue; case 's': case 'S': matchsel |= WHO_FIELD_SER; continue; case 'r': case 'R': matchsel |= WHO_FIELD_REN; continue; case 'a': case 'A': matchsel |= WHO_FIELD_ACC; continue; } if (ch == '%') while ((ch = *p++) && (ch != ',')) { counter++; switch (ch) { case 'c': case 'C': fields |= WHO_FIELD_CHA; break; case 'd': case 'D': fields |= WHO_FIELD_DIS; break; case 'f': case 'F': fields |= WHO_FIELD_FLA; break; case 'h': case 'H': fields |= WHO_FIELD_HOS; break; case 'i': case 'I': fields |= WHO_FIELD_NIP; break; case 'l': case 'L': fields |= WHO_FIELD_IDL; case 'n': case 'N': fields |= WHO_FIELD_NIC; break; case 'r': case 'R': fields |= WHO_FIELD_REN; break; case 's': case 'S': fields |= WHO_FIELD_SER; break; case 't': case 'T': fields |= WHO_FIELD_QTY; break; case 'u': case 'U': fields |= WHO_FIELD_UID; break; case 'a': case 'A': fields |= WHO_FIELD_ACC; break; default: break; } }; if (ch) qrt = p; } if (!matchsel) matchsel = WHO_FIELD_DEF; if (!fields) counter = 7; if (feature_bool(FEAT_HIS_WHO_SERVERNAME) && !IsAnOper(sptr)) matchsel &= ~WHO_FIELD_SER; if (qrt && (fields & WHO_FIELD_QTY)) { p = qrt; if (!((*p > '9') || (*p < '0'))) p++; if (!((*p > '9') || (*p < '0'))) p++; if (!((*p > '9') || (*p < '0'))) p++; *p = '\0'; } else qrt = 0; /* I'd love to add also a check on the number of matches fields per time */ counter = (2048 / (counter + 4)); if (mask && (strlen(mask) > 510)) mask[510] = '\0'; who_marker = get_client_marker(); commas = (mask && strchr(mask, ',')); /* First treat mask as a list of plain nicks/channels */ if (mask) { strcpy(mymask, mask); for (p = 0, nick = ircd_strtok(&p, mymask, ","); nick; nick = ircd_strtok(&p, 0, ",")) { if (IsChannelName(nick) && (chptr = FindChannel(nick))) { isthere = (find_channel_member(sptr, chptr) != 0); if (isthere || SEE_CHANNEL(sptr, chptr, bitsel)) { struct Membership* member; for (member = chptr->members; member; member = member->next_member) { acptr = member->user; if ((bitsel & WHOSELECT_OPER) && !SeeOper(sptr,acptr)) continue; if ((acptr != sptr) && (member->status & CHFL_ZOMBIE)) continue; if (!(isthere || (SEE_USER(sptr, acptr, bitsel)))) continue; if (!Process(acptr)) /* This can't be moved before other checks */ continue; if (!(isthere || (IsOper(sptr) && (bitsel & WHOSELECT_EXTRA) && HasPriv(sptr, PRIV_SEE_CHAN)) || (SHOW_MORE(sptr, counter)))) break; do_who(sptr, acptr, chptr, fields, qrt); } } } else { if ((acptr = FindUser(nick)) && ((!(bitsel & WHOSELECT_OPER)) || SeeOper(sptr,acptr)) && Process(acptr) && SHOW_MORE(sptr, counter)) { do_who(sptr, acptr, 0, fields, qrt); } } } } /* If we didn't have any comma in the mask treat it as a real mask and try to match all relevant fields */ if (!(commas || (counter < 1))) { int minlen, cset; static struct in_mask imask; if (mask) { matchcomp(mymask, &minlen, &cset, mask); if (matchcompIP(&imask, mask)) matchsel &= ~WHO_FIELD_NIP; if ((minlen > NICKLEN) || !(cset & NTL_IRCNK)) matchsel &= ~WHO_FIELD_NIC; if ((matchsel & WHO_FIELD_SER) && ((minlen > HOSTLEN) || (!(cset & NTL_IRCHN)) || (!markMatchexServer(mymask, minlen)))) matchsel &= ~WHO_FIELD_SER; if ((minlen > USERLEN) || !(cset & NTL_IRCUI)) matchsel &= ~WHO_FIELD_UID; if ((minlen > HOSTLEN) || !(cset & NTL_IRCHN)) matchsel &= ~WHO_FIELD_HOS; } /* First of all loop through the clients in common channels */ if ((!(counter < 1)) && matchsel) { struct Membership* member; struct Membership* chan; for (chan = cli_user(sptr)->channel; chan; chan = chan->next_channel) { chptr = chan->channel; for (member = chptr->members; member; member = member->next_member) { acptr = member->user; if (!(IsUser(acptr) && Process(acptr))) continue; /* Now Process() is at the beginning, if we fail we'll never have to show this acptr in this query */ if ((bitsel & WHOSELECT_OPER) && !SeeOper(sptr,acptr)) continue; if ((mask) && ((!(matchsel & WHO_FIELD_NIC)) || matchexec(cli_name(acptr), mymask, minlen)) && ((!(matchsel & WHO_FIELD_UID)) || matchexec(cli_user(acptr)->username, mymask, minlen)) && ((!(matchsel & WHO_FIELD_SER)) || (!HasFlag(cli_user(acptr)->server, FLAG_MAP))) && ((!(matchsel & WHO_FIELD_HOS)) || matchexec(cli_user(acptr)->host, mymask, minlen)) && ((!(matchsel & WHO_FIELD_HOS)) || !HasSetHost(acptr) || !HasHiddenHost(acptr) || !IsAnOper(sptr) || matchexec(cli_user(acptr)->realhost, mymask, minlen)) && ((!(matchsel & WHO_FIELD_REN)) || matchexec(cli_info(acptr), mymask, minlen)) && ((!(matchsel & WHO_FIELD_NIP)) || ((HasHiddenHost(acptr) || HasSetHost(acptr)) && !IsAnOper(sptr)) || ((((cli_ip(acptr).s_addr & imask.mask.s_addr) != imask.bits.s_addr)) || (imask.fall && matchexec(ircd_ntoa((const char*) &(cli_ip(acptr))), mymask, minlen))))) continue; if (!SHOW_MORE(sptr, counter)) break; do_who(sptr, acptr, chptr, fields, qrt); } } } /* Loop through all clients :-\, if we still have something to match to and we can show more clients */ if ((!(counter < 1)) && matchsel) for (acptr = cli_prev(&me); acptr; acptr = cli_prev(acptr)) { if (!(IsUser(acptr) && Process(acptr))) continue; if ((bitsel & WHOSELECT_OPER) && !SeeOper(sptr,acptr)) continue; if (!(SEE_USER(sptr, acptr, bitsel))) continue; if ((mask) && ((!(matchsel & WHO_FIELD_NIC)) || matchexec(cli_name(acptr), mymask, minlen)) && ((!(matchsel & WHO_FIELD_UID)) || matchexec(cli_user(acptr)->username, mymask, minlen)) && ((!(matchsel & WHO_FIELD_SER)) || (!HasFlag(cli_user(acptr)->server, FLAG_MAP))) && ((!(matchsel & WHO_FIELD_HOS)) || matchexec(cli_user(acptr)->host, mymask, minlen)) && ((!(matchsel & WHO_FIELD_HOS)) || !HasSetHost(acptr) || !HasHiddenHost(acptr) || !IsAnOper(sptr) || matchexec(cli_user(acptr)->realhost, mymask, minlen)) && ((!(matchsel & WHO_FIELD_REN)) || matchexec(cli_info(acptr), mymask, minlen)) && ((!(matchsel & WHO_FIELD_NIP)) || (HasHiddenHost(acptr) && !IsAnOper(sptr)) || ((((cli_ip(acptr).s_addr & imask.mask.s_addr) != imask.bits.s_addr)) || (imask.fall && matchexec(ircd_ntoa((const char*) &(cli_ip(acptr))), mymask, minlen))))) continue; if (!SHOW_MORE(sptr, counter)) break; do_who(sptr, acptr, 0, fields, qrt); } } /* Make a clean mask suitable to be sent in the "end of" */ if (mask && (p = strchr(mask, ' '))) *p = '\0'; send_reply(sptr, RPL_ENDOFWHO, BadPtr(mask) ? "*" : mask); /* Notify the user if we decided that his query was too long */ if (counter < 0) send_reply(sptr, ERR_QUERYTOOLONG, "WHO"); return 0; }
/* * 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; }
void do_kill (dbref player, dbref cause, int key, char *what, char *costchar) { dbref victim; char *buf1, *buf2; int cost; init_match(player, what, TYPE_PLAYER); match_neighbor(); match_me(); match_here(); if (Wizard(player)) { match_player(); match_absolute(); } victim = match_result(); switch (victim) { case NOTHING: notify(player, "I don't see that player here."); break; case AMBIGUOUS: notify(player, "I don't know who you mean!"); break; default: if ((Typeof(victim) != TYPE_PLAYER) && (Typeof(victim) != TYPE_THING)) { notify(player, "Sorry, you can only kill players and things."); break; } if ((Haven(Location(victim)) && !Wizard(player)) || (controls(victim, Location(victim)) && !controls(player, Location(victim))) || Immortal(victim)) { notify(player, "Sorry."); break; } if (key == KILL_SLAY) { if (Builder(player) && Builder(victim)) { notify(player, "Sorry."); break; } } /* go for it */ cost = atoi(costchar); if (key == KILL_KILL) { if (HasPriv(victim,player,POWER_NOKILL,POWER4,NOTHING)) { notify(player, "Sorry."); break; } if (cost < mudconf.killmin) cost = mudconf.killmin; if (cost > mudconf.killmax) cost = mudconf.killmax; /* see if it works */ if (!payfor(player, cost)) { notify(player, unsafe_tprintf("You don't have enough %s.", mudconf.many_coins)); return; } } else { cost = 0; } if (!(((random() % mudconf.killguarantee) < cost) || (key == KILL_SLAY)) || Wizard(victim)) { /* Failure: notify player and victim only */ notify(player, "Your murder attempt failed."); buf1 = alloc_lbuf("do_kill.failed"); sprintf(buf1, "%s tried to kill you!", Name(player)); notify_with_cause(victim, player, buf1); if (Suspect(player)) { strcpy(buf1, Name(player)); if (player == Owner(player)) { raw_broadcast(0, WIZARD, "[Suspect] %s tried to kill %s(#%d).", buf1, Name(victim), victim); } else { buf2 = alloc_lbuf("do_kill.SUSP.failed"); strcpy(buf2, Name(Owner(player))); raw_broadcast(0, WIZARD, "[Suspect] %s <via %s(#%d)> tried to kill %s(#%d).", buf2, buf1, player, Name(victim), victim); free_lbuf(buf2); } } free_lbuf(buf1); break; } /* Success! You killed him */ buf1 = alloc_lbuf("do_kill.succ.1"); buf2 = alloc_lbuf("do_kill.succ.2"); if (Suspect(player)) { strcpy(buf1, Name(player)); if (player == Owner(player)) { raw_broadcast(0, WIZARD, "[Suspect] %s killed %s(#%d).", buf1, Name(victim), victim); } else { strcpy(buf2, Name(Owner(player))); raw_broadcast(0, WIZARD, "[Suspect] %s <via %s(#%d)> killed %s(#%d).", buf2, buf1, player, Name(victim), victim); } } sprintf(buf1, "You killed %s!", Name(victim)); sprintf(buf2, "killed %s!", Name(victim)); if (Typeof(victim) != TYPE_PLAYER) if (halt_que(NOTHING, victim) > 0) if (!Quiet(victim)) notify(Owner(victim), "Halted."); did_it(player, victim, A_KILL, buf1, A_OKILL, buf2, A_AKILL, (char **)NULL, 0); /* notify victim */ sprintf(buf1, "%s killed you!", Name(player)); notify_with_cause(victim, player, buf1); /* Pay off the bonus */ if (key == KILL_KILL) { cost /= 2; /* victim gets half */ if (Pennies(Owner(victim)) < mudconf.paylimit) { sprintf(buf1, "Your insurance policy pays %d %s.", cost, mudconf.many_coins); notify(victim, buf1); giveto(Owner(victim), cost, NOTHING); } else { notify(victim, "Your insurance policy has been revoked."); } } free_lbuf(buf1); free_lbuf(buf2); /* send him home */ move_via_generic(victim, HOME, NOTHING, 0); divest_object(victim); break; } }
/* * m_oper - generic message handler */ int m_oper(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct ConfItem* aconf; char* name; char* password; assert(0 != cptr); assert(cptr == sptr); name = parc > 1 ? parv[1] : 0; password = parc > 2 ? parv[2] : 0; if (EmptyString(name) || EmptyString(password)) return need_more_params(sptr, "OPER"); aconf = find_conf_exact(name, sptr, CONF_OPERATOR); if (!aconf || IsIllegal(aconf)) { send_reply(sptr, ERR_NOOPERHOST); sendto_opmask_butone(0, SNO_OLDREALOP, "Failed staff authentication attempt by %s (%s@%s)", parv[0], cli_user(sptr)->username, cli_sockhost(sptr)); return 0; } assert(0 != (aconf->status & CONF_OPERATOR)); if (oper_password_match(password, aconf->passwd)) { struct Flags old_mode = cli_flags(sptr); if (ACR_OK != attach_conf(sptr, aconf)) { send_reply(sptr, ERR_NOOPERHOST); sendto_opmask_butone(0, SNO_OLDREALOP, "Failed staff authentication attempt by %s " "(%s@%s)", parv[0], cli_user(sptr)->username, cli_sockhost(sptr)); return 0; } SetLocOp(sptr); client_set_privs(sptr, aconf); if (HasPriv(sptr, PRIV_PROPAGATE)) { ClearLocOp(sptr); SetOper(sptr); ++UserStats.opers; } cli_handler(cptr) = OPER_HANDLER; SetFlag(sptr, FLAG_WALLOP); SetFlag(sptr, FLAG_SERVNOTICE); SetFlag(sptr, FLAG_DEBUG); set_snomask(sptr, SNO_OPERDEFAULT, SNO_ADD); cli_max_sendq(sptr) = 0; /* Get the sendq from the oper's class */ send_umode_out(cptr, sptr, &old_mode, HasPriv(sptr, PRIV_PROPAGATE)); send_reply(sptr, RPL_YOUREOPER); sendto_opmask_butone(0, SNO_OLDSNO, "%s (%s@%s) has authenticated as staff", parv[0], cli_user(sptr)->username, cli_sockhost(sptr)); log_write(LS_OPER, L_INFO, 0, "OPER (%s) by (%#C)", name, sptr); } else { send_reply(sptr, ERR_PASSWDMISMATCH); sendto_opmask_butone(0, SNO_OLDREALOP, "Failed staff authentication attempt by %s (%s@%s)", parv[0], cli_user(sptr)->username, cli_sockhost(sptr)); } return 0; }
void do_join(struct Client *cptr, struct Client *sptr, struct JoinBuf *join, struct JoinBuf *create, char *chan, char *key, int level) { struct Channel *chptr; struct Gline *gline; /* BADCHANed channel */ if ((gline = gline_find(chan, GLINE_BADCHAN | GLINE_EXACT)) && GlineIsActive(gline) && !IsAnOper(sptr)) { send_reply(sptr, ERR_BANNEDFROMCHAN, chan); return; } /* Bouncy +L joins */ if (level > feature_int(FEAT_MAX_BOUNCE)) { sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :*** Couldn't join %s ! - Redirection (+L) setting was too bouncy", sptr, chan); return; } if (!(chptr = FindChannel(chan))) { if (((chan[0] == '&') && !feature_bool(FEAT_LOCAL_CHANNELS)) || strlen(chan) > IRCD_MIN(CHANNELLEN, feature_int(FEAT_CHANNELLEN))) { send_reply(sptr, ERR_NOSUCHCHANNEL, chan); return; } if (feature_bool(FEAT_CHANNEL_CREATE_IRCOPONLY) && !IsAnOper(sptr) && !IsChannelService(sptr)) { send_reply(sptr, ERR_NOSUCHCHANNEL, chan); return; } if (!(chptr = get_channel(sptr, chan, CGT_CREATE))) return; /* Try to add the new channel as a recent target for the user. */ if (check_target_limit(sptr, chptr, chptr->chname, 0)) { chptr->members = 0; destruct_channel(chptr); return; } joinbuf_join(create, chptr, CHFL_CHANOP | CHFL_CHANNEL_MANAGER); } else if (find_member_link(chptr, sptr)) { return; /* already on channel */ } else if (check_target_limit(sptr, chptr, chptr->chname, 0)) { return; } else { int flags = CHFL_DEOPPED; int err = 0; int excepted = 0; int exceptkli = 0; struct Ban *ban = NULL; if (*chptr->mode.redir && (*chptr->mode.redir != '\0')) { if (chptr->users >= chptr->mode.limit) { if (IsNoLink(sptr)) send_reply(sptr, ERR_LINKCHAN, chptr->chname, chptr->mode.redir); else if (!IsChannelName(chptr->mode.redir) || !strIsIrcCh(chptr->mode.redir)) send_reply(sptr, ERR_NOSUCHCHANNEL, chptr->mode.redir); else { send_reply(sptr, ERR_LINKSET, chptr->chname, chptr->chname, chptr->mode.redir); do_join(cptr, sptr, join, create, chptr->mode.redir, key, level+1); } return; } } if (find_ban(sptr, chptr->exceptlist, EBAN_EXCEPTLIST, 0)) { if (feature_bool(FEAT_CHMODE_e_CHMODEEXCEPTION)) exceptkli = 1; excepted = 1; } /* Check Apass/Upass -- since we only ever look at a single * "key" per channel now, this hampers brute force attacks. */ if (feature_bool(FEAT_CHMODE_Z_STRICT) && (chptr->mode.exmode & EXMODE_SSLONLY) && !IsSSL(sptr)) err = ERR_SSLONLYCHAN; else if (key && !strcmp(key, chptr->mode.apass)) flags = CHFL_CHANOP | CHFL_CHANNEL_MANAGER; else if (key && !strcmp(key, chptr->mode.upass)) flags = CHFL_CHANOP; else if (chptr->users == 0 && !chptr->mode.apass[0] && !(chptr->mode.exmode & EXMODE_PERSIST)) { /* Joining a zombie channel (zannel): give ops and increment TS. */ flags = CHFL_CHANOP; chptr->creationtime++; } else if (IsXtraOp(sptr)) { /* XtraOp bypasses all other checks. */ } else if ((chptr->mode.exmode & EXMODE_SSLONLY) && !IsSSL(sptr)) err = ERR_SSLONLYCHAN; else if (IsInvited(sptr, chptr)) { /* Invites bypass these other checks. */ } else if (*chptr->mode.key && (!key || strcmp(key, chptr->mode.key)) && !exceptkli) err = ERR_BADCHANNELKEY; else if (*chptr->mode.key && feature_bool(FEAT_FLEXIBLEKEYS) && (key && !strcmp(key, chptr->mode.key))) { /* Assume key checked by previous condition was found to be correct and allow join because FEAT_FLEXIBLEKEYS was enabled */ } else if ((chptr->mode.mode & MODE_INVITEONLY) && !exceptkli) err = ERR_INVITEONLYCHAN; else if (chptr->mode.limit && (chptr->users >= chptr->mode.limit) && !exceptkli) err = ERR_CHANNELISFULL; else if ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(sptr)) err = ERR_NEEDREGGEDNICK; else if ((chptr->mode.exmode & EXMODE_ADMINONLY) && !IsAdmin(sptr)) err = ERR_ADMINONLYCHAN; else if ((chptr->mode.exmode & EXMODE_OPERONLY) && !IsAnOper(sptr)) err = ERR_OPERONLYCHAN; else if ((ban = find_ban(sptr, chptr->banlist, EBAN_NONE, 0)) && !excepted) err = ERR_BANNEDFROMCHAN; /* An oper with WALK_LCHAN privilege can join a local channel * he otherwise could not join by using "OVERRIDE" as the key. * This will generate a HACK(4) notice, but fails if the oper * could normally join the channel. */ if (IsLocalChannel(chptr->chname) && HasPriv(sptr, PRIV_WALK_LCHAN) && !(flags & CHFL_CHANOP) && key && !strcmp(key, "OVERRIDE")) { switch (err) { case 0: if (strcmp(chptr->mode.key, "OVERRIDE") && strcmp(chptr->mode.apass, "OVERRIDE") && strcmp(chptr->mode.upass, "OVERRIDE")) { send_reply(sptr, ERR_DONTCHEAT, chptr->chname); return; } break; case ERR_INVITEONLYCHAN: err = 'i'; break; case ERR_CHANNELISFULL: err = 'l'; break; case ERR_BANNEDFROMCHAN: err = 'b'; break; case ERR_BADCHANNELKEY: err = 'k'; break; case ERR_NEEDREGGEDNICK: err = 'r'; break; case ERR_ADMINONLYCHAN: err = 'a'; break; case ERR_OPERONLYCHAN: err = 'O'; break; case ERR_SSLONLYCHAN: err = 'Z'; break; default: err = '?'; break; } /* send accountability notice */ if (err) sendto_opmask_butone(0, SNO_HACK4, "OPER JOIN: %C JOIN %H " "(overriding +%c)", sptr, chptr, err); err = 0; } /* Is there some reason the user may not join? */ if (err) { switch(err) { case ERR_NEEDREGGEDNICK: send_reply(sptr, ERR_NEEDREGGEDNICK, chptr->chname, feature_str(FEAT_URLREG)); break; default: send_reply(sptr, err, chptr->chname); break; } return; } joinbuf_join(join, chptr, flags); if (flags & CHFL_CHANOP) { struct ModeBuf mbuf; /* Always let the server op him: this is needed on a net with older servers because they 'destruct' channels immediately when they become empty without sending out a DESTRUCT message. As a result, they would always bounce a mode (as HACK(2)) when the user ops himself. (There is also no particularly good reason to have the user op himself.) */ modebuf_init(&mbuf, &me, cptr, chptr, MODEBUF_DEST_SERVER); modebuf_mode_client(&mbuf, MODE_ADD | MODE_CHANOP, sptr, chptr->mode.apass[0] ? ((flags & CHFL_CHANNEL_MANAGER) ? 0 : 1) : MAXOPLEVEL); modebuf_flush(&mbuf); } } del_invite(sptr, chptr); if (chptr->topic[0]) { send_reply(sptr, RPL_TOPIC, chptr->chname, chptr->topic); send_reply(sptr, RPL_TOPICWHOTIME, chptr->chname, chptr->topic_nick, chptr->topic_time); } do_names(sptr, chptr, NAMES_ALL|NAMES_EON); /* send /names list */ }
/* * m_kick - generic message handler * * parv[0] = sender prefix * parv[1] = channel * parv[2] = client to kick * parv[parc-1] = kick comment */ int m_kick(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { struct Client *who; struct Channel *chptr; struct Membership *member = 0; char *name, *comment; ClrFlag(sptr, FLAG_TS8); if (parc < 3 || *parv[1] == '\0') return need_more_params(sptr, "KICK"); name = parv[1]; /* simple checks */ if (!(chptr = get_channel(sptr, name, CGT_NO_CREATE))) return send_reply(sptr, ERR_NOSUCHCHANNEL, name); if (!is_chan_op(sptr, chptr) && !is_half_op(sptr, chptr)) return send_reply(sptr, ERR_CHANOPRIVSNEEDED, name); if (!(who = find_chasing(sptr, parv[2], 0))) return 0; /* find_chasing sends the reply for us */ /* Don't allow the channel service to be kicked */ /* * ASUKA_X: * Allow +X'ed users to kick +k'ed, but not U-lined services. * --Bigfoot */ if (IsChannelService(who) && IsService(cli_user(who)->server)) return send_reply(sptr, ERR_ISCHANSERVICE, cli_name(who), chptr->chname, "a network service"); if (IsChannelService(who) && !IsXtraOp(sptr) && (who!=sptr)) return send_reply(sptr, ERR_ISCHANSERVICE, cli_name(who), chptr->chname, "an IRC operator"); /* Don't allow halfops to kick chanops */ if (is_chan_op(who, chptr) && is_half_op(sptr, chptr) && !is_chan_op(sptr, chptr)) return send_reply(sptr, ERR_HALFCANTKICKOP, name); /* Prevent kicking opers from local channels -DM- */ if (IsLocalChannel(chptr->chname) && HasPriv(who, PRIV_DEOP_LCHAN)) return send_reply(sptr, ERR_ISOPERLCHAN, cli_name(who), chptr->chname); /* check if kicked user is actually on the channel */ if (!(member = find_member_link(chptr, who)) || IsZombie(member)) return send_reply(sptr, ERR_USERNOTINCHANNEL, cli_name(who), chptr->chname); /* We rely on ircd_snprintf to truncate the comment */ comment = EmptyString(parv[parc - 1]) ? parv[0] : parv[parc - 1]; if (!IsLocalChannel(name)) sendcmdto_serv_butone(sptr, CMD_KICK, cptr, "%H %C :%s", chptr, who, comment); sendcmdto_channel_butserv_butone((IsServer(sptr) ? &me : sptr), CMD_KICK, chptr, NULL, 0, "%H %C :%s", chptr, who, comment); make_zombie(member, who, cptr, sptr, chptr); return 0; }
/* * mo_jupe - oper message handler * * parv[0] = Send prefix * parv[1] = [[+|-]<server name>] * * Local (to me) style: * * parv[2] = [Expiration offset] * parv[3] = [Comment] * * Global (or remote local) style: * * parv[2] = [target] * parv[3] = [Expiration offset] * parv[4] = [Comment] * */ int mo_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; char *server = parv[1], *target = 0, *reason; if (parc < 2) return jupe_list(sptr, 0); if (*server == '+') { flags |= JUPE_ACTIVE; server++; } else if (*server == '-') server++; else return jupe_list(sptr, server); if (!feature_bool(FEAT_CONFIG_OPERCMDS)) return send_reply(sptr, ERR_DISABLED, "JUPE"); if (parc == 4) { expire_off = atoi(parv[2]); reason = parv[3]; flags |= JUPE_LOCAL; } else if (parc > 4) { target = parv[2]; expire_off = atoi(parv[3]); reason = parv[4]; } else return need_more_params(sptr, "JUPE"); if (target) { if (!(target[0] == '*' && target[1] == '\0')) { if (!(acptr = find_match_server(target))) return send_reply(sptr, ERR_NOSUCHSERVER, target); if (!IsMe(acptr)) { /* manually propagate, since we don't set it */ if (!HasPriv(sptr, PRIV_JUPE)) return send_reply(sptr, ERR_NOPRIVILEGES); sendcmdto_one(sptr, CMD_JUPE, acptr, "%C %c%s %s %Tu :%s", acptr, flags & JUPE_ACTIVE ? '+' : '-', server, parv[3], TStime(), reason); return 0; } else if (!HasPriv(sptr, PRIV_LOCAL_JUPE)) return send_reply(sptr, ERR_NOPRIVILEGES); flags |= JUPE_LOCAL; } else if (!HasPriv(sptr, PRIV_JUPE)) return send_reply(sptr, ERR_NOPRIVILEGES); } ajupe = jupe_find(server); if (ajupe) { if (JupeIsLocal(ajupe) && !(flags & JUPE_LOCAL)) /* global over local */ jupe_free(ajupe); else { if (flags & JUPE_ACTIVE) return jupe_activate(cptr, sptr, ajupe, TStime(), flags); else return jupe_deactivate(cptr, sptr, ajupe, TStime(), flags); } } return jupe_add(cptr, sptr, server, reason, expire_off, TStime(), flags); }
/** Given a feature vector string, set the value of a feature. * @param[in] from Client trying to set 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_set(struct Client* from, const char* const* fields, int count) { int i, change = 0, tmp; const char *t_str; struct FeatureDesc *feat; if (from && !HasPriv(from, PRIV_SET) && !IsServer(from)) return send_reply(from, ERR_NOPRIVILEGES); if (count < 1) { if (from) /* report an error in the number of arguments */ need_more_params(from, "SET"); else log_write(LS_CONFIG, L_ERROR, 0, "Not enough fields in F line"); } else if ((feat = feature_desc(from, fields[0]))) { /* find feature */ if (from && feat->flags & FEAT_READ) return send_reply(from, ERR_NOFEATURE, fields[0]); switch (feat_type(feat)) { case FEAT_NONE: if (feat->set && (i = (*feat->set)(from, fields + 1, count - 1))) { change++; /* feature handler wants a change recorded */ if (i > 0) /* call the set callback and do marking */ feat->flags |= FEAT_MARK; else /* i < 0 */ feat->flags &= ~FEAT_MARK; break; } case FEAT_INT: /* an integer value */ case FEAT_UINT: tmp = feat->v_int; /* detect changes... */ if (count < 2) { /* reset value */ feat->v_int = feat->def_int; feat->flags &= ~FEAT_MARK; } else { /* ok, figure out the value and whether to mark it */ feat->v_int = strtoul(fields[1], 0, 0); if (feat->v_int == feat->def_int) feat->flags &= ~FEAT_MARK; else feat->flags |= FEAT_MARK; } if (feat->v_int != tmp) /* check for change */ change++; break; case FEAT_BOOL: /* it's a boolean value--true or false */ tmp = feat->v_int; /* detect changes... */ if (count < 2) { /* reset value */ feat->v_int = feat->def_int; feat->flags &= ~FEAT_MARK; } else { /* figure out the value and whether to mark it */ if (!ircd_strncmp(fields[1], "TRUE", strlen(fields[1])) || !ircd_strncmp(fields[1], "YES", strlen(fields[1])) || (strlen(fields[1]) >= 2 && !ircd_strncmp(fields[1], "ON", strlen(fields[1])))) feat->v_int = 1; else if (!ircd_strncmp(fields[1], "FALSE", strlen(fields[1])) || !ircd_strncmp(fields[1], "NO", strlen(fields[1])) || (strlen(fields[1]) >= 2 && !ircd_strncmp(fields[1], "OFF", strlen(fields[1])))) feat->v_int = 0; else if (from) /* report an error... */ return send_reply(from, ERR_BADFEATVALUE, fields[1], feat->type); else { log_write(LS_CONFIG, L_ERROR, 0, "Bad value \"%s\" for feature %s", fields[1], feat->type); return 0; } if (feat->v_int == feat->def_int) /* figure out whether to mark it */ feat->flags &= ~FEAT_MARK; else feat->flags |= FEAT_MARK; } if (feat->v_int != tmp) /* check for change */ change++; break; case FEAT_STR: /* it's a string value */ if (count < 2) t_str = feat->def_str; /* changing to default */ else t_str = *fields[1] ? fields[1] : 0; if (!t_str && !(feat->flags & FEAT_NULL)) { /* NULL value permitted? */ if (from) return send_reply(from, ERR_BADFEATVALUE, "NULL", feat->type); else { log_write(LS_CONFIG, L_ERROR, 0, "Bad value \"NULL\" for feature %s", feat->type); return 0; } } if (t_str == feat->def_str || (t_str && feat->def_str && !(feat->flags & FEAT_CASE ? strcmp(t_str, feat->def_str) : ircd_strcmp(t_str, feat->def_str)))) { /* resetting to default */ if (feat->v_str != feat->def_str) { change++; /* change from previous value */ if (feat->v_str) MyFree(feat->v_str); /* free old value */ } feat->v_str = feat->def_str; /* very special... */ feat->flags &= ~FEAT_MARK; } else if (!t_str) { if (feat->v_str) { change++; /* change from previous value */ if (feat->v_str != feat->def_str) MyFree(feat->v_str); /* free old value */ } feat->v_str = 0; /* set it to NULL */ feat->flags |= FEAT_MARK; } else if (!feat->v_str || (feat->flags & FEAT_CASE ? strcmp(t_str, feat->v_str) : ircd_strcmp(t_str, feat->v_str))) { /* new value */ change++; /* change from previous value */ if (feat->v_str && feat->v_str != feat->def_str) MyFree(feat->v_str); /* free old value */ DupString(feat->v_str, t_str); /* store new value */ feat->flags |= FEAT_MARK; } else /* they match, but don't match the default */ feat->flags |= FEAT_MARK; break; } if (change && feat->notify) /* call change notify function */ (*feat->notify)(); if (change && from) { if(!IsServer(from) && !IsMe(from)) send_reply(from, SND_EXPLICIT | RPL_FEATURE, ":Value of %s changed", feat->type); switch (feat_type(feat)) { case FEAT_NONE: sendto_opmask_butone(0, SNO_OLDSNO, "%C changed %s", from, feat->type); break; case FEAT_INT: sendto_opmask_butone(0, SNO_OLDSNO, "%C changed %s to %d", from, feat->type, feat->v_int); break; case FEAT_BOOL: sendto_opmask_butone(0, SNO_OLDSNO, "%C changed %s to %s", from, feat->type, (feat->v_int ? "TRUE" : "FALSE")); break; case FEAT_STR: if(feat->v_str) sendto_opmask_butone(0, SNO_OLDSNO, "%C changed %s to: %s", from, feat->type, feat->v_str); else sendto_opmask_butone(0, SNO_OLDSNO, "%C unset %s", from, feat->type); break; } /* switch */ } /* if (change) */ } return 0; }