/* parse_resv() * * inputs - source_p, NULL supported * - thing to resv * - time_t if tkline * - reason * outputs - none * side effects - parse resv, create if valid */ static void parse_resv(struct Client *source_p, char *name, int tkline_time, char *reason) { if (IsChanPrefix(*name)) { struct MaskItem *conf = NULL; if ((conf = create_resv(name, reason, NULL)) == NULL) { if (IsClient(source_p)) sendto_one_notice(source_p, &me, ":A RESV has already been placed on channel: %s", name); return; } conf->setat = CurrentTime; SetConfDatabase(conf); if (tkline_time) { if (IsClient(source_p)) sendto_one_notice(source_p, &me, ":A %d minute %s RESV has been placed on channel: %s", tkline_time/60, (MyClient(source_p) ? "local" : "remote"), name); sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE, "%s has placed a %d minute %s RESV on channel: %s [%s]", get_oper_name(source_p), tkline_time/60, (MyClient(source_p) ? "local" : "remote"), conf->name, conf->reason); ilog(LOG_TYPE_RESV, "%s added temporary %d min. RESV for [%s] [%s]", get_oper_name(source_p), (int)tkline_time/60, conf->name, conf->reason); conf->until = CurrentTime + tkline_time; } else { if (IsClient(source_p)) sendto_one_notice(source_p, &me, ":A %s RESV has been placed on channel %s", (MyClient(source_p) ? "local" : "remote"), name); sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE, "%s has placed a %s RESV on channel %s : [%s]", get_oper_name(source_p), (MyClient(source_p) ? "local" : "remote"), conf->name, conf->reason); ilog(LOG_TYPE_RESV, "%s added RESV for [%s] [%s]", get_oper_name(source_p), conf->name, conf->reason); } } else { struct MaskItem *conf = NULL; if (!valid_wild_card_simple(name)) { if (IsClient(source_p)) sendto_one_notice(source_p, &me, ":Please include at least %u non-wildcard characters with the resv", ConfigGeneral.min_nonwildcard_simple); return; } if (!HasUMode(source_p, UMODE_ADMIN) && has_wildcards(name)) { if (IsClient(source_p)) sendto_one_notice(source_p, &me, ":You must be an admin to perform a wildcard RESV"); return; } if ((conf = create_resv(name, reason, NULL)) == NULL) { if (IsClient(source_p)) sendto_one_notice(source_p, &me, ":A RESV has already been placed on nick %s", name); return; } conf->setat = CurrentTime; SetConfDatabase(conf); if (tkline_time) { if (IsClient(source_p)) sendto_one_notice(source_p, &me, ":A %d minute %s RESV has been placed on nick %s : [%s]", tkline_time/60, (MyClient(source_p) ? "local" : "remote"), conf->name, conf->reason); sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE, "%s has placed a %d minute %s RESV on nick %s : [%s]", get_oper_name(source_p), tkline_time/60, (MyClient(source_p) ? "local" : "remote"), conf->name, conf->reason); ilog(LOG_TYPE_RESV, "%s added temporary %d min. RESV for [%s] [%s]", get_oper_name(source_p), (int)tkline_time/60, conf->name, conf->reason); conf->until = CurrentTime + tkline_time; } else { if (IsClient(source_p)) sendto_one_notice(source_p, &me, ":A %s RESV has been placed on nick %s : [%s]", (MyClient(source_p) ? "local" : "remote"), conf->name, conf->reason); sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE, "%s has placed a %s RESV on nick %s : [%s]", get_oper_name(source_p), (MyClient(source_p) ? "local" : "remote"), conf->name, conf->reason); ilog(LOG_TYPE_RESV, "%s added RESV for [%s] [%s]", get_oper_name(source_p), conf->name, conf->reason); } } }
/* ms_ban() * * parv[1] - type * parv[2] - username mask or * * parv[3] - hostname mask * parv[4] - creation TS * parv[5] - duration (relative to creation) * parv[6] - lifetime (relative to creation) * parv[7] - oper or * * parv[8] - reason (possibly with |operreason) */ static int ms_ban(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { rb_dlink_node *ptr; struct ConfItem *aconf; unsigned int ntype; const char *oper, *stype; time_t now, created, hold, lifetime; char *p; int act; int valid; now = rb_current_time(); if (strlen(parv[1]) != 1) { sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Unknown BAN type %s from %s", parv[1], source_p->name); return 0; } switch (parv[1][0]) { case 'K': ntype = CONF_KILL; stype = "K-Line"; break; case 'X': ntype = CONF_XLINE; stype = "X-Line"; break; case 'R': ntype = IsChannelName(parv[3]) ? CONF_RESV_CHANNEL : CONF_RESV_NICK; stype = "RESV"; break; default: sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Unknown BAN type %s from %s", parv[1], source_p->name); return 0; } created = atol(parv[4]); hold = created + atoi(parv[5]); lifetime = created + atoi(parv[6]); if (!strcmp(parv[7], "*")) oper = IsServer(source_p) ? source_p->name : get_oper_name(source_p); else oper = parv[7]; ptr = find_prop_ban(ntype, parv[2], parv[3]); if (ptr != NULL) { /* We already know about this ban mask. */ aconf = ptr->data; if (aconf->created > created || (aconf->created == created && aconf->lifetime >= lifetime)) { if (IsPerson(source_p)) sendto_one_notice(source_p, ":Your %s [%s%s%s] has been superseded", stype, aconf->user ? aconf->user : "", aconf->user ? "@" : "", aconf->host); return 0; } /* act indicates if something happened (from the oper's * point of view). This is the case if the ban was * previously active (not deleted) or if the new ban * is not a removal and not already expired. */ act = !(aconf->status & CONF_ILLEGAL) || (hold != created && hold > now); if (lifetime > aconf->lifetime) aconf->lifetime = lifetime; /* already expired, hmm */ if (aconf->lifetime <= now) return 0; /* Deactivate, it will be reactivated later if appropriate. */ deactivate_conf(aconf, ptr, now); rb_free(aconf->user); aconf->user = NULL; rb_free(aconf->host); aconf->host = NULL; operhash_delete(aconf->info.oper); aconf->info.oper = NULL; rb_free(aconf->passwd); aconf->passwd = NULL; rb_free(aconf->spasswd); aconf->spasswd = NULL; } else { /* New ban mask. */ aconf = make_conf(); aconf->status = CONF_ILLEGAL | ntype; aconf->lifetime = lifetime; rb_dlinkAddAlloc(aconf, &prop_bans); act = hold != created && hold > now; } aconf->flags &= ~CONF_FLAGS_MYOPER; aconf->flags |= CONF_FLAGS_TEMPORARY; aconf->user = ntype == CONF_KILL ? rb_strdup(parv[2]) : NULL; aconf->host = rb_strdup(parv[3]); aconf->info.oper = operhash_add(oper); aconf->created = created; aconf->hold = hold; if (ntype != CONF_KILL || (p = strchr(parv[parc - 1], '|')) == NULL) aconf->passwd = rb_strdup(parv[parc - 1]); else { aconf->passwd = rb_strndup(parv[parc - 1], p - parv[parc - 1] + 1); aconf->spasswd = rb_strdup(p + 1); } /* The ban is fully filled in and in the prop_bans list * but still deactivated. Now determine if it should be activated * and send the server notices. */ /* We only reject *@* and the like here. * Otherwise malformed bans are fairly harmless and can be removed. */ switch (ntype) { case CONF_KILL: valid = valid_wild_card(aconf->user, aconf->host); break; case CONF_RESV_CHANNEL: valid = 1; break; default: valid = valid_wild_card_simple(aconf->host); break; } if (act && hold != created && !valid) { sendto_realops_snomask(SNO_GENERAL, L_ALL, "Ignoring global %d min. %s from %s%s%s for [%s%s%s]: too few non-wildcard characters", (int)((hold - now) / 60), stype, IsServer(source_p) ? source_p->name : get_oper_name(source_p), strcmp(parv[7], "*") ? " on behalf of " : "", strcmp(parv[7], "*") ? parv[7] : "", aconf->user ? aconf->user : "", aconf->user ? "@" : "", aconf->host); if(IsPerson(source_p)) sendto_one_notice(source_p, ":Your %s [%s%s%s] has too few non-wildcard characters", stype, aconf->user ? aconf->user : "", aconf->user ? "@" : "", aconf->host); /* Propagate it, but do not apply it locally. */ } else if (act && hold != created) { /* Keep the notices in sync with modules/m_kline.c etc. */ sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s added global %d min. %s%s%s for [%s%s%s] [%s]", IsServer(source_p) ? source_p->name : get_oper_name(source_p), (int)((hold - now) / 60), stype, strcmp(parv[7], "*") ? " from " : "", strcmp(parv[7], "*") ? parv[7] : "", aconf->user ? aconf->user : "", aconf->user ? "@" : "", aconf->host, parv[parc - 1]); ilog(L_KLINE, "%s %s %d %s%s%s %s", parv[1], IsServer(source_p) ? source_p->name : get_oper_name(source_p), (int)((hold - now) / 60), aconf->user ? aconf->user : "", aconf->user ? " " : "", aconf->host, parv[parc - 1]); aconf->status &= ~CONF_ILLEGAL; } else if (act) { sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s has removed the global %s for: [%s%s%s]%s%s", IsServer(source_p) ? source_p->name : get_oper_name(source_p), stype, aconf->user ? aconf->user : "", aconf->user ? "@" : "", aconf->host, strcmp(parv[7], "*") ? " on behalf of " : "", strcmp(parv[7], "*") ? parv[7] : ""); ilog(L_KLINE, "U%s %s %s%s %s", parv[1], IsServer(source_p) ? source_p->name : get_oper_name(source_p), aconf->user ? aconf->user : "", aconf->user ? " " : "", aconf->host); } /* If CONF_ILLEGAL is still set at this point, remove entries from the * reject cache (for klines and xlines). * If CONF_ILLEGAL is not set, add the ban to the type-specific data * structure and take action on matched clients/channels. */ switch (ntype) { case CONF_KILL: if (aconf->status & CONF_ILLEGAL) remove_reject_mask(aconf->user, aconf->host); else { add_conf_by_address(aconf->host, CONF_KILL, aconf->user, NULL, aconf); if(ConfigFileEntry.kline_delay || (IsServer(source_p) && !HasSentEob(source_p))) { if(kline_queued == 0) { rb_event_addonce("check_klines", check_klines_event, NULL, ConfigFileEntry.kline_delay ? ConfigFileEntry.kline_delay : 1); kline_queued = 1; } } else check_klines(); } break; case CONF_XLINE: if (aconf->status & CONF_ILLEGAL) remove_reject_mask(aconf->host, NULL); else { rb_dlinkAddAlloc(aconf, &xline_conf_list); check_xlines(); } break; case CONF_RESV_CHANNEL: if (!(aconf->status & CONF_ILLEGAL)) { add_to_resv_hash(aconf->host, aconf); resv_chan_forcepart(aconf->host, aconf->passwd, hold - now); } break; case CONF_RESV_NICK: if (!(aconf->status & CONF_ILLEGAL)) rb_dlinkAddAlloc(aconf, &resv_conf_list); break; } sendto_server(client_p, NULL, CAP_BAN|CAP_TS6, NOCAPS, ":%s BAN %s %s %s %s %s %s %s :%s", source_p->id, parv[1], parv[2], parv[3], parv[4], parv[5], parv[6], parv[7], parv[parc - 1]); return 0; }
/* parse_resv() * * inputs - source_p, NULL supported * - thing to resv * - time_t if tkline * - reason * outputs - none * side effects - parse resv, create if valid */ static void parse_resv(struct Client *source_p, char *name, int tkline_time, char *reason) { struct ConfItem *conf = NULL; int services = 0; if(IsServices(source_p)) services = 1; if(IsChanPrefix(*name)) { struct ResvChannel *resv_p; if((conf = create_channel_resv(name, reason, 0)) == NULL) { if(!services) sendto_one(source_p, ":%s NOTICE %s :A RESV has already been placed on channel: %s", me.name, source_p->name, name); return; } resv_p = map_to_conf(conf); if(tkline_time != 0) { if(!services) { sendto_one(source_p, ":%s NOTICE %s :A %d minute %s RESV has been placed on channel: %s", me.name, source_p->name, tkline_time / 60, (MyClient(source_p) ? "local" : "remote"), name); sendto_realops_flags(UMODE_ALL, L_ALL, "%s has placed a %d minute %s RESV on channel: %s [%s]", get_oper_name(source_p), tkline_time / 60, (MyClient(source_p) ? "local" : "remote"), resv_p->name, resv_p->reason); } ilog(L_TRACE, "%s added temporary %d min. RESV for [%s] [%s]", source_p->name, (int) tkline_time / 60, conf->name, resv_p->reason); resv_p->hold = CurrentTime + tkline_time; add_temp_line(conf); } else { if(!services) { sendto_one(source_p, ":%s NOTICE %s :A %s RESV has been placed on channel %s", me.name, source_p->name, (MyClient(source_p) ? "local" : "remote"), name); sendto_realops_flags(UMODE_ALL, L_ALL, "%s has placed a %s RESV on channel %s : [%s]", get_oper_name(source_p), (MyClient(source_p) ? "local" : "remote"), resv_p->name, resv_p->reason); } write_conf_line(source_p, conf, NULL /* not used */ , 0 /* not used */ ); } } else { struct MatchItem *resv_p = NULL; if(!valid_wild_card_simple(name) && !IsServices(source_p)) { sendto_one(source_p, ":%s NOTICE %s :Please include at least %d non-wildcard characters with the resv", me.name, source_p->name, ConfigFileEntry.min_nonwildcard_simple); return; } if(!IsAdmin(source_p) && !IsServices(source_p) && strpbrk(name, "*?#")) { sendto_one(source_p, ":%s NOTICE %s :You must be an admin to perform a " "wildcard RESV", me.name, source_p->name); return; } if((conf = create_nick_resv(name, reason, 0)) == NULL) { if(!services) sendto_one(source_p, ":%s NOTICE %s :A RESV has already been placed on nick %s", me.name, source_p->name, name); return; } resv_p = map_to_conf(conf); if(tkline_time != 0) { if(!services) { sendto_one(source_p, ":%s NOTICE %s :A %d minute %s RESV has been placed on nick %s : [%s]", me.name, source_p->name, tkline_time / 60, (MyClient(source_p) ? "local" : "remote"), conf->name, resv_p->reason); sendto_realops_flags(UMODE_ALL, L_ALL, "%s has placed a %d minute %s RESV on nick %s : [%s]", get_oper_name(source_p), tkline_time / 60, (MyClient(source_p) ? "local" : "remote"), conf->name, resv_p->reason); } ilog(L_TRACE, "%s added temporary %d min. RESV for [%s] [%s]", source_p->name, (int) tkline_time / 60, conf->name, resv_p->reason); resv_p->hold = CurrentTime + tkline_time; add_temp_line(conf); } else { if(!services) { sendto_one(source_p, ":%s NOTICE %s :A %s RESV has been placed on nick %s : [%s]", me.name, source_p->name, (MyClient(source_p) ? "local" : "remote"), conf->name, resv_p->reason); sendto_realops_flags(UMODE_ALL, L_ALL, "%s has placed a %s RESV on nick %s : [%s]", get_oper_name(source_p), (MyClient(source_p) ? "local" : "remote"), conf->name, resv_p->reason); } write_conf_line(source_p, conf, NULL /* not used */ , 0 /* not used */ ); } } }