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