1 /*
2 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 *
4 * Copyright (c) 1997-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 m_set.c
23 * \brief Includes required functions for processing the SET command.
24 * \version $Id: m_set.c 9858 2021-01-01 04:43:42Z michael $
25 */
26
27 #include "stdinc.h"
28 #include "client.h"
29 #include "event.h"
30 #include "irc_string.h"
31 #include "ircd.h"
32 #include "numeric.h"
33 #include "send.h"
34 #include "conf.h"
35 #include "parse.h"
36 #include "modules.h"
37 #include "misc.h"
38
39
40 /* SET AUTOCONN */
41 static void
quote_autoconn(struct Client * source_p,const char * arg,int newval)42 quote_autoconn(struct Client *source_p, const char *arg, int newval)
43 {
44 static const char *const status[] =
45 {
46 "OFF", "ON"
47 };
48
49 if (EmptyString(arg))
50 {
51 sendto_one_notice(source_p, &me, ":Please specify a server name!");
52 return;
53 }
54
55 struct MaskItem *conf = connect_find(arg, irccmp);
56 if (conf == NULL)
57 {
58 sendto_one_notice(source_p, &me, ":Cannot find %s", arg);
59 return;
60 }
61
62 if (newval)
63 SetConfAllowAutoConn(conf);
64 else
65 ClearConfAllowAutoConn(conf);
66
67 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
68 "%s has changed AUTOCONN for %s to %s",
69 get_oper_name(source_p), conf->name, status[newval != 0]);
70 sendto_one_notice(source_p, &me, ":AUTOCONN for %s is now set to %s",
71 conf->name, status[newval != 0]);
72 }
73
74 /* SET AUTOCONNALL */
75 static void
quote_autoconnall(struct Client * source_p,const char * arg,int newval)76 quote_autoconnall(struct Client *source_p, const char *arg, int newval)
77 {
78 static const char *const status[] =
79 {
80 "OFF", "ON"
81 };
82
83 if (newval >= 0)
84 {
85 GlobalSetOptions.autoconn = newval != 0;
86 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
87 "%s has changed AUTOCONNALL to %s",
88 get_oper_name(source_p), status[GlobalSetOptions.autoconn == true]);
89 }
90 else
91 sendto_one_notice(source_p, &me, ":AUTOCONNALL is currently %s",
92 status[GlobalSetOptions.autoconn == true]);
93 }
94
95 /* SET FLOODCOUNT */
96 static void
quote_floodcount(struct Client * source_p,const char * arg,int newval)97 quote_floodcount(struct Client *source_p, const char *arg, int newval)
98 {
99 if (newval >= 0)
100 {
101 GlobalSetOptions.floodcount = newval;
102 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
103 "%s has changed FLOODCOUNT to %u",
104 get_oper_name(source_p), GlobalSetOptions.floodcount);
105 }
106 else
107 sendto_one_notice(source_p, &me, ":FLOODCOUNT is currently %u",
108 GlobalSetOptions.floodcount);
109 }
110
111 /* SET FLOODTIME */
112 static void
quote_floodtime(struct Client * source_p,const char * arg,int newval)113 quote_floodtime(struct Client *source_p, const char *arg, int newval)
114 {
115 if (newval >= 0)
116 {
117 GlobalSetOptions.floodtime = newval;
118 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
119 "%s has changed FLOODTIME to %u",
120 get_oper_name(source_p), GlobalSetOptions.floodtime);
121 }
122 else
123 sendto_one_notice(source_p, &me, ":FLOODTIME is currently %u",
124 GlobalSetOptions.floodtime);
125 }
126
127 /* SET MAX */
128 static void
quote_max(struct Client * source_p,const char * arg,int newval)129 quote_max(struct Client *source_p, const char *arg, int newval)
130 {
131 if (newval > 0)
132 {
133 if (newval > MAXCLIENTS_MAX)
134 {
135 sendto_one_notice(source_p, &me, ":You cannot set MAXCLIENTS to > %d, restoring to %u",
136 MAXCLIENTS_MAX, GlobalSetOptions.maxclients);
137 return;
138 }
139
140 GlobalSetOptions.maxclients = newval;
141 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
142 "%s set new MAXCLIENTS to %u (%u current)",
143 get_oper_name(source_p), GlobalSetOptions.maxclients, dlink_list_length(&local_client_list));
144 }
145 else
146 sendto_one_notice(source_p, &me, ":Current MAXCLIENTS = %u (%u)",
147 GlobalSetOptions.maxclients, dlink_list_length(&local_client_list));
148 }
149
150 /* SET SPAMNUM */
151 static void
quote_spamnum(struct Client * source_p,const char * arg,int newval)152 quote_spamnum(struct Client *source_p, const char *arg, int newval)
153 {
154 if (newval >= 0)
155 {
156 if (newval == 0)
157 {
158 GlobalSetOptions.spam_num = newval;
159 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
160 "%s has disabled ANTI_SPAMBOT", source_p->name);
161 return;
162 }
163
164 GlobalSetOptions.spam_num = IRCD_MAX(newval, MIN_SPAM_NUM);
165 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
166 "%s has changed SPAMNUM to %u",
167 get_oper_name(source_p), GlobalSetOptions.spam_num);
168 }
169 else
170 sendto_one_notice(source_p, &me, ":SPAMNUM is currently %u",
171 GlobalSetOptions.spam_num);
172 }
173
174 /* SET SPAMTIME */
175 static void
quote_spamtime(struct Client * source_p,const char * arg,int newval)176 quote_spamtime(struct Client *source_p, const char *arg, int newval)
177 {
178 if (newval > 0)
179 {
180 GlobalSetOptions.spam_time = IRCD_MAX(newval, MIN_SPAM_TIME);
181 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
182 "%s has changed SPAMTIME to %u",
183 get_oper_name(source_p), GlobalSetOptions.spam_time);
184 }
185 else
186 sendto_one_notice(source_p, &me, ":SPAMTIME is currently %u",
187 GlobalSetOptions.spam_time);
188 }
189
190 /* SET JFLOODTIME */
191 static void
quote_jfloodtime(struct Client * source_p,const char * arg,int newval)192 quote_jfloodtime(struct Client *source_p, const char *arg, int newval)
193 {
194 if (newval >= 0)
195 {
196 GlobalSetOptions.joinfloodtime = newval;
197 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
198 "%s has changed JFLOODTIME to %u",
199 get_oper_name(source_p), GlobalSetOptions.joinfloodtime);
200 }
201 else
202 sendto_one_notice(source_p, &me, ":JFLOODTIME is currently %u",
203 GlobalSetOptions.joinfloodtime);
204 }
205
206 /* SET JFLOODCOUNT */
207 static void
quote_jfloodcount(struct Client * source_p,const char * arg,int newval)208 quote_jfloodcount(struct Client *source_p, const char *arg, int newval)
209 {
210 if (newval >= 0)
211 {
212 GlobalSetOptions.joinfloodcount = newval;
213 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
214 "%s has changed JFLOODCOUNT to %u",
215 get_oper_name(source_p), GlobalSetOptions.joinfloodcount);
216 }
217 else
218 sendto_one_notice(source_p, &me, ":JFLOODCOUNT is currently %u",
219 GlobalSetOptions.joinfloodcount);
220 }
221
222 /* Structure used for the SET table itself */
223 struct SetStruct
224 {
225 const char *const name;
226 void (*const handler)(struct Client *, const char *, int);
227 bool wants_char; /* 1 if it expects (char *, [int]) */
228 bool wants_int; /* 1 if it expects ([char *], int) */
229 /* eg: 0, 1 == only an int arg
230 * eg: 1, 1 == char and int args */
231 };
232
233 /*
234 * If this ever needs to be expanded to more than one arg of each
235 * type, want_char/want_int could be the count of the arguments,
236 * instead of just a boolean flag...
237 *
238 * -davidt
239 */
240 static const struct SetStruct set_cmd_table[] =
241 {
242 /* name function string arg int arg */
243 /* ------------------------------------------------------ */
244 { "AUTOCONN", quote_autoconn, true, true },
245 { "AUTOCONNALL", quote_autoconnall, false, true },
246 { "FLOODCOUNT", quote_floodcount, false, true },
247 { "FLOODTIME", quote_floodtime, false, true },
248 { "MAX", quote_max, false, true },
249 { "SPAMNUM", quote_spamnum, false, true },
250 { "SPAMTIME", quote_spamtime, false, true },
251 { "JFLOODTIME", quote_jfloodtime, false, true },
252 { "JFLOODCOUNT", quote_jfloodcount, false, true },
253 /* ------------------------------------------------------ */
254 { NULL, NULL, false, false }
255 };
256
257 /*
258 * list_quote_commands() sends the client all the available commands.
259 * Four to a line for now.
260 */
261 static void
list_quote_commands(struct Client * source_p)262 list_quote_commands(struct Client *source_p)
263 {
264 unsigned int j = 0;
265 const char *names[4] = { "", "", "", "" };
266
267 sendto_one_notice(source_p, &me, ":Available QUOTE SET commands:");
268
269 for (const struct SetStruct *tab = set_cmd_table; tab->handler; ++tab)
270 {
271 names[j++] = tab->name;
272
273 if (j > 3)
274 {
275 sendto_one_notice(source_p, &me, ":%s %s %s %s",
276 names[0], names[1],
277 names[2], names[3]);
278 j = 0;
279 names[0] = names[1] = names[2] = names[3] = "";
280 }
281 }
282
283 if (j)
284 sendto_one_notice(source_p, &me, ":%s %s %s %s",
285 names[0], names[1],
286 names[2], names[3]);
287 }
288
289 /*
290 * mo_set - SET command handler
291 * set options while running
292 */
293 static void
mo_set(struct Client * source_p,int parc,char * parv[])294 mo_set(struct Client *source_p, int parc, char *parv[])
295 {
296 int newval;
297 const char *strarg = NULL;
298 const char *intarg = NULL;
299
300 if (!HasOFlag(source_p, OPER_FLAG_SET))
301 {
302 sendto_one_numeric(source_p, &me, ERR_NOPRIVS, "set");
303 return;
304 }
305
306 if (parc > 1)
307 {
308 /*
309 * Go through all the commands in set_cmd_table, until one is
310 * matched.
311 */
312 for (const struct SetStruct *tab = set_cmd_table; tab->handler; ++tab)
313 {
314 if (irccmp(tab->name, parv[1]))
315 continue;
316
317 /*
318 * Command found; now execute the code
319 */
320 int n = 2;
321
322 if (tab->wants_char)
323 strarg = parv[n++];
324
325 if (tab->wants_int)
326 intarg = parv[n++];
327
328 if ((n - 1) > parc)
329 sendto_one_notice(source_p, &me, ":SET %s expects (\"%s%s\") args", tab->name,
330 (tab->wants_char ? "string, " : ""),
331 (tab->wants_int ? "int" : ""));
332
333 if (parc <= 2)
334 {
335 strarg = NULL;
336 intarg = NULL;
337 }
338
339 if (tab->wants_int && parc > 2)
340 {
341 if (intarg)
342 {
343 if (irccmp(intarg, "yes") == 0 || irccmp(intarg, "on") == 0)
344 newval = 1;
345 else if (irccmp(intarg, "no") == 0 || irccmp(intarg, "off") == 0)
346 newval = 0;
347 else
348 newval = atoi(intarg);
349 }
350 else
351 newval = -1;
352
353 if (newval < 0)
354 {
355 sendto_one_notice(source_p, &me, ":Value less than 0 illegal for %s", tab->name);
356 return;
357 }
358 }
359 else
360 newval = -1;
361
362 tab->handler(source_p, strarg, newval);
363 return;
364 }
365
366 /*
367 * Code here will be executed when a /QUOTE SET command is not
368 * found within set_cmd_table.
369 */
370 sendto_one_notice(source_p, &me, ":Variable not found.");
371 return;
372 }
373
374 list_quote_commands(source_p);
375 }
376
377 static struct Message set_msgtab =
378 {
379 .cmd = "SET",
380 .handlers[UNREGISTERED_HANDLER] = { .handler = m_unregistered },
381 .handlers[CLIENT_HANDLER] = { .handler = m_not_oper },
382 .handlers[SERVER_HANDLER] = { .handler = m_ignore },
383 .handlers[ENCAP_HANDLER] = { .handler = m_ignore },
384 .handlers[OPER_HANDLER] = { .handler = mo_set }
385 };
386
387 static void
module_init(void)388 module_init(void)
389 {
390 mod_add_cmd(&set_msgtab);
391 }
392
393 static void
module_exit(void)394 module_exit(void)
395 {
396 mod_del_cmd(&set_msgtab);
397 }
398
399 struct module module_entry =
400 {
401 .version = "$Revision: 9858 $",
402 .modinit = module_init,
403 .modexit = module_exit,
404 };
405