1 /*
2  * atheme-services: A collection of minimalist IRC services
3  * flags.c: Functions to convert a flags table into a bitmask.
4  *
5  * Copyright (c) 2005-2010 Atheme Project (http://www.atheme.org)
6  *
7  * Permission to use, copy, modify, and/or distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
12  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
13  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
14  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
15  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
16  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
17  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
18  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
19  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
20  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
21  * POSSIBILITY OF SUCH DAMAGE.
22  */
23 
24 #include "atheme.h"
25 
26 #define FLAGS_ADD       0x1
27 #define FLAGS_DEL       0x2
28 
29 unsigned int ca_all = CA_ALL_ALL;
30 unsigned int ca_all_enable = CA_ALL_ALL;
31 
32 static char flags_buf[128];
33 
34 struct flags_table chanacs_flags[256] = {
35 	['v'] = {CA_VOICE, 0, true,      "voice"},
36 	['V'] = {CA_AUTOVOICE, 0, true,  "autovoice"},
37 	['o'] = {CA_OP, 0, true,         "op"},
38 	['O'] = {CA_AUTOOP, 0, true,     "autoop"},
39 	['t'] = {CA_TOPIC, 0, true,      "topic"},
40 	['s'] = {CA_SET, 0, true,        "set"},
41 	['r'] = {CA_REMOVE, 0, true,     "remove"},
42 	['i'] = {CA_INVITE, 0, true,     "invite"},
43 	['R'] = {CA_RECOVER, 0, true,    "recover"},
44 	['f'] = {CA_FLAGS, 0, true,      "acl-change"},
45 	['h'] = {CA_HALFOP, 0, true,     "halfop"},
46 	['H'] = {CA_AUTOHALFOP, 0, true, "autohalfop"},
47 	['A'] = {CA_ACLVIEW, 0, true,    "acl-view"},
48 	['F'] = {CA_FOUNDER, 0, false,   "founder"},
49 	['q'] = {CA_USEOWNER, 0, true,   "owner"},
50 	['a'] = {CA_USEPROTECT, 0, true, "protect"},
51 	['b'] = {CA_AKICK, 0, false,     "banned"},
52 	['e'] = {CA_EXEMPT, 0, true,     "exempt"},
53 };
54 
55 gflags_t mu_flags[] = {
56 	{ 'h', MU_HOLD },
57 	{ 'n', MU_NEVEROP },
58 	{ 'o', MU_NOOP },
59 	{ 'W', MU_WAITAUTH },
60 	{ 's', MU_HIDEMAIL },
61 	{ 'm', MU_NOMEMO },
62 	{ 'e', MU_EMAILMEMOS },
63 	{ 'C', MU_CRYPTPASS },
64 	{ 'b', MU_NOBURSTLOGIN },
65 	{ 'E', MU_ENFORCE },
66 	{ 'P', MU_USE_PRIVMSG },
67 	{ 'p', MU_PRIVATE },
68 	{ 'Q', MU_QUIETCHG },
69 	{ 'g', MU_NOGREET },
70 	{ 'r', MU_REGNOLIMIT },
71 	{ 'N', MU_NEVERGROUP },
72 	{ 'S', MU_NOPASSWORD },
73 	{ 0, 0 },
74 };
75 
76 gflags_t mc_flags[] = {
77 	{ 'h', MC_HOLD },
78 	{ 'o', MC_NOOP },
79 	{ 'l', MC_LIMITFLAGS },
80 	{ 'z', MC_SECURE },
81 	{ 'v', MC_VERBOSE },
82 	{ 'r', MC_RESTRICTED },
83 	{ 'k', MC_KEEPTOPIC },
84 	{ 'e', MC_VERBOSE_OPS },
85 	{ 't', MC_TOPICLOCK },
86 	{ 'g', MC_GUARD },
87 	{ 'p', MC_PRIVATE },
88 	{ 'n', MC_NOSYNC },
89 	{ 'f', MC_ANTIFLOOD },
90 	{ 0, 0 },
91 };
92 
93 gflags_t soper_flags[] = {
94 	{ 'c', SOPER_CONF },
95 	{ 0, 0 },
96 };
97 
flags_associate(unsigned char flag,unsigned int restrictflags,bool def,const char * name)98 unsigned int flags_associate(unsigned char flag, unsigned int restrictflags, bool def, const char *name)
99 {
100 	if (chanacs_flags[flag].value && chanacs_flags[flag].value != 0xFFFFFFFF)
101 		return 0;
102 
103 	chanacs_flags[flag].value = flags_find_slot();
104 	chanacs_flags[flag].restrictflags = restrictflags;
105 	chanacs_flags[flag].def = def;
106 	chanacs_flags[flag].name = name;
107 
108 	update_chanacs_flags();
109 
110 	return chanacs_flags[flag].value;
111 }
112 
flags_clear(unsigned char flag)113 void flags_clear(unsigned char flag)
114 {
115 	/* 0xFFFFFFFF = orphaned flag */
116 	chanacs_flags[flag].value = 0xFFFFFFFF;
117 	chanacs_flags[flag].restrictflags = 0;
118 	chanacs_flags[flag].def = false;
119 	chanacs_flags[flag].name = NULL;
120 }
121 
flags_find_slot(void)122 unsigned int flags_find_slot(void)
123 {
124 	unsigned int flag, i;
125 	unsigned int all_flags = 0;
126 
127 	for (i = 0; i < ARRAY_SIZE(chanacs_flags); i++)
128 		all_flags |= chanacs_flags[i].value;
129 
130 	for (flag = 1; flag && (all_flags & flag); flag <<= 1);
131 
132 	return flag;
133 }
134 
135 /* Construct bitmasks to be added and removed
136  * Postcondition *addflags & *removeflags == 0
137  * -- jilles */
flags_make_bitmasks(const char * string,unsigned int * addflags,unsigned int * removeflags)138 void flags_make_bitmasks(const char *string, unsigned int *addflags, unsigned int *removeflags)
139 {
140 	unsigned int flag;
141 	bool shortflag = false;
142 	int status = FLAGS_ADD;
143 
144 	*addflags = *removeflags = 0;
145 	while (*string)
146 	{
147 		switch (*string)
148 		{
149 		  case '+':
150 			  status = FLAGS_ADD;
151 			  break;
152 
153 		  case '-':
154 			  status = FLAGS_DEL;
155 			  break;
156 
157 		  case '=':
158 			  *addflags = 0;
159 			  *removeflags = 0xFFFFFFFF;
160 			  status = FLAGS_ADD;
161 			  break;
162 
163 		  case '*':
164 			  if (status == FLAGS_ADD)
165 			  {
166 				  *addflags |= ca_all_enable;
167 				  *removeflags |= CA_AKICK;
168 			  }
169 			  else if (status == FLAGS_DEL)
170 			  {
171 				  *addflags = 0;
172 				  *removeflags = 0xFFFFFFFF;
173 			  }
174 			  break;
175 
176 		  default:
177 			  if (!shortflag && (flag = xflag_lookup(string)) != 0x0)
178 			  {
179 				  if (status == FLAGS_ADD)
180 				  {
181 					  *addflags |= flag;
182 					  *removeflags &= ~flag;
183 				  }
184 				  else if (status == FLAGS_DEL)
185 				  {
186 					  *addflags &= ~flag;
187 					  *removeflags |= flag;
188 				  }
189 
190 				  *addflags &= ca_all;
191 				  *removeflags &= ca_all;
192 
193 				  return;
194 			  }
195 			  else if ((flag = chanacs_flags[(unsigned char)*string].value) != 0x0)
196 			  {
197 				  if (status == FLAGS_ADD)
198 				  {
199 					  *addflags |= flag;
200 					  *removeflags &= ~flag;
201 				  }
202 				  else if (status == FLAGS_DEL)
203 				  {
204 					  *addflags &= ~flag;
205 					  *removeflags |= flag;
206 				  }
207 			  }
208 
209 			  shortflag = true;
210 		}
211 
212 		string++;
213 	}
214 
215 	*addflags &= ca_all;
216 	*removeflags &= ca_all;
217 
218 	return;
219 }
220 
flags_to_bitmask(const char * string,unsigned int flags)221 unsigned int flags_to_bitmask(const char *string, unsigned int flags)
222 {
223 	unsigned int bitmask = (flags ? flags : 0x0);
224 	int status = FLAGS_ADD;
225 	unsigned int flag;
226 
227 	while (*string)
228 	{
229 		switch (*string)
230 		{
231 		  case '+':
232 			  status = FLAGS_ADD;
233 			  break;
234 
235 		  case '-':
236 			  status = FLAGS_DEL;
237 			  break;
238 
239 		  case '=':
240 			  bitmask = 0;
241 			  status = FLAGS_ADD;
242 			  break;
243 
244 		  case '*':
245 			  if (status == FLAGS_ADD)
246 				  bitmask |= CA_ALLPRIVS & ca_all_enable & ~CA_FOUNDER;
247 			  else if (status == FLAGS_DEL)
248 				  bitmask = 0;
249 			  break;
250 
251 		  default:
252 			  if ((flag = chanacs_flags[(unsigned char) *string].value) != 0x0)
253 			  {
254 				  if (status == FLAGS_ADD)
255 					  bitmask |= flag;
256 				  else if (status == FLAGS_DEL)
257 					  bitmask &= ~flag;
258 			  }
259 		}
260 
261 		string++;
262 	}
263 
264 	return bitmask & ca_all;
265 }
266 
bitmask_to_flags(unsigned int flags)267 char *bitmask_to_flags(unsigned int flags)
268 {
269 	char *bptr;
270 	unsigned int i = 0;
271 
272 	bptr = flags_buf;
273 
274 	*bptr++ = '+';
275 
276 	for (i = 0; i < ARRAY_SIZE(chanacs_flags); i++)
277 		if (chanacs_flags[i].value & flags)
278 			*bptr++ = (char) i;
279 
280 	*bptr++ = '\0';
281 
282 	return flags_buf;
283 }
284 
bitmask_to_flags2(unsigned int addflags,unsigned int removeflags)285 char *bitmask_to_flags2(unsigned int addflags, unsigned int removeflags)
286 {
287 	char *bptr;
288 	unsigned int i = 0;
289 
290 	bptr = flags_buf;
291 
292 	if (removeflags)
293 	{
294 		*bptr++ = '-';
295 		for (i = 0; i < ARRAY_SIZE(chanacs_flags); i++)
296 			if (chanacs_flags[i].value & removeflags)
297 				*bptr++ = (char) i;
298 	}
299 	if (addflags)
300 	{
301 		*bptr++ = '+';
302 		for (i = 0; i < ARRAY_SIZE(chanacs_flags); i++)
303 			if (chanacs_flags[i].value & addflags)
304 				*bptr++ = (char) i;
305 	}
306 
307 	*bptr++ = '\0';
308 
309 	return flags_buf;
310 }
311 
312 /* flags a non-founder with +f and these flags is allowed to set -- jilles */
allow_flags(mychan_t * mc,unsigned int theirflags)313 unsigned int allow_flags(mychan_t *mc, unsigned int theirflags)
314 {
315 	unsigned int flags;
316 
317 	flags = theirflags;
318 	flags &= ~CA_AKICK;
319 	if (flags & CA_REMOVE)
320 		flags |= CA_AKICK;
321 	if (flags & CA_OP)
322 		flags |= CA_AUTOOP;
323 	if (flags & CA_HALFOP)
324 		flags |= CA_AUTOHALFOP;
325 	if (flags & CA_VOICE)
326 		flags |= CA_AUTOVOICE;
327 	if (use_limitflags && mc->flags & MC_LIMITFLAGS)
328 	{
329 		if (!(theirflags & (CA_HIGHPRIVS & ~CA_FLAGS)))
330 			flags &= CA_AKICK;
331 		else if ((theirflags & CA_HIGHPRIVS) != CA_HIGHPRIVS)
332 			flags &= ~CA_HIGHPRIVS;
333 	}
334 	return flags;
335 }
336 
update_chanacs_flags(void)337 void update_chanacs_flags(void)
338 {
339 	unsigned int i;
340 
341 	ca_all = ca_all_enable = 0;
342 	for (i = 0; i < ARRAY_SIZE(chanacs_flags); i++)
343 	{
344 		ca_all |= chanacs_flags[i].value;
345 		if (chanacs_flags[i].def == true)
346 			ca_all_enable |= chanacs_flags[i].value;
347 	}
348 
349 	if (ircd != NULL)
350 	{
351 		if (!ircd->uses_halfops)
352 			ca_all &= ~(CA_HALFOP | CA_AUTOHALFOP);
353 		if (!ircd->uses_protect)
354 			ca_all &= ~CA_USEPROTECT;
355 		if (!ircd->uses_owner)
356 			ca_all &= ~CA_USEOWNER;
357 	}
358 }
359 
xflag_lookup(const char * name)360 unsigned int xflag_lookup(const char *name)
361 {
362 	unsigned int i;
363 
364 	for (i = 0; i < ARRAY_SIZE(chanacs_flags); i++)
365 	{
366 		if (chanacs_flags[i].name == NULL)
367 			continue;
368 
369 		if (!strcasecmp(chanacs_flags[i].name, name))
370 			return chanacs_flags[i].value;
371 	}
372 
373 	return 0;
374 }
375 
xflag_apply(unsigned int in,const char * name)376 unsigned int xflag_apply(unsigned int in, const char *name)
377 {
378 	unsigned int out, flag;
379 	int status = FLAGS_ADD;
380 
381 	out = in;
382 
383 	switch (*name)
384 	{
385 	case '+':
386 		status = FLAGS_ADD;
387 		name++;
388 		break;
389 	case '-':
390 		status = FLAGS_DEL;
391 		name++;
392 		break;
393 	}
394 
395 	flag = xflag_lookup(name);
396 
397 	if (status == FLAGS_ADD)
398 		out |= flag;
399 	else
400 		out &= ~flag;
401 
402 	return out;
403 }
404 
xflag_tostr(unsigned int flags)405 const char *xflag_tostr(unsigned int flags)
406 {
407 	unsigned int i;
408 	static char buf[BUFSIZE];
409 
410 	*buf = '\0';
411 
412 	for (i = 0; i < ARRAY_SIZE(chanacs_flags); i++)
413 	{
414 		if (chanacs_flags[i].name == NULL)
415 			continue;
416 
417 		if (!(flags & chanacs_flags[i].value))
418 			continue;
419 
420 		if (*buf != '\0')
421 			mowgli_strlcat(buf, ", ", sizeof buf);
422 
423 		mowgli_strlcat(buf, chanacs_flags[i].name, sizeof buf);
424 	}
425 
426 	return buf;
427 }
428 
gflags_tostr(gflags_t * gflags,unsigned int flags)429 char *gflags_tostr(gflags_t *gflags, unsigned int flags)
430 {
431 	static char buf[257];
432 	char *p = buf;
433 	int i;
434 	*p++ = '+';
435 	for (i = 0; gflags[i].ch; i++)
436 		if (flags & gflags[i].value)
437 			*p++ = gflags[i].ch;
438 	*p = '\0';
439 	return buf;
440 }
441 
gflag_fromchar(gflags_t * gflags,char f,unsigned int * res)442 static bool gflag_fromchar(gflags_t *gflags, char f, unsigned int *res)
443 {
444 	int i;
445 	if (f == '+') return true;
446 	for (i = 0; gflags[i].ch; i++)
447 	{
448 		if (gflags[i].ch != f) continue;
449 		*res |= gflags[i].value;
450 		return true;
451 	}
452 	return false;
453 }
454 
gflags_fromstr(gflags_t * gflags,const char * f,unsigned int * res)455 bool gflags_fromstr(gflags_t *gflags, const char *f, unsigned int *res)
456 {
457 	*res = 0;
458 	while (*f)
459 		if (!gflag_fromchar(gflags, *f++, res))
460 			return false;
461 	return true;
462 }
463 
464 /* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
465  * vim:ts=8
466  * vim:sw=8
467  * vim:noexpandtab
468  */
469