void dispose_ban( BAN_DATA * pban, int type ) { if( !pban ) return; if( type != BAN_SITE && type != BAN_CLASS && type != BAN_RACE ) { bug( "%s: Unknown Ban Type %d.", __func__, type ); return; } switch ( type ) { case BAN_SITE: UNLINK( pban, first_ban, last_ban, next, prev ); break; case BAN_CLASS: UNLINK( pban, first_ban_class, last_ban_class, next, prev ); break; case BAN_RACE: UNLINK( pban, first_ban_race, last_ban_race, next, prev ); break; } free_ban( pban ); }
void load_bans( void ) { FILE * fp; BAN_DATA *ban_last; char * site; if ( ( fp = fopen( BAN_FILE, "r" ) ) == NULL ) return ; ban_last = NULL; for ( ; ; ) { BAN_DATA *pban; if ( feof( fp ) ) { fclose( fp ); return ; } pban = new_ban(); site = fread_word( fp ); if ( !str_cmp( site, "#" ) ) { fclose( fp ); return ; } pban->site = str_dup( site ); pban->ban_flags = fread_flag( fp ); pban->person = str_dup( fread_word( fp ) ); pban->date_stamp = fread_long_number( fp ); pban->period = fread_number( fp ); pban->reason = fread_string_eol( fp ); if ( pban->period > 0 && pban->date_stamp + ( pban->period * 24 * 3600 ) <= current_time ) { free_ban( pban ); continue; } if ( ban_list == NULL ) ban_list = pban; else ban_last->next = pban; ban_last = pban; } }
/* * Unbans a site. */ void do_allow(CHAR_DATA * ch, char *argument) { char arg[MAX_INPUT_LENGTH]; char buf[MAX_STRING_LENGTH]; BAN_DATA *prev; BAN_DATA *curr; one_argument(argument, arg); if (arg[0] == '\0') { send_to_char("Remove which site from the ban list?\r\n", ch); return; } prev = NULL; for (curr = ban_list; curr != NULL; prev = curr, curr = curr->next) { if (!str_cmp(arg, curr->name)) { if (curr->level > get_trust(ch)) { send_to_char("You are not powerful enough to lift that ban.\r\n", ch); return; } if (prev == NULL) { ban_list = ban_list->next; } else { prev->next = curr->next; } free_ban(curr); sprintf(buf, "Ban on %s lifted.\r\n", arg); send_to_char(buf, ch); save_bans(); return; } } send_to_char("Site is not banned.\r\n", ch); return; } // end do_allow
/** Attempt to apply a SILENCE update to a user. * * Silences are propagated lazily between servers to save on bandwidth * and remote memory. Any removal and any silence exception must be * propagated until a server has not seen the mask being removed or * has no positive silences for the user. * * @param[in] sptr Client to update. * @param[in] mask Single silence mask to apply, optionally preceded by '+' or '-' and maybe '~'. * @return The new ban entry on success, NULL on failure. */ static struct Ban * apply_silence(struct Client *sptr, char *mask) { struct Ban *sile; int flags; int res; char orig_mask[NICKLEN+USERLEN+HOSTLEN+3]; assert(mask && mask[0]); /* Check for add or remove. */ if (mask[0] == '-') { flags = BAN_DEL; mask++; } else if (mask[0] == '+') { flags = BAN_ADD; mask++; } else flags = BAN_ADD; /* Check for being an exception. */ if (mask[0] == '~') { flags |= BAN_EXCEPTION; mask++; } /* Make the silence and set additional flags. */ ircd_strncpy(orig_mask, mask, sizeof(orig_mask) - 1); sile = make_ban(pretty_mask(mask)); sile->flags |= flags; /* If they're a local user trying to ban too broad a mask, forbid it. */ if (MyUser(sptr) && (sile->flags & BAN_IPMASK) && sile->addrbits > 0 && sile->addrbits < (irc_in_addr_is_ipv4(&sile->address) ? 112 : 32)) { send_reply(sptr, ERR_MASKTOOWIDE, orig_mask); free_ban(sile); return NULL; } /* Apply it to the silence list. */ res = apply_ban(&cli_user(sptr)->silence, sile, 1); return res ? NULL : sile; }
/* * del_listmode - delete a listmode (+beI) from a channel * that matches the specified banid. */ int del_listmode(Ban **list, aChannel *chptr, char *banid) { Ban **ban; Ban *tmp; if (!banid) return -1; for (ban = list; *ban; ban = &((*ban)->next)) { if (mycmp(banid, (*ban)->banstr) == 0) { tmp = *ban; *ban = tmp->next; MyFree(tmp->banstr); MyFree(tmp->who); free_ban(tmp); return 0; } } return -1; }
void update_bans() { BAN_DATA *prev; BAN_DATA *curr; prev = NULL; for ( curr = ban_list; curr != NULL; prev = curr, curr = curr->next ) { if ( curr->period > 0 && curr->date_stamp + ( curr->period * 24 * 3600 ) <= current_time ) { if ( prev == NULL ) ban_list = ban_list->next; else prev->next = curr->next; free_ban( curr ); save_bans(); return ; } } return ; }
void do_allow( CHAR_DATA *ch, char *argument ) { char arg[ MAX_INPUT_LENGTH ]; char buf[ MAX_STRING_LENGTH ]; BAN_DATA *prev; BAN_DATA *curr; one_argument( argument, arg ); if ( arg[ 0 ] == '\0' ) { send_to_char( "Który ban usun±æ z listy?\n\r", ch ); return ; } prev = NULL; for ( curr = ban_list; curr != NULL; prev = curr, curr = curr->next ) { if ( !str_cmp( arg, curr->site ) ) { if ( prev == NULL ) ban_list = ban_list->next; else prev->next = curr->next; free_ban( curr ); sprintf( buf, "Ban na adres %s zdjêty.\n\r", arg ); send_to_char( buf, ch ); save_bans(); return ; } } send_to_char( "Tego adresu nie ma na li¶cie banów.\n\r", ch ); return ; }
/* * ms_burst - server message handler * * -- by Run [email protected] december 1995 till march 1997 * * parv[0] = sender prefix * parv[1] = channel name * parv[2] = channel timestamp * The meaning of the following parv[]'s depend on their first character: * If parv[n] starts with a '+': * Net burst, additive modes * parv[n] = <mode> * parv[n+1] = <param> (optional) * parv[n+2] = <param> (optional) * If parv[n] starts with a '%', then n will be parc-1: * parv[n] = %<ban> <ban> <ban> ... * If parv[n] starts with another character: * parv[n] = <nick>[:<mode>],<nick>[:<mode>],... * where <mode> defines the mode and op-level * for nick and all following nicks until the * next <mode> field. * Digits in the <mode> field have of two meanings: * 1) if it is the first field in this BURST message * that contains digits, and/or when a 'v' is * present in the <mode>: * The absolute value of the op-level. * 2) if there are only digits in this field and * it is not the first field with digits: * An op-level increment relative to the previous * op-level. * First all modeless nicks must be emmitted, * then all combinations of modes without ops * (currently that is only 'v') followed by the same * series but then with ops (currently 'o','ov'). * * Example: * "A8 B #test 87654321 +ntkAl key secret 123 A8AAG,A8AAC:v,A8AAA:0,A8AAF:2,A8AAD,A8AAB:v1,A8AAE:1 :%ban1 ban2" * * <mode> list example: * * "xxx,sss:v,ttt,aaa:123,bbb,ccc:2,ddd,kkk:v2,lll:2,mmm" * * means * * xxx // first modeless nicks * sss +v // then opless nicks * ttt +v // no ":<mode>": everything stays the same * aaa -123 // first field with digit: absolute value * bbb -123 * ccc -125 // only digits, not first field: increment * ddd -125 * kkk -2 +v // field with a 'v': absolute value * lll -4 +v // only digits: increment * mmm -4 +v * * Anti net.ride code. * * When the channel already exist, and its TS is larger than * the TS in the BURST message, then we cancel all existing modes. * If its is smaller then the received BURST message is ignored. * If it's equal, then the received modes are just added. * * BURST is also accepted outside a netburst now because it * is sent upstream as reaction to a DESTRUCT message. For * these BURST messages it is possible that the listed channel * members are already joined. */ int ms_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { struct ModeBuf modebuf, *mbuf = 0; struct Channel *chptr; time_t timestamp; struct Membership *member, *nmember; struct Ban *lp, **lp_p; unsigned int parse_flags = (MODE_PARSE_FORCE | MODE_PARSE_BURST); int param, nickpos = 0, banpos = 0; char modestr[BUFSIZE], nickstr[BUFSIZE], banstr[BUFSIZE]; if (parc < 3) return protocol_violation(sptr,"Too few parameters for BURST"); if (!(chptr = get_channel(sptr, parv[1], CGT_CREATE))) return 0; /* can't create the channel? */ timestamp = atoi(parv[2]); if (chptr->creationtime) /* 0 for new (empty) channels, i.e. when this server just restarted. */ { if (parc == 3) /* Zannel BURST? */ { /* An empty channel without +A set, will cause a BURST message with exactly 3 parameters (because all modes have been reset). If the timestamp on such channels is only a few seconds older from our own, then we ignore this burst: we do not deop our own side. Likewise, we expect the other (empty) side to copy our timestamp from our own BURST message, even though it is slightly larger. The reason for this is to allow people to join an empty non-A channel (a zannel) during a net.split, and not be deopped when the net reconnects (with another zannel). When someone joins a split zannel, their side increments the TS by one. If they cycle a few times then we still don't have a reason to deop them. Theoretically I see no reason not to accept ANY timestamp, but to be sure, we only accept timestamps that are just a few seconds off (one second for each time they cycled the channel). */ /* Don't even deop users who cycled four times during the net.break. */ if (timestamp < chptr->creationtime && chptr->creationtime <= timestamp + 4 && chptr->users != 0) /* Only do this when WE have users, so that if we do this the BURST that we sent has parc > 3 and the other side will use the test below: */ timestamp = chptr->creationtime; /* Do not deop our side. */ } else if (chptr->creationtime < timestamp && timestamp <= chptr->creationtime + 4 && chptr->users == 0) { /* If one side of the net.junction does the above timestamp = chptr->creationtime, then the other side must do this: */ chptr->creationtime = timestamp; /* Use the same TS on both sides. */ } /* In more complex cases, we might still end up with a creationtime desync of a few seconds, but that should be synced automatically rather quickly (every JOIN caries a timestamp and will sync it; modes by users do not carry timestamps and are accepted regardless). Only when nobody joins the channel on the side with the oldest timestamp before a new net.break occurs precisely inbetween the desync, an unexpected bounce might happen on reconnect. */ } if (!chptr->creationtime || chptr->creationtime > timestamp) { /* * Kick local members if channel is +i or +k and our TS was larger * than the burst TS (anti net.ride). The modes hack is here because * we have to do this before mode_parse, as chptr may go away. */ for (param = 3; param < parc; param++) { int check_modes; if (parv[param][0] != '+') continue; check_modes = netride_modes(parc - param, parv + param, chptr->mode.key); if (check_modes < 0) { if (chptr->users == 0) sub1_from_channel(chptr); return protocol_violation(sptr, "Invalid mode string in BURST"); } else if (check_modes) { /* Clear any outstanding rogue invites */ mode_invite_clear(chptr); for (member = chptr->members; member; member = nmember) { nmember = member->next_member; if (!MyUser(member->user) || IsZombie(member)) continue; /* Kick as netrider if key mismatch *or* remote channel is * +i (unless user is an oper) *or* remote channel is +r * (unless user has an account). */ if (!(check_modes & MODE_KEY) && (!(check_modes & MODE_INVITEONLY) || IsAnOper(member->user)) && (!(check_modes & MODE_REGONLY) || IsAccount(member->user))) continue; sendcmdto_serv_butone(&me, CMD_KICK, NULL, "%H %C :Net Rider", chptr, member->user); sendcmdto_channel_butserv_butone(&his, CMD_KICK, chptr, NULL, 0, "%H %C :Net Rider", chptr, member->user); make_zombie(member, member->user, &me, &me, chptr); } } break; } /* If the channel had only locals, it went away by now. */ if (!(chptr = get_channel(sptr, parv[1], CGT_CREATE))) return 0; /* can't create the channel? */ } /* turn off burst joined flag */ for (member = chptr->members; member; member = member->next_member) member->status &= ~(CHFL_BURST_JOINED|CHFL_BURST_ALREADY_OPPED|CHFL_BURST_ALREADY_VOICED); if (!chptr->creationtime) /* mark channel as created during BURST */ chptr->mode.mode |= MODE_BURSTADDED; /* new channel or an older one */ if (!chptr->creationtime || chptr->creationtime > timestamp) { chptr->creationtime = timestamp; modebuf_init(mbuf = &modebuf, &me, cptr, chptr, MODEBUF_DEST_CHANNEL | MODEBUF_DEST_NOKEY); modebuf_mode(mbuf, MODE_DEL | chptr->mode.mode); /* wipeout modes */ chptr->mode.mode &= MODE_BURSTADDED | MODE_WASDELJOINS; /* wipe out modes not represented in chptr->mode.mode */ if (chptr->mode.limit) { modebuf_mode_uint(mbuf, MODE_DEL | MODE_LIMIT, chptr->mode.limit); chptr->mode.limit = 0; } if (chptr->mode.key[0]) { modebuf_mode_string(mbuf, MODE_DEL | MODE_KEY, chptr->mode.key, 0); chptr->mode.key[0] = '\0'; } if (chptr->mode.upass[0]) { modebuf_mode_string(mbuf, MODE_DEL | MODE_UPASS, chptr->mode.upass, 0); chptr->mode.upass[0] = '\0'; } if (chptr->mode.apass[0]) { modebuf_mode_string(mbuf, MODE_DEL | MODE_APASS, chptr->mode.apass, 0); chptr->mode.apass[0] = '\0'; } parse_flags |= (MODE_PARSE_SET | MODE_PARSE_WIPEOUT); /* wipeout keys */ /* mark bans for wipeout */ for (lp = chptr->banlist; lp; lp = lp->next) lp->flags |= BAN_BURST_WIPEOUT; /* clear topic set by netrider (if set) */ if (*chptr->topic) { *chptr->topic = '\0'; *chptr->topic_nick = '\0'; chptr->topic_time = 0; sendcmdto_channel_butserv_butone(&his, CMD_TOPIC, chptr, NULL, 0, "%H :%s", chptr, chptr->topic); } } else if (chptr->creationtime == timestamp) { modebuf_init(mbuf = &modebuf, &me, cptr, chptr, MODEBUF_DEST_CHANNEL | MODEBUF_DEST_NOKEY); parse_flags |= MODE_PARSE_SET; /* set new modes */ } param = 3; /* parse parameters */ while (param < parc) { switch (*parv[param]) { case '+': /* parameter introduces a mode string */ param += mode_parse(mbuf, cptr, sptr, chptr, parc - param, parv + param, parse_flags, NULL); break; case '%': /* parameter contains bans */ if (parse_flags & MODE_PARSE_SET) { char *banlist = parv[param] + 1, *p = 0, *ban, *ptr; struct Ban *newban; for (ban = ircd_strtok(&p, banlist, " "); ban; ban = ircd_strtok(&p, 0, " ")) { ban = collapse(pretty_mask(ban)); /* * Yeah, we should probably do this elsewhere, and make it better * and more general; this will hold until we get there, though. * I dislike the current add_banid API... -Kev * * I wish there were a better algo. for this than the n^2 one * shown below *sigh* */ for (lp = chptr->banlist; lp; lp = lp->next) { if (!ircd_strcmp(lp->banstr, ban)) { ban = 0; /* don't add ban */ lp->flags &= ~BAN_BURST_WIPEOUT; /* not wiping out */ break; /* new ban already existed; don't even repropagate */ } else if (!(lp->flags & BAN_BURST_WIPEOUT) && !mmatch(lp->banstr, ban)) { ban = 0; /* don't add ban unless wiping out bans */ break; /* new ban is encompassed by an existing one; drop */ } else if (!mmatch(ban, lp->banstr)) lp->flags |= BAN_OVERLAPPED; /* remove overlapping ban */ if (!lp->next) break; } if (ban) { /* add the new ban to the end of the list */ /* Build ban buffer */ if (!banpos) { banstr[banpos++] = ' '; banstr[banpos++] = ':'; banstr[banpos++] = '%'; } else banstr[banpos++] = ' '; for (ptr = ban; *ptr; ptr++) /* add ban to buffer */ banstr[banpos++] = *ptr; newban = make_ban(ban); /* create new ban */ strcpy(newban->who, "*"); newban->when = TStime(); newban->flags |= BAN_BURSTED; newban->next = 0; if (lp) lp->next = newban; /* link it in */ else chptr->banlist = newban; } } } param++; /* look at next param */ break; default: /* parameter contains clients */ { struct Client *acptr; char *nicklist = parv[param], *p = 0, *nick, *ptr; int current_mode, last_mode, base_mode; int oplevel = -1; /* Mark first field with digits: means the same as 'o' (but with level). */ int last_oplevel = 0; struct Membership* member; base_mode = CHFL_DEOPPED | CHFL_BURST_JOINED; if (chptr->mode.mode & MODE_DELJOINS) base_mode |= CHFL_DELAYED; current_mode = last_mode = base_mode; for (nick = ircd_strtok(&p, nicklist, ","); nick; nick = ircd_strtok(&p, 0, ",")) { if ((ptr = strchr(nick, ':'))) { /* new flags; deal */ *ptr++ = '\0'; if (parse_flags & MODE_PARSE_SET) { int current_mode_needs_reset; for (current_mode_needs_reset = 1; *ptr; ptr++) { if (*ptr == 'o') { /* has oper status */ /* * An 'o' is pre-oplevel protocol, so this is only for * backwards compatibility. Give them an op-level of * MAXOPLEVEL so everyone can deop them. */ oplevel = MAXOPLEVEL; if (current_mode_needs_reset) { current_mode = base_mode; current_mode_needs_reset = 0; } current_mode = (current_mode & ~(CHFL_DEOPPED | CHFL_DELAYED)) | CHFL_CHANOP; /* * Older servers may send XXYYY:ov, in which case we * do not want to use the code for 'v' below. */ if (ptr[1] == 'v') { current_mode |= CHFL_VOICE; ptr++; } } else if (*ptr == 'v') { /* has voice status */ if (current_mode_needs_reset) { current_mode = base_mode; current_mode_needs_reset = 0; } current_mode = (current_mode & ~CHFL_DELAYED) | CHFL_VOICE; oplevel = -1; /* subsequent digits are an absolute op-level value. */ } else if (IsDigit(*ptr)) { int level_increment = 0; if (oplevel == -1) { /* op-level is absolute value? */ if (current_mode_needs_reset) { current_mode = base_mode; current_mode_needs_reset = 0; } oplevel = 0; } current_mode = (current_mode & ~(CHFL_DEOPPED | CHFL_DELAYED)) | CHFL_CHANOP; do { level_increment = 10 * level_increment + *ptr++ - '0'; } while (IsDigit(*ptr)); oplevel += level_increment; } else /* I don't recognize that flag */ break; /* so stop processing */ } } } if (!(acptr = findNUser(nick)) || cli_from(acptr) != cptr) continue; /* ignore this client */ /* Build nick buffer */ nickstr[nickpos] = nickpos ? ',' : ' '; /* first char */ nickpos++; for (ptr = nick; *ptr; ptr++) /* store nick */ nickstr[nickpos++] = *ptr; if (current_mode != last_mode) { /* if mode changed... */ last_mode = current_mode; last_oplevel = oplevel; nickstr[nickpos++] = ':'; /* add a specifier */ if (current_mode & CHFL_VOICE) nickstr[nickpos++] = 'v'; if (current_mode & CHFL_CHANOP) { if (chptr->mode.apass[0]) nickpos += ircd_snprintf(0, nickstr + nickpos, sizeof(nickstr) - nickpos, "%u", oplevel); else nickstr[nickpos++] = 'o'; } } else if (current_mode & CHFL_CHANOP && oplevel != last_oplevel) { /* if just op level changed... */ nickstr[nickpos++] = ':'; /* add a specifier */ nickpos += ircd_snprintf(0, nickstr + nickpos, sizeof(nickstr) - nickpos, "%u", oplevel - last_oplevel); last_oplevel = oplevel; } if (!(member = find_member_link(chptr, acptr))) { add_user_to_channel(chptr, acptr, current_mode, oplevel); if (!(current_mode & CHFL_DELAYED)) sendcmdto_channel_butserv_butone(acptr, CMD_JOIN, chptr, NULL, 0, "%H", chptr); } else { /* The member was already joined (either by CREATE or JOIN). Remember the current mode. */ if (member->status & CHFL_CHANOP) member->status |= CHFL_BURST_ALREADY_OPPED; if (member->status & CHFL_VOICE) member->status |= CHFL_BURST_ALREADY_VOICED; /* Synchronize with the burst. */ member->status |= CHFL_BURST_JOINED | (current_mode & (CHFL_CHANOP|CHFL_VOICE)); SetOpLevel(member, oplevel); } } } param++; break; } /* switch (*parv[param]) */ } /* while (param < parc) */ nickstr[nickpos] = '\0'; banstr[banpos] = '\0'; if (parse_flags & MODE_PARSE_SET) { modebuf_extract(mbuf, modestr + 1); /* for sending BURST onward */ modestr[0] = modestr[1] ? ' ' : '\0'; } else modestr[0] = '\0'; sendcmdto_serv_butone(sptr, CMD_BURST, cptr, "%H %Tu%s%s%s", chptr, chptr->creationtime, modestr, nickstr, banstr); if (parse_flags & MODE_PARSE_WIPEOUT || banpos) mode_ban_invalidate(chptr); if (parse_flags & MODE_PARSE_SET) { /* any modes changed? */ /* first deal with channel members */ for (member = chptr->members; member; member = member->next_member) { if (member->status & CHFL_BURST_JOINED) { /* joined during burst */ if ((member->status & CHFL_CHANOP) && !(member->status & CHFL_BURST_ALREADY_OPPED)) modebuf_mode_client(mbuf, MODE_ADD | CHFL_CHANOP, member->user, OpLevel(member)); if ((member->status & CHFL_VOICE) && !(member->status & CHFL_BURST_ALREADY_VOICED)) modebuf_mode_client(mbuf, MODE_ADD | CHFL_VOICE, member->user, OpLevel(member)); } else if (parse_flags & MODE_PARSE_WIPEOUT) { /* wipeout old ops */ if (member->status & CHFL_CHANOP) modebuf_mode_client(mbuf, MODE_DEL | CHFL_CHANOP, member->user, OpLevel(member)); if (member->status & CHFL_VOICE) modebuf_mode_client(mbuf, MODE_DEL | CHFL_VOICE, member->user, OpLevel(member)); member->status = (member->status & ~(CHFL_CHANNEL_MANAGER | CHFL_CHANOP | CHFL_VOICE)) | CHFL_DEOPPED; } } /* Now deal with channel bans */ lp_p = &chptr->banlist; while (*lp_p) { lp = *lp_p; /* remove ban from channel */ if (lp->flags & (BAN_OVERLAPPED | BAN_BURST_WIPEOUT)) { char *bandup; DupString(bandup, lp->banstr); modebuf_mode_string(mbuf, MODE_DEL | MODE_BAN, bandup, 1); *lp_p = lp->next; /* clip out of list */ free_ban(lp); continue; } else if (lp->flags & BAN_BURSTED) /* add ban to channel */ modebuf_mode_string(mbuf, MODE_ADD | MODE_BAN, lp->banstr, 0); /* don't free banstr */ lp->flags &= BAN_IPMASK; /* reset the flag */ lp_p = &(*lp_p)->next; } } return mbuf ? modebuf_flush(mbuf) : 0; }
void ban_site( CHAR_DATA *ch, char *argument ) { char date[ 50 ]; struct tm *btime; char buf[ MAX_STRING_LENGTH ], buf2[ MAX_STRING_LENGTH ], buf3[ MAX_STRING_LENGTH ]; char arg1[ MAX_INPUT_LENGTH ], arg2[ MAX_INPUT_LENGTH ], arg3[ MAX_INPUT_LENGTH ]; char *name; BUFFER *buffer; BAN_DATA *pban, *prev; bool prefix = FALSE, suffix = FALSE; int type; argument = one_argument( argument, arg1 ); argument = one_argument( argument, arg2 ); argument = one_argument( argument, arg3 ); if ( arg1[ 0 ] == '\0' ) { if ( ban_list == NULL ) { send_to_char( "Nie ma ¿adnych banów.\n\r", ch ); return ; } buffer = new_buf(); add_buf( buffer, "{CAdres Kto Typ{x\n\r" ); for ( pban = ban_list;pban != NULL;pban = pban->next ) { sprintf( buf2, "%s%s%s", IS_SET( pban->ban_flags, BAN_PREFIX ) ? "*" : "", pban->site, IS_SET( pban->ban_flags, BAN_SUFFIX ) ? "*" : "" ); btime = localtime( &pban->date_stamp ); strftime( date, 20, "%d-%m-%Y %H:%M:%S", btime ); if ( pban->period <= 0 ) sprintf( buf3, "od %s na sta³e", date ); else if ( pban->period == 1 ) sprintf( buf3, "od %s na 1 dzieñ", date ); else sprintf( buf3, "od %s na %d dni", date, pban->period ); sprintf( buf, "{Y%-40s{x %-10s %-7s\n\r{CCzas{x: %s\n\r{CPowód{x: %s\n\r", buf2, pban->person, IS_SET( pban->ban_flags, BAN_NEWBIES ) ? "newbies" : IS_SET( pban->ban_flags, BAN_PERMIT ) ? "permit" : IS_SET( pban->ban_flags, BAN_ALL ) ? "all" : "", buf3, IS_NULLSTR(pban->reason) ? "nie podano" : pban->reason ); add_buf( buffer, buf ); if ( pban->next ) add_buf( buffer, "\n\r" ); } add_buf( buffer, "\n\rDodanie nowego bana:\n\r" ); add_buf( buffer, "permban [*]<adres>[*] all|newbies|permit <ile dni> [<powod>]\n\r" ); add_buf( buffer, "- podanie 0 przy liczbie dni oznacza ban na sta³e\n\r" ); page_to_char( buf_string( buffer ), ch ); free_buf( buffer ); return ; } /* find out what type of ban */ if ( !str_prefix( arg2, "permit" ) ) type = BAN_PERMIT; else if ( !str_prefix( arg2, "newbies" ) ) type = BAN_NEWBIES; else if ( !str_prefix( arg2, "all" ) ) type = BAN_ALL; else { send_to_char( "Dopuszczalne typy bana to: all, newbies, permit.\n\r", ch ); return ; } name = arg1; if ( name[ 0 ] == '*' ) { prefix = TRUE; name++; } if ( name[ strlen( name ) - 1 ] == '*' ) { suffix = TRUE; name[ strlen( name ) - 1 ] = '\0'; } if ( strlen( name ) == 0 ) { send_to_char( "Nie poda³e¶ adresu do zbanowania.\n\r", ch ); return ; } if ( arg3[0] == '\0' || !is_number( arg3 ) ) { send_to_char( "Podaj liczbê dni przez jak± ma trwaæ ban (0 - ca³y czas).\n\r", ch ); return; } prev = NULL; for ( pban = ban_list; pban != NULL; prev = pban, pban = pban->next ) { if ( !str_cmp( name, pban->site ) ) { if ( prev == NULL ) ban_list = pban->next; else prev->next = pban->next; free_ban( pban ); } } pban = new_ban(); pban->site = str_dup( name ); pban->person = str_dup( ch->name ); pban->date_stamp = current_time; pban->period = UMAX( 0, atoi( arg3 ) ); pban->reason = str_dup( argument ); /* set ban type */ pban->ban_flags = type; if ( prefix ) SET_BIT( pban->ban_flags, BAN_PREFIX ); if ( suffix ) SET_BIT( pban->ban_flags, BAN_SUFFIX ); pban->next = ban_list; ban_list = pban; save_bans(); sprintf( buf, "Adres %s zosta³ dodany do listy banów.\n\r", pban->site ); send_to_char( buf, ch ); return ; }
void ban_site(CHAR_DATA *ch, char *argument, bool fPerm) { char buf[MAX_STRING_LENGTH],buf2[MAX_STRING_LENGTH]; char arg1[MAX_INPUT_LENGTH], arg2[MAX_INPUT_LENGTH]; char *name; BUFFER *buffer; BAN_DATA *pban, *prev; bool prefix = FALSE,suffix = FALSE; int type; argument = one_argument(argument,arg1); argument = one_argument(argument,arg2); if ( arg1[0] == '\0' ) { if (ban_list == NULL) { send_to_char("No sites banned at this time.\n\r",ch); return; } buffer = new_buf(); add_buf(buffer,"Banned sites level type status\n\r"); for (pban = ban_list;pban != NULL;pban = pban->next) { sprintf(buf2,"%s%s%s", IS_SET(pban->ban_flags,BAN_PREFIX) ? "*" : "", pban->name, IS_SET(pban->ban_flags,BAN_SUFFIX) ? "*" : ""); sprintf(buf,"%-12s %-3d %-7s %s\n\r", buf2, pban->level, IS_SET(pban->ban_flags,BAN_NEWBIES) ? "newbies" : IS_SET(pban->ban_flags,BAN_MULTI) ? "multi" : IS_SET(pban->ban_flags,BAN_PERMIT) ? "permit" : IS_SET(pban->ban_flags,BAN_ALL) ? "all" : "", IS_SET(pban->ban_flags,BAN_PERMANENT) ? "perm" : "temp"); add_buf(buffer,buf); } page_to_char( buf_string(buffer), ch ); free_buf(buffer); return; } /* find out what type of ban */ if (arg2[0] == '\0' || !str_prefix(arg2,"all")) type = BAN_ALL; else if (!str_prefix(arg2,"newbies")) type = BAN_NEWBIES; else if (!str_prefix(arg2,"multi")) type = BAN_MULTI; else if (!str_prefix(arg2,"permit")) type = BAN_PERMIT; else { send_to_char("Acceptable ban types are all, newbies, and permit, and multi.\n\r", ch); return; } name = arg1; if (name[0] == '*') { prefix = TRUE; name++; } if (name[strlen(name) - 1] == '*') { suffix = TRUE; name[strlen(name) - 1] = '\0'; } if (strlen(name) == 0) { send_to_char("You have to ban SOMETHING.\n\r",ch); return; } prev = NULL; for ( pban = ban_list; pban != NULL; prev = pban, pban = pban->next ) { if (!str_cmp(name,pban->name)) { if (pban->level > get_trust(ch)) { send_to_char( "That ban was set by a higher power.\n\r", ch ); return; } else { if (prev == NULL) ban_list = pban->next; else prev->next = pban->next; free_ban(pban); } } } pban = new_ban(); pban->name = str_dup(name); pban->level = get_trust(ch); /* set ban type */ pban->ban_flags = type; if (prefix) SET_BIT(pban->ban_flags,BAN_PREFIX); if (suffix) SET_BIT(pban->ban_flags,BAN_SUFFIX); if (fPerm) SET_BIT(pban->ban_flags,BAN_PERMANENT); pban->next = ban_list; ban_list = pban; save_bans(); sprintf(buf,"%s has been banned.\n\r",pban->name); send_to_char( buf, ch ); return; }
/* * do_clearmode(struct Client *cptr, struct Client *sptr, * struct Channel *chptr, char *control) * * This is the function that actually clears the channel modes. */ static int do_clearmode(struct Client *cptr, struct Client *sptr, struct Channel *chptr, char *control) { static int flags[] = { MODE_CHANOP, 'o', MODE_VOICE, 'v', MODE_PRIVATE, 'p', MODE_SECRET, 's', MODE_MODERATED, 'm', MODE_TOPICLIMIT, 't', MODE_INVITEONLY, 'i', MODE_NOPRIVMSGS, 'n', MODE_KEY, 'k', MODE_BAN, 'b', MODE_LIMIT, 'l', MODE_REGONLY, 'r', MODE_DELJOINS, 'D', 0x0, 0x0 }; int *flag_p; unsigned int del_mode = 0; char control_buf[20]; int control_buf_i = 0; struct ModeBuf mbuf; struct Ban *link, *next; struct Membership *member; /* Ok, so what are we supposed to get rid of? */ for (; *control; control++) { for (flag_p = flags; flag_p[0]; flag_p += 2) if (*control == flag_p[1]) { del_mode |= flag_p[0]; break; } } if (!del_mode) return 0; /* nothing to remove; ho hum. */ modebuf_init(&mbuf, sptr, cptr, chptr, (MODEBUF_DEST_CHANNEL | /* Send MODE to channel */ MODEBUF_DEST_OPMODE | /* Treat it like an OPMODE */ MODEBUF_DEST_HACK4)); /* Generate a HACK(4) notice */ modebuf_mode(&mbuf, MODE_DEL | (del_mode & chptr->mode.mode)); chptr->mode.mode &= ~del_mode; /* and of course actually delete them */ /* If we're removing invite, remove all the invites */ if (del_mode & MODE_INVITEONLY) mode_invite_clear(chptr); /* * If we're removing the key, note that; note that we can't clear * the key until after modebuf_* are done with it */ if (del_mode & MODE_KEY && *chptr->mode.key) modebuf_mode_string(&mbuf, MODE_DEL | MODE_KEY, chptr->mode.key, 0); /* If we're removing the limit, note that and clear the limit */ if (del_mode & MODE_LIMIT && chptr->mode.limit) { modebuf_mode_uint(&mbuf, MODE_DEL | MODE_LIMIT, chptr->mode.limit); chptr->mode.limit = 0; /* not referenced, so safe */ } /* * Go through and mark the bans for deletion; note that we can't * free them until after modebuf_* are done with them */ if (del_mode & MODE_BAN) { for (link = chptr->banlist; link; link = next) { char *bandup; next = link->next; DupString(bandup, link->banstr); modebuf_mode_string(&mbuf, MODE_DEL | MODE_BAN, /* delete ban */ bandup, 1); free_ban(link); } chptr->banlist = 0; } /* Deal with users on the channel */ if (del_mode & (MODE_BAN | MODE_CHANOP | MODE_VOICE)) for (member = chptr->members; member; member = member->next_member) { if (IsZombie(member)) /* we ignore zombies */ continue; if (del_mode & MODE_BAN) /* If we cleared bans, clear the valid flags */ ClearBanValid(member); /* Drop channel operator status */ if (IsChanOp(member) && del_mode & MODE_CHANOP) { modebuf_mode_client(&mbuf, MODE_DEL | MODE_CHANOP, member->user, MAXOPLEVEL + 1); member->status &= ~CHFL_CHANOP; } /* Drop voice */ if (HasVoice(member) && del_mode & MODE_VOICE) { modebuf_mode_client(&mbuf, MODE_DEL | MODE_VOICE, member->user, MAXOPLEVEL + 1); member->status &= ~CHFL_VOICE; } } /* And flush the modes to the channel */ modebuf_flush(&mbuf); /* Finally, we can clear the key... */ if (del_mode & MODE_KEY) chptr->mode.key[0] = '\0'; /* Ok, build control string again */ for (flag_p = flags; flag_p[0]; flag_p += 2) if (del_mode & flag_p[0]) control_buf[control_buf_i++] = flag_p[1]; control_buf[control_buf_i] = '\0'; /* Log it... */ log_write(LS_OPERMODE, L_INFO, LOG_NOSNOTICE, "%#C CLEARMODE %H %s", sptr, chptr, control_buf); /* Then send it */ if (!IsLocalChannel(chptr->chname)) sendcmdto_serv_butone(sptr, CMD_CLEARMODE, cptr, "%H %s", chptr, control_buf); return 0; }
/* ** Subtract one user from channel i (and free channel ** block, if channel became empty). */ void sub1_from_channel(aChannel *chptr) { Ban *ban; Link *lp; /* if (--chptr->users <= 0) */ if (chptr->users == 0 || --chptr->users == 0) { /* * Now, find all invite links from channel structure */ RunHook(HOOKTYPE_CHANNEL_DESTROY, chptr); while ((lp = chptr->invites)) del_invite(lp->value.cptr, chptr); while (chptr->banlist) { ban = chptr->banlist; chptr->banlist = ban->next; MyFree(ban->banstr); MyFree(ban->who); free_ban(ban); } while (chptr->exlist) { ban = chptr->exlist; chptr->exlist = ban->next; MyFree(ban->banstr); MyFree(ban->who); free_ban(ban); } while (chptr->invexlist) { ban = chptr->invexlist; chptr->invexlist = ban->next; MyFree(ban->banstr); MyFree(ban->who); free_ban(ban); } #ifdef EXTCMODE /* free extcmode params */ extcmode_free_paramlist(chptr->mode.extmodeparam); chptr->mode.extmodeparam = NULL; #endif #ifdef NEWCHFLOODPROT chanfloodtimer_stopchantimers(chptr); if (chptr->mode.floodprot) MyFree(chptr->mode.floodprot); #endif #ifdef JOINTHROTTLE cmodej_delchannelentries(chptr); #endif if (chptr->topic) MyFree(chptr->topic); if (chptr->topic_nick) MyFree(chptr->topic_nick); if (chptr->prevch) chptr->prevch->nextch = chptr->nextch; else channel = chptr->nextch; if (chptr->nextch) chptr->nextch->prevch = chptr->prevch; (void)del_from_channel_hash_table(chptr->chname, chptr); IRCstats.channels--; MyFree((char *)chptr); } }
/** Apply and send silence updates for a user. * @param[in] sptr Client whose silence list has been updated. * @param[in] silences Comma-separated list of silence updates. * @param[in] dest Direction to send updates in (NULL for broadcast). */ static void forward_silences(struct Client *sptr, char *silences, struct Client *dest) { struct Ban *accepted[MAXPARA], *sile, **plast; char *cp, *p, buf[BUFSIZE]; size_t ac_count, buf_used, slen, ii; /* Split the list of silences and try to apply each one in turn. */ for (cp = ircd_strtok(&p, silences, ","), ac_count = 0; cp && (ac_count < MAXPARA); cp = ircd_strtok(&p, 0, ",")) { if ((sile = apply_silence(sptr, cp))) accepted[ac_count++] = sile; } if (MyUser(sptr)) { size_t siles, maxsiles, totlength, maxlength, jj; /* Check that silence count and total length are permitted. */ maxsiles = feature_int(FEAT_MAXSILES); maxlength = maxsiles * feature_int(FEAT_AVBANLEN); siles = totlength = 0; /* Count number of current silences and their total length. */ plast = &cli_user(sptr)->silence; for (sile = cli_user(sptr)->silence; sile; sile = sile->next) { if (sile->flags & (BAN_OVERLAPPED | BAN_ADD | BAN_DEL)) continue; siles++; totlength += strlen(sile->banstr); plast = &sile->next; } for (ii = jj = 0; ii < ac_count; ++ii) { sile = accepted[ii]; /* If the update is being added, and we would exceed the maximum * count or length, drop the update. */ if (!(sile->flags & (BAN_OVERLAPPED | BAN_DEL))) { slen = strlen(sile->banstr); if ((siles >= maxsiles) || (totlength + slen >= maxlength)) { *plast = NULL; if (MyUser(sptr)) send_reply(sptr, ERR_SILELISTFULL, accepted[ii]->banstr); free_ban(accepted[ii]); continue; } /* Update counts. */ siles++; totlength += slen; plast = &sile->next; } /* Store the update. */ accepted[jj++] = sile; } /* Write back the number of accepted updates. */ ac_count = jj; /* Send the silence update list, including overlapped silences (to * make it easier on clients). */ buf_used = 0; for (sile = cli_user(sptr)->silence; sile; sile = sile->next) { char ch; if (sile->flags & (BAN_OVERLAPPED | BAN_DEL)) ch = '-'; else if (sile->flags & BAN_ADD) ch = '+'; else continue; slen = strlen(sile->banstr); if (buf_used + slen + 4 > 400) { buf[buf_used] = '\0'; sendcmdto_one(sptr, CMD_SILENCE, sptr, "%s", buf); buf_used = 0; } if (buf_used) buf[buf_used++] = ','; buf[buf_used++] = ch; if (sile->flags & BAN_EXCEPTION) buf[buf_used++] = '~'; memcpy(buf + buf_used, sile->banstr, slen); buf_used += slen; } if (buf_used > 0) { buf[buf_used] = '\0'; sendcmdto_one(sptr, CMD_SILENCE, sptr, "%s", buf); buf_used = 0; } } /* Forward any silence removals or exceptions updates to other * servers if the user has positive silences. */ if (!dest || !MyUser(dest)) { for (ii = buf_used = 0; ii < ac_count; ++ii) { char ch; sile = accepted[ii]; if (sile->flags & BAN_OVERLAPPED) continue; else if (sile->flags & BAN_DEL) ch = '-'; else if (sile->flags & BAN_ADD) { if (!(sile->flags & BAN_EXCEPTION)) continue; ch = '+'; } else continue; slen = strlen(sile->banstr); if (buf_used + slen + 4 > 400) { buf[buf_used] = '\0'; if (dest) sendcmdto_one(sptr, CMD_SILENCE, dest, "%C %s", dest, buf); else sendcmdto_serv_butone(sptr, CMD_SILENCE, sptr, "* %s", buf); buf_used = 0; } if (buf_used) buf[buf_used++] = ','; buf[buf_used++] = ch; if (sile->flags & BAN_EXCEPTION) buf[buf_used++] = '~'; memcpy(buf + buf_used, sile->banstr, slen); buf_used += slen; } if (buf_used > 0) { buf[buf_used] = '\0'; if (dest) sendcmdto_one(sptr, CMD_SILENCE, dest, "%C %s", dest, buf); else sendcmdto_serv_butone(sptr, CMD_SILENCE, sptr, "* %s", buf); buf_used = 0; } } /* Remove overlapped and deleted silences from the user's silence * list. Clear BAN_ADD since we're walking the list anyway. */ for (plast = &cli_user(sptr)->silence; (sile = *plast) != NULL; ) { if (sile->flags & (BAN_OVERLAPPED | BAN_DEL)) { *plast = sile->next; free_ban(sile); } else { sile->flags &= ~BAN_ADD; *plast = sile; plast = &sile->next; } } /* Free any silence-deleting updates. */ for (ii = 0; ii < ac_count; ++ii) { if ((accepted[ii]->flags & (BAN_ADD | BAN_DEL)) == BAN_DEL) { free_ban(accepted[ii]); } } }
/* Rewritten by Run - 24 sept 94 */ static void exit_one_client(struct Client* bcptr, const char* comment) { struct SLink *lp; struct Ban *bp; if (cli_serv(bcptr) && cli_serv(bcptr)->client_list) /* Was SetServerYXX called ? */ ClearServerYXX(bcptr); /* Removes server from server_list[] */ if (IsUser(bcptr)) { /* * clear out uping requests */ if (IsUPing(bcptr)) uping_cancel(bcptr, 0); /* * Stop a running /LIST clean */ if (MyUser(bcptr) && cli_listing(bcptr)) { MyFree(cli_listing(bcptr)); cli_listing(bcptr) = NULL; } /* * If a person is on a channel, send a QUIT notice * to every client (person) on the same channel (so * that the client can show the "**signoff" message). * (Note: The notice is to the local clients *only*) */ sendcmdto_common_channels_butone(bcptr, CMD_QUIT, NULL, ":%s", comment); remove_user_from_all_channels(bcptr); /* Clean up invitefield */ while ((lp = cli_user(bcptr)->invited)) del_invite(bcptr, lp->value.chptr); /* Clean up silencefield */ while ((bp = cli_user(bcptr)->silence)) { cli_user(bcptr)->silence = bp->next; free_ban(bp); } /* Clean up snotice lists */ if (MyUser(bcptr)) set_snomask(bcptr, ~0, SNO_DEL); if (IsInvisible(bcptr)) { assert(UserStats.inv_clients > 0); --UserStats.inv_clients; } if (IsOper(bcptr)) { assert(UserStats.opers > 0); --UserStats.opers; } if (MyConnect(bcptr)) Count_clientdisconnects(bcptr, UserStats); else Count_remoteclientquits(UserStats, bcptr); } else if (IsServer(bcptr)) { /* Remove downlink list node of uplink */ remove_dlink(&(cli_serv(cli_serv(bcptr)->up))->down, cli_serv(bcptr)->updown); cli_serv(bcptr)->updown = 0; if (MyConnect(bcptr)) Count_serverdisconnects(UserStats); else Count_remoteserverquits(UserStats); } else if (IsMe(bcptr)) { sendto_opmask_butone(0, SNO_OLDSNO, "ERROR: tried to exit me! : %s", comment); return; /* ...must *never* exit self! */ } else if (IsUnknown(bcptr) || IsConnecting(bcptr) || IsHandshake(bcptr)) Count_unknowndisconnects(UserStats); /* * Update IPregistry */ if (IsIPChecked(bcptr)) IPcheck_disconnect(bcptr); /* * Remove from serv->client_list * NOTE: user is *always* NULL if this is a server */ if (cli_user(bcptr)) { assert(!IsServer(bcptr)); /* bcptr->user->server->serv->client_list[IndexYXX(bcptr)] = NULL; */ RemoveYXXClient(cli_user(bcptr)->server, cli_yxx(bcptr)); } /* Remove bcptr from the client list */ #ifdef DEBUGMODE if (hRemClient(bcptr) != 0) Debug((DEBUG_ERROR, "%p !in tab %s[%s] %p %p %p %d %d %p", bcptr, cli_name(bcptr), cli_from(bcptr) ? cli_sockhost(cli_from(bcptr)) : "??host", cli_from(bcptr), cli_next(bcptr), cli_prev(bcptr), cli_fd(bcptr), cli_status(bcptr), cli_user(bcptr))); #else hRemClient(bcptr); #endif remove_client_from_list(bcptr); }
void fread_ban( FILE * fp, int type ) { BAN_DATA *pban; unsigned int i = 0; bool fMatch = FALSE; CREATE( pban, BAN_DATA, 1 ); pban->name = fread_string_nohash( fp ); pban->level = fread_number( fp ); pban->duration = fread_number( fp ); pban->unban_date = fread_number( fp ); if( type == BAN_SITE ) { /* Sites have 2 extra numbers written out */ pban->prefix = fread_number( fp ); pban->suffix = fread_number( fp ); } pban->warn = fread_number( fp ); pban->ban_by = fread_string_nohash( fp ); pban->ban_time = fread_string_nohash( fp ); pban->note = fread_string( fp ); /* * Need to lookup the class or race number if it is of that type */ if( type == BAN_CLASS ) for( i = 0; i < MAX_CLASS; i++ ) { if( !str_cmp( class_table[i]->who_name, pban->name ) ) { fMatch = TRUE; break; } } else if( type == BAN_RACE ) for( i = 0; i < MAX_RACE; i++ ) { if( !str_cmp( race_table[i]->race_name, pban->name ) ) { fMatch = TRUE; break; } } else if( type == BAN_SITE ) for( i = 0; i < strlen( pban->name ); i++ ) { if( pban->name[i] == '@' ) { char *temp; const char *temp2; temp = str_dup( pban->name ); temp[i] = '\0'; temp2 = &pban->name[i + 1]; DISPOSE( pban->name ); pban->name = str_dup( temp2 ); DISPOSE( temp ); break; } } if( type == BAN_RACE || type == BAN_CLASS ) { if( fMatch ) pban->flag = i; else /* The file is corupted throw out this ban structure */ { bug( "Bad class structure %d.\r\n", i ); free_ban( pban ); return; } } if( type == BAN_CLASS ) LINK( pban, first_ban_class, last_ban_class, next, prev ); else if( type == BAN_RACE ) LINK( pban, first_ban_race, last_ban_race, next, prev ); else if( type == BAN_SITE ) LINK( pban, first_ban, last_ban, next, prev ); else /* Bad type throw out the ban structure */ { bug( "Fread_ban: Bad type %d", type ); free_ban( pban ); } return; }
void do_allow( CHAR_DATA *ch, char *argument ) { char arg[MAX_INPUT_LENGTH]; char buf[MAX_STRING_LENGTH]; BAN_DATA *prev; BAN_DATA *curr; char *name, *user, *host; one_argument( argument, arg ); if ( arg[0] == '\0' ) { send_to_char( "Remove which site from the ban list?\n\r", ch ); return; } name = arg; user = &str_empty[0]; for ( host = name; *name != '\0'; ) { if ( *name == '@' ) { user = host; *name = '\0'; host = name+1; break; } name++; } prev = NULL; for ( curr = ban_list; curr != NULL; prev = curr, curr = curr->next ) { if ( IS_SET(curr->ban_flags, BAN_USER) && str_cmp(curr->user, user) ) continue; if ( !str_cmp( host, curr->host ) ) { if (curr->level > get_trust(ch)) { send_to_char( "You are not powerful enough to lift that ban.\n\r",ch); return; } if ( prev == NULL ) ban_list = ban_list->next; else prev->next = curr->next; if ( IS_SET(curr->ban_flags, BAN_USER) ) sprintf( buf, "Ban on %s@%s lifted.\r\n", curr->user, curr->host ); else sprintf( buf, "Ban on %s lifted.\r\n", curr->host ); free_ban(curr); send_to_char( buf, ch ); save_bans(); return; } } send_to_char( "Site is not banned.\n\r", ch ); return; }