/* * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd) * * Copyright (c) 2001-2021 ircd-hybrid development team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 * USA */ /*! \file conf_resv.c * \brief Functions to reserve(jupe) a nick/channel. * \version $Id: conf_resv.c 9858 2021-01-01 04:43:42Z michael $ */ #include "stdinc.h" #include "list.h" #include "send.h" #include "client.h" #include "memory.h" #include "ircd.h" #include "irc_string.h" #include "ircd_defs.h" #include "misc.h" #include "conf.h" #include "conf_resv.h" #include "hostmask.h" static dlink_list resv_chan_list; static dlink_list resv_nick_list; const dlink_list * resv_chan_get_list(void) { return &resv_chan_list; } const dlink_list * resv_nick_get_list(void) { return &resv_nick_list; } void resv_delete(struct ResvItem *resv, bool expired) { if (expired == true) sendto_realops_flags(UMODE_EXPIRATION, L_ALL, SEND_NOTICE, "Temporary RESV for [%s] expired", resv->mask); while (resv->exempt_list.head) { struct ResvExemptItem *exempt = resv->exempt_list.head->data; dlinkDelete(&exempt->node, &resv->exempt_list); xfree(exempt->name); xfree(exempt->user); xfree(exempt->host); xfree(exempt); } dlinkDelete(&resv->node, resv->list); xfree(resv->mask); xfree(resv->reason); xfree(resv); } /* create_resv() * * inputs - name of nick to create resv for * - reason for resv * - 1 if from ircd.conf, 0 if from elsewhere * output - pointer to struct ResvNick * side effects - */ struct ResvItem * resv_make(const char *mask, const char *reason, const dlink_list *elist) { dlink_list *list; if (IsChanPrefix(*mask)) list = &resv_chan_list; else list = &resv_nick_list; struct ResvItem *resv = xcalloc(sizeof(*resv)); resv->list = list; resv->mask = xstrdup(mask); resv->reason = xstrndup(reason, IRCD_MIN(strlen(reason), REASONLEN)); dlinkAdd(resv, &resv->node, resv->list); if (elist) { dlink_node *node; DLINK_FOREACH(node, elist->head) { char nick[NICKLEN + 1]; char user[USERLEN + 1]; char host[HOSTLEN + 1]; struct split_nuh_item nuh; char *s = node->data; nuh.nuhmask = s; nuh.nickptr = nick; nuh.userptr = user; nuh.hostptr = host; nuh.nicksize = sizeof(nick); nuh.usersize = sizeof(user); nuh.hostsize = sizeof(host); split_nuh(&nuh); struct ResvExemptItem *exempt = xcalloc(sizeof(*exempt)); exempt->name = xstrdup(nick); exempt->user = xstrdup(user); exempt->host = xstrdup(host); exempt->type = parse_netmask(host, &exempt->addr, &exempt->bits); dlinkAdd(exempt, &exempt->node, &resv->exempt_list); } } return resv; } struct ResvItem * resv_find(const char *name, int (*compare)(const char *, const char *)) { dlink_node *node, *node_next; dlink_list *list; if (IsChanPrefix(*name)) list = &resv_chan_list; else list = &resv_nick_list; DLINK_FOREACH_SAFE(node, node_next, list->head) { struct ResvItem *resv = node->data; if (resv->expire && (resv->expire <= event_base->time.sec_real)) resv_delete(resv, true); else if (compare(resv->mask, name) == 0) return resv; } return NULL; } bool resv_exempt_find(const struct Client *client, const struct ResvItem *resv) { dlink_node *node; DLINK_FOREACH(node, resv->exempt_list.head) { const struct ResvExemptItem *exempt = node->data; if (match(exempt->name, client->name) == 0 && match(exempt->user, client->username) == 0) { switch (exempt->type) { case HM_HOST: if (match(exempt->host, client->realhost) == 0 || match(exempt->host, client->sockhost) == 0 || match(exempt->host, client->host) == 0) return true; break; case HM_IPV6: case HM_IPV4: if (address_compare(&client->ip, &exempt->addr, false, false, exempt->bits) == true) return true; break; default: assert(0); } } } return false; } void resv_clear(void) { dlink_list *tab[] = { &resv_chan_list, &resv_nick_list, NULL }; for (dlink_list **list = tab; *list; ++list) { dlink_node *node, *node_next; DLINK_FOREACH_SAFE(node, node_next, (*list)->head) { struct ResvItem *resv = node->data; if (resv->in_database == false) resv_delete(resv, false); } } } void resv_expire(void) { dlink_list *tab[] = { &resv_chan_list, &resv_nick_list, NULL }; for (dlink_list **list = tab; *list; ++list) { dlink_node *node, *node_next; DLINK_FOREACH_SAFE(node, node_next, (*list)->head) { struct ResvItem *resv = node->data; if (resv->expire && (resv->expire <= event_base->time.sec_real)) resv_delete(resv, true); } } }