1 /*
2 * m_flags.c: Implements comstud-style mode flags.
3 *
4 * Copyright 2002 by W. Campbell and the ircd-hybrid development team
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * 1.Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 * 2.Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3.The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
22 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 *
30 * $Id: m_flags.c 28681 2015-10-02 16:49:39Z androsyn $
31 */
32
33 /* List of ircd includes from ../include/ */
34 #include "stdinc.h"
35 #include "ratbox_lib.h"
36 #include "struct.h"
37 #include "client.h"
38 #include "common.h"
39 #include "ircd.h"
40 #include "match.h"
41 #include "numeric.h"
42 #include "s_conf.h"
43 #include "s_log.h"
44 #include "s_serv.h"
45 #include "send.h"
46 #include "parse.h"
47 #include "modules.h"
48 #include "s_user.h" /* send_umode_out() */
49 #include "s_newconf.h"
50
51 static int m_flags(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
52 static int mo_flags(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
53
54 static char *set_flags_to_string(struct Client *client_p);
55 static char *unset_flags_to_string(struct Client *client_p);
56
57
58 struct Message test_msgtab = {
59 "FLAGS", 0, 0, 0, MFLG_SLOW,
60 {mg_unreg, {m_flags, 0}, {m_flags, 0}, mg_ignore, mg_ignore, {mo_flags, 0}}
61 };
62
63
64 mapi_clist_av1 test_clist[] = { &test_msgtab, NULL };
65
66 DECLARE_MODULE_AV1(test, NULL, NULL, test_clist, NULL, NULL, "$Revision: 28681 $");
67
68
69 /* FLAGS requires it's own mini parser, since the last parameter in it can
70 ** contain a number of FLAGS. CS handles FLAGS mode1 mode2 OR
71 ** FLAGS :mode1 mode2, but not both mixed.
72 **
73 ** The best way to match a flag to a mode is with a simple table
74 */
75
76 struct FlagTable
77 {
78 const char *name;
79 int mode;
80 int oper;
81 };
82
83 /* *INDENT-OFF* */
84 static struct FlagTable flag_table[] = {
85 /* name mode it represents oper only? */
86 #if 0
87 /* This one is special...controlled via an oper block option */
88 { "OWALLOPS", UMODE_OPERWALL, 1 },
89 #endif
90 { "SWALLOPS", UMODE_WALLOP, 0 },
91 { "STATSNOTICES", UMODE_SPY, 1 },
92 /* We don't have a separate OKILL and SKILL modes */
93 { "OKILLS", UMODE_SERVNOTICE, 0 },
94 { "SKILLS", UMODE_SKILL, 0 },
95 { "SNOTICES", UMODE_SERVNOTICE, 0 },
96 /* We don't have separate client connect and disconnect modes */
97 { "CLICONNECTS", UMODE_CCONN, 1 },
98 { "CLIDISCONNECTS", UMODE_CCONN, 1 },
99 /* I'm taking a wild guess here... */
100 { "THROTTLES", UMODE_REJ, 1 },
101 #if 0
102 /* This one is special...controlled via an oper block option */
103 { "NICKCHANGES", UMODE_NCHANGE, 1 },
104 /* NICKCHANGES must be checked for separately */
105 #endif
106 /* I'm assuming this is correct... */
107 { "IPMISMATCHES", UMODE_UNAUTH, 1 },
108 { "LWALLOPS", UMODE_LOCOPS, 1 },
109 /* These aren't separate on Hybrid */
110 { "CONNECTS", UMODE_EXTERNAL, 1 },
111 { "SQUITS", UMODE_EXTERNAL, 1 },
112 /* Now we have our Hybrid specific flags */
113 { "FULL", UMODE_FULL, 1 },
114 /* Not in CS, but we might as well put it here */
115 { "INVISIBLE", UMODE_INVISIBLE, 0 },
116 { "BOTS", UMODE_BOTS, 1 },
117 { "CALLERID", UMODE_CALLERID, 0 },
118 { "UNAUTH", UMODE_UNAUTH, 1 },
119 { "DEBUG", UMODE_DEBUG, 1 },
120 { NULL, 0, 0}
121 };
122 /* *INDENT-ON* */
123
124 /* We won't control CALLERID or INVISIBLE in here */
125
126 #define FL_ALL_USER_FLAGS (UMODE_WALLOP | UMODE_SKILL | UMODE_SERVNOTICE )
127
128 /* and we don't control NCHANGES here either */
129
130 #define FL_ALL_OPER_FLAGS (FL_ALL_USER_FLAGS | UMODE_CCONN | UMODE_REJ |\
131 UMODE_FULL | UMODE_SPY | UMODE_DEBUG |\
132 UMODE_BOTS | UMODE_EXTERNAL |\
133 UMODE_UNAUTH | UMODE_LOCOPS )
134
135 /*
136 ** m_flags
137 ** parv[0] = sender prefix
138 ** parv[1] = parameter
139 */
140 static int
m_flags(struct Client * client_p,struct Client * source_p,int parc,const char * parv[])141 m_flags(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
142 {
143 int i, j;
144 int isadd;
145 int setflags;
146 int isgood;
147 char *p;
148 char *flag;
149
150 if(parc < 2)
151 {
152 /* Generate a list of what flags you have and what you are missing,
153 ** and send it to the user
154 */
155 sendto_one(source_p, ":%s NOTICE %s :Current flags:%s",
156 me.name, parv[0], set_flags_to_string(source_p));
157 sendto_one(source_p, ":%s NOTICE %s :Current missing flags:%s",
158 me.name, parv[0], unset_flags_to_string(source_p));
159 return 1;
160 }
161
162 /* Preserve the current flags */
163 setflags = source_p->umodes;
164
165 /* XXX - change this to support a multiple last parameter like ISON */
166
167 for(i = 1; i < parc; i++)
168 {
169 char *s = LOCAL_COPY(parv[i]);
170 for(flag = rb_strtok_r(s, " ", &p); flag; flag = rb_strtok_r(NULL, " ", &p))
171 {
172 /* We default to being in ADD mode */
173 isadd = 1;
174
175 /* We default to being in BAD mode */
176 isgood = 0;
177
178 if(!isalpha(flag[0]))
179 {
180 if(flag[0] == '-')
181 isadd = 0;
182 else if(flag[0] == '+')
183 isadd = 1;
184 flag++;
185 }
186
187 /* support ALL here */
188 if(!irccmp(flag, "ALL"))
189 {
190 if(isadd)
191 source_p->umodes |= FL_ALL_USER_FLAGS;
192 else
193 source_p->umodes &= ~FL_ALL_USER_FLAGS;
194 sendto_one(source_p, ":%s NOTICE %s :Current flags:%s",
195 me.name, parv[0], set_flags_to_string(source_p));
196 sendto_one(source_p, ":%s NOTICE %s :Current missing flags:%s",
197 me.name, parv[0], unset_flags_to_string(source_p));
198 send_umode_out(client_p, source_p, setflags);
199 return 1;
200 }
201
202 for(j = 0; flag_table[j].name; j++)
203 {
204 if(!flag_table[j].oper && !irccmp(flag, flag_table[j].name))
205 {
206 if(isadd)
207 source_p->umodes |= flag_table[j].mode;
208 else
209 source_p->umodes &= ~(flag_table[j].mode);
210 isgood = 1;
211 continue;
212 }
213 }
214 /* This for ended without matching a valid FLAG, here is where
215 ** I want to operate differently than ircd-comstud, and just ignore
216 ** the invalid flag, send a warning and go on.
217 */
218 if(!isgood)
219 sendto_one(source_p, ":%s NOTICE %s :Invalid FLAGS: %s (IGNORING)",
220 me.name, parv[0], flag);
221 }
222 }
223
224 /* All done setting the flags, print the notices out to the user
225 ** telling what flags they have and what flags they are missing
226 */
227 sendto_one(source_p, ":%s NOTICE %s :Current flags:%s",
228 me.name, parv[0], set_flags_to_string(source_p));
229 sendto_one(source_p, ":%s NOTICE %s :Current missing flags:%s",
230 me.name, parv[0], unset_flags_to_string(source_p));
231
232 send_umode_out(client_p, source_p, setflags);
233 return 0;
234 }
235
236 /*
237 ** mo_flags
238 ** parv[0] = sender prefix
239 ** parv[1] = parameter
240 */
241 static int
mo_flags(struct Client * client_p,struct Client * source_p,int parc,const char * parv[])242 mo_flags(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
243 {
244 int i, j;
245 int isadd;
246 int setflags;
247 int isgood;
248 char *p;
249 char *flag;
250
251 if(parc < 2)
252 {
253 /* Generate a list of what flags you have and what you are missing,
254 ** and send it to the user
255 */
256 sendto_one(source_p, ":%s NOTICE %s :Current flags:%s",
257 me.name, parv[0], set_flags_to_string(source_p));
258 sendto_one(source_p, ":%s NOTICE %s :Current missing flags:%s",
259 me.name, parv[0], unset_flags_to_string(source_p));
260 return 1;
261 }
262
263 /* Preserve the current flags */
264 setflags = source_p->umodes;
265
266 /* XXX - change this to support a multiple last parameter like ISON */
267
268 for(i = 1; i < parc; i++)
269 {
270 char *s = LOCAL_COPY(parv[i]);
271 for(flag = rb_strtok_r(s, " ", &p); flag; flag = rb_strtok_r(NULL, " ", &p))
272 {
273 /* We default to being in ADD mode */
274 isadd = 1;
275
276 /* We default to being in BAD mode */
277 isgood = 0;
278
279 if(!isalpha(flag[0]))
280 {
281 if(flag[0] == '-')
282 isadd = 0;
283 else if(flag[0] == '+')
284 isadd = 1;
285 flag++;
286 }
287
288 /* support ALL here */
289 if(!irccmp(flag, "ALL"))
290 {
291 if(isadd)
292 source_p->umodes |= FL_ALL_OPER_FLAGS;
293 else
294 source_p->umodes &= ~FL_ALL_OPER_FLAGS;
295 sendto_one(source_p, ":%s NOTICE %s :Current flags:%s",
296 me.name, parv[0], set_flags_to_string(source_p));
297 sendto_one(source_p, ":%s NOTICE %s :Current missing flags:%s",
298 me.name, parv[0], unset_flags_to_string(source_p));
299 send_umode_out(client_p, source_p, setflags);
300 return 1;
301 }
302
303 if(!irccmp(flag, "NICKCHANGES"))
304 {
305 if(!IsOperN(source_p))
306 {
307 sendto_one(source_p,
308 ":%s NOTICE %s :*** You need oper and N flag for +n",
309 me.name, parv[0]);
310 continue;
311 }
312 if(isadd)
313 source_p->umodes |= UMODE_NCHANGE;
314 else
315 source_p->umodes &= ~UMODE_NCHANGE;
316 isgood = 1;
317 continue;
318 }
319 if(!irccmp(flag, "OWALLOPS"))
320 {
321 if(!IsOperOperwall(source_p))
322 {
323 sendto_one(source_p,
324 ":%s NOTICE %s :*** You need oper and operwall flag for +z",
325 me.name, parv[0]);
326 continue;
327 }
328 if(isadd)
329 source_p->umodes |= UMODE_OPERWALL;
330 else
331 source_p->umodes &= ~UMODE_OPERWALL;
332 isgood = 1;
333 continue;
334 }
335
336 for(j = 0; flag_table[j].name; j++)
337 {
338 if(!irccmp(flag, flag_table[j].name))
339 {
340 if(isadd)
341 source_p->umodes |= flag_table[j].mode;
342 else
343 source_p->umodes &= ~(flag_table[j].mode);
344 isgood = 1;
345 continue;
346 }
347 }
348 /* This for ended without matching a valid FLAG, here is where
349 ** I want to operate differently than ircd-comstud, and just ignore
350 ** the invalid flag, send a warning and go on.
351 */
352 if(!isgood)
353 sendto_one(source_p, ":%s NOTICE %s :Invalid FLAGS: %s (IGNORING)",
354 me.name, parv[0], flag);
355 }
356 }
357
358 /* All done setting the flags, print the notices out to the user
359 ** telling what flags they have and what flags they are missing
360 */
361 sendto_one(source_p, ":%s NOTICE %s :Current flags:%s",
362 me.name, parv[0], set_flags_to_string(source_p));
363 sendto_one(source_p, ":%s NOTICE %s :Current missing flags:%s",
364 me.name, parv[0], unset_flags_to_string(source_p));
365
366 send_umode_out(client_p, source_p, setflags);
367 return 0;
368 }
369
370 static char *
set_flags_to_string(struct Client * client_p)371 set_flags_to_string(struct Client *client_p)
372 {
373 /* XXX - list all flags that we have set on the client */
374 static char setflags[BUFSIZE + 1];
375 int i;
376
377 /* Clear it to begin with, we'll be doing a lot of rb_sprintf's */
378 setflags[0] = '\0';
379
380 /* Unlike unset_flags_to_string(), we don't have to care about oper
381 ** flags and not showing them
382 */
383
384 if(client_p->umodes & UMODE_OPERWALL)
385 {
386 rb_sprintf(setflags, "%s %s", setflags, "OWALLOPS");
387 }
388
389 for(i = 0; flag_table[i].name; i++)
390 {
391 if(client_p->umodes & flag_table[i].mode)
392 {
393 rb_sprintf(setflags, "%s %s", setflags, flag_table[i].name);
394 }
395 }
396
397 #if 0
398 if(IsOper(client_p) && IsOperN(client_p))
399 {
400 #endif
401 /* You can only be set +NICKCHANGES if you are an oper and
402 ** IsOperN(client_p) is true
403 */
404 if(client_p->umodes & UMODE_NCHANGE)
405 {
406 rb_sprintf(setflags, "%s %s", setflags, "NICKCHANGES");
407 }
408 #if 0
409 }
410 #endif
411
412 return setflags;
413 }
414
415 static char *
unset_flags_to_string(struct Client * client_p)416 unset_flags_to_string(struct Client *client_p)
417 {
418 /* Inverse of above */
419 /* XXX - list all flags that we do NOT have set on the client */
420 static char setflags[BUFSIZE + 1];
421 int i, isoper;
422
423 /* Clear it to begin with, we'll be doing a lot of rb_sprintf's */
424 setflags[0] = '\0';
425
426 if(IsOper(client_p))
427 isoper = 1;
428 else
429 isoper = 0;
430
431 if(IsOper(client_p) && IsOperOperwall(client_p))
432 {
433 if(!(client_p->umodes & UMODE_OPERWALL))
434 {
435 rb_sprintf(setflags, "%s %s", setflags, "OWALLOPS");
436 }
437 }
438
439 for(i = 0; flag_table[i].name; i++)
440 {
441 if(!(client_p->umodes & flag_table[i].mode))
442 {
443 if(!isoper && flag_table[i].oper)
444 continue;
445 rb_sprintf(setflags, "%s %s", setflags, flag_table[i].name);
446 }
447 }
448
449 if(IsOper(client_p) && IsOperN(client_p))
450 {
451 if(!(client_p->umodes & UMODE_NCHANGE))
452 {
453 rb_sprintf(setflags, "%s %s", setflags, "NICKCHANGES");
454 }
455 }
456
457 return setflags;
458 }
459