1 /*
2  *  ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3  *
4  *  Copyright (c) 2001-2021 ircd-hybrid development team
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19  *  USA
20  */
21 
22 /*! \file conf_resv.c
23  * \brief Functions to reserve(jupe) a nick/channel.
24  * \version $Id: conf_resv.c 9858 2021-01-01 04:43:42Z michael $
25  */
26 
27 #include "stdinc.h"
28 #include "list.h"
29 #include "send.h"
30 #include "client.h"
31 #include "memory.h"
32 #include "ircd.h"
33 #include "irc_string.h"
34 #include "ircd_defs.h"
35 #include "misc.h"
36 #include "conf.h"
37 #include "conf_resv.h"
38 #include "hostmask.h"
39 
40 
41 static dlink_list resv_chan_list;
42 static dlink_list resv_nick_list;
43 
44 
45 const dlink_list *
resv_chan_get_list(void)46 resv_chan_get_list(void)
47 {
48   return &resv_chan_list;
49 }
50 
51 const dlink_list *
resv_nick_get_list(void)52 resv_nick_get_list(void)
53 {
54   return &resv_nick_list;
55 }
56 
57 void
resv_delete(struct ResvItem * resv,bool expired)58 resv_delete(struct ResvItem *resv, bool expired)
59 {
60   if (expired == true)
61     sendto_realops_flags(UMODE_EXPIRATION, L_ALL, SEND_NOTICE, "Temporary RESV for [%s] expired",
62                          resv->mask);
63 
64   while (resv->exempt_list.head)
65   {
66     struct ResvExemptItem *exempt = resv->exempt_list.head->data;
67 
68     dlinkDelete(&exempt->node, &resv->exempt_list);
69     xfree(exempt->name);
70     xfree(exempt->user);
71     xfree(exempt->host);
72     xfree(exempt);
73   }
74 
75   dlinkDelete(&resv->node, resv->list);
76   xfree(resv->mask);
77   xfree(resv->reason);
78   xfree(resv);
79 }
80 
81 /* create_resv()
82  *
83  * inputs	- name of nick to create resv for
84  *		- reason for resv
85  *		- 1 if from ircd.conf, 0 if from elsewhere
86  * output	- pointer to struct ResvNick
87  * side effects	-
88  */
89 struct ResvItem *
resv_make(const char * mask,const char * reason,const dlink_list * elist)90 resv_make(const char *mask, const char *reason, const dlink_list *elist)
91 {
92   dlink_list *list;
93 
94   if (IsChanPrefix(*mask))
95     list = &resv_chan_list;
96   else
97     list = &resv_nick_list;
98 
99   struct ResvItem *resv = xcalloc(sizeof(*resv));
100   resv->list = list;
101   resv->mask = xstrdup(mask);
102   resv->reason = xstrndup(reason, IRCD_MIN(strlen(reason), REASONLEN));
103   dlinkAdd(resv, &resv->node, resv->list);
104 
105   if (elist)
106   {
107     dlink_node *node;
108 
109     DLINK_FOREACH(node, elist->head)
110     {
111       char nick[NICKLEN + 1];
112       char user[USERLEN + 1];
113       char host[HOSTLEN + 1];
114       struct split_nuh_item nuh;
115       char *s = node->data;
116 
117       nuh.nuhmask  = s;
118       nuh.nickptr  = nick;
119       nuh.userptr  = user;
120       nuh.hostptr  = host;
121 
122       nuh.nicksize = sizeof(nick);
123       nuh.usersize = sizeof(user);
124       nuh.hostsize = sizeof(host);
125 
126       split_nuh(&nuh);
127 
128       struct ResvExemptItem *exempt = xcalloc(sizeof(*exempt));
129       exempt->name = xstrdup(nick);
130       exempt->user = xstrdup(user);
131       exempt->host = xstrdup(host);
132       exempt->type = parse_netmask(host, &exempt->addr, &exempt->bits);
133       dlinkAdd(exempt, &exempt->node, &resv->exempt_list);
134     }
135   }
136 
137   return resv;
138 }
139 
140 struct ResvItem *
resv_find(const char * name,int (* compare)(const char *,const char *))141 resv_find(const char *name, int (*compare)(const char *, const char *))
142 {
143   dlink_node *node, *node_next;
144   dlink_list *list;
145 
146   if (IsChanPrefix(*name))
147     list = &resv_chan_list;
148   else
149     list = &resv_nick_list;
150 
151   DLINK_FOREACH_SAFE(node, node_next, list->head)
152   {
153     struct ResvItem *resv = node->data;
154 
155     if (resv->expire &&
156         (resv->expire <= event_base->time.sec_real))
157       resv_delete(resv, true);
158     else if (compare(resv->mask, name) == 0)
159       return resv;
160   }
161 
162   return NULL;
163 }
164 
165 bool
resv_exempt_find(const struct Client * client,const struct ResvItem * resv)166 resv_exempt_find(const struct Client *client, const struct ResvItem *resv)
167 {
168   dlink_node *node;
169 
170   DLINK_FOREACH(node, resv->exempt_list.head)
171   {
172     const struct ResvExemptItem *exempt = node->data;
173 
174     if (match(exempt->name, client->name) == 0 && match(exempt->user, client->username) == 0)
175     {
176       switch (exempt->type)
177       {
178         case HM_HOST:
179           if (match(exempt->host, client->realhost) == 0 ||
180               match(exempt->host, client->sockhost) == 0 || match(exempt->host, client->host) == 0)
181             return true;
182           break;
183         case HM_IPV6:
184         case HM_IPV4:
185           if (address_compare(&client->ip, &exempt->addr, false, false, exempt->bits) == true)
186             return true;
187           break;
188         default:
189           assert(0);
190       }
191     }
192   }
193 
194   return false;
195 }
196 
197 void
resv_clear(void)198 resv_clear(void)
199 {
200   dlink_list *tab[] = { &resv_chan_list, &resv_nick_list, NULL };
201 
202   for (dlink_list **list = tab; *list; ++list)
203   {
204     dlink_node *node, *node_next;
205 
206     DLINK_FOREACH_SAFE(node, node_next, (*list)->head)
207     {
208       struct ResvItem *resv = node->data;
209 
210       if (resv->in_database == false)
211         resv_delete(resv, false);
212     }
213   }
214 }
215 
216 void
resv_expire(void)217 resv_expire(void)
218 {
219   dlink_list *tab[] = { &resv_chan_list, &resv_nick_list, NULL };
220 
221   for (dlink_list **list = tab; *list; ++list)
222   {
223     dlink_node *node, *node_next;
224 
225     DLINK_FOREACH_SAFE(node, node_next, (*list)->head)
226     {
227       struct ResvItem *resv = node->data;
228 
229       if (resv->expire &&
230           (resv->expire <= event_base->time.sec_real))
231         resv_delete(resv, true);
232     }
233   }
234 }
235