]> jfr.im git - irc/rqf/shadowircd.git/blob - modules/m_resv.c
Allow /ojoin !#channel/%#channel, if admin/halfop are enabled.
[irc/rqf/shadowircd.git] / modules / m_resv.c
1 /*
2 * ircd-ratbox: A slightly useful ircd.
3 * m_resv.c: Reserves(jupes) a nickname or channel.
4 *
5 * Copyright (C) 2001-2002 Hybrid Development Team
6 * Copyright (C) 2002-2005 ircd-ratbox development team
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 * USA
22 *
23 * $Id$
24 */
25
26 #include "stdinc.h"
27 #include "client.h"
28 #include "channel.h"
29 #include "ircd.h"
30 #include "numeric.h"
31 #include "s_serv.h"
32 #include "send.h"
33 #include "msg.h"
34 #include "parse.h"
35 #include "modules.h"
36 #include "s_conf.h"
37 #include "s_newconf.h"
38 #include "hash.h"
39 #include "logger.h"
40 #include "bandbi.h"
41 #include "operhash.h"
42
43 static int mo_resv(struct Client *, struct Client *, int, const char **);
44 static int ms_resv(struct Client *, struct Client *, int, const char **);
45 static int me_resv(struct Client *, struct Client *, int, const char **);
46 static int mo_unresv(struct Client *, struct Client *, int, const char **);
47 static int ms_unresv(struct Client *, struct Client *, int, const char **);
48 static int me_unresv(struct Client *, struct Client *, int, const char **);
49
50 struct Message resv_msgtab = {
51 "RESV", 0, 0, 0, MFLG_SLOW | MFLG_UNREG,
52 {mg_ignore, mg_not_oper, {ms_resv, 4}, {ms_resv, 4}, {me_resv, 5}, {mo_resv, 3}}
53 };
54
55 struct Message unresv_msgtab = {
56 "UNRESV", 0, 0, 0, MFLG_SLOW | MFLG_UNREG,
57 {mg_ignore, mg_not_oper, {ms_unresv, 3}, {ms_unresv, 3}, {me_unresv, 2}, {mo_unresv, 2}}
58 };
59
60 mapi_clist_av1 resv_clist[] = { &resv_msgtab, &unresv_msgtab, NULL };
61
62 DECLARE_MODULE_AV1(resv, NULL, NULL, resv_clist, NULL, NULL, "$Revision$");
63
64 static void parse_resv(struct Client *source_p, const char *name,
65 const char *reason, int temp_time, int propagated);
66 static void propagate_resv(struct Client *source_p, const char *target,
67 int temp_time, const char *name, const char *reason);
68 static void cluster_resv(struct Client *source_p, int temp_time,
69 const char *name, const char *reason);
70
71 static void handle_remote_unresv(struct Client *source_p, const char *name);
72 static void remove_resv(struct Client *source_p, const char *name, int propagated);
73
74 /*
75 * mo_resv()
76 * parv[0] = sender prefix
77 * parv[1] = channel/nick to forbid
78 * parv[2] = reason
79 */
80 static int
81 mo_resv(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
82 {
83 const char *name;
84 const char *reason;
85 const char *target_server = NULL;
86 int temp_time;
87 int loc = 1;
88 int propagated = ConfigFileEntry.use_propagated_bans;
89
90 if(!IsOperResv(source_p))
91 {
92 sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "resv");
93 return 0;
94 }
95
96 /* RESV [time] <name> [ON <server>] :<reason> */
97
98 if((temp_time = valid_temp_time(parv[loc])) >= 0)
99 loc++;
100 /* we just set temp_time to -1! */
101 else
102 temp_time = 0;
103
104 name = parv[loc];
105 loc++;
106
107 if((parc >= loc + 2) && (irccmp(parv[loc], "ON") == 0))
108 {
109 if(!IsOperRemoteBan(source_p))
110 {
111 sendto_one(source_p, form_str(ERR_NOPRIVS),
112 me.name, source_p->name, "remoteban");
113 return 0;
114 }
115
116 target_server = parv[loc + 1];
117 loc += 2;
118
119 /* Set as local-only. */
120 propagated = 0;
121 }
122
123 if(parc <= loc || EmptyString(parv[loc]))
124 {
125 sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, source_p->name, "RESV");
126 return 0;
127 }
128
129 reason = parv[loc];
130
131 /* remote resv.. */
132 if(target_server)
133 {
134 propagate_resv(source_p, target_server, temp_time, name, reason);
135
136 if(match(target_server, me.name) == 0)
137 return 0;
138 }
139 else if(!propagated && rb_dlink_list_length(&cluster_conf_list) > 0)
140 cluster_resv(source_p, temp_time, name, reason);
141
142 if(propagated && temp_time == 0)
143 {
144 sendto_one_notice(source_p, ":Cannot set a permanent global ban");
145 return 0;
146 }
147
148 parse_resv(source_p, name, reason, temp_time, propagated);
149
150 return 0;
151 }
152
153 /* ms_resv()
154 * parv[0] = sender prefix
155 * parv[1] = target server
156 * parv[2] = channel/nick to forbid
157 * parv[3] = reason
158 */
159 static int
160 ms_resv(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
161 {
162 /* parv[0] parv[1] parv[2] parv[3]
163 * oper target server resv reason
164 */
165 propagate_resv(source_p, parv[1], 0, parv[2], parv[3]);
166
167 if(!match(parv[1], me.name))
168 return 0;
169
170 if(!IsPerson(source_p))
171 return 0;
172
173 parse_resv(source_p, parv[2], parv[3], 0, 0);
174 return 0;
175 }
176
177 static int
178 me_resv(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
179 {
180 /* time name 0 :reason */
181 if(!IsPerson(source_p))
182 return 0;
183
184 parse_resv(source_p, parv[2], parv[4], atoi(parv[1]), 0);
185 return 0;
186 }
187
188 /* parse_resv()
189 *
190 * inputs - source_p if error messages wanted
191 * - thing to resv
192 * - reason for resv
193 * outputs -
194 * side effects - will parse the resv and create it if valid
195 */
196 static void
197 parse_resv(struct Client *source_p, const char *name, const char *reason, int temp_time, int propagated)
198 {
199 struct ConfItem *aconf;
200
201 if(!MyClient(source_p) &&
202 !find_shared_conf(source_p->username, source_p->host,
203 source_p->servptr->name,
204 (temp_time > 0) ? SHARED_TRESV : SHARED_PRESV))
205 return;
206
207 if(IsChannelName(name))
208 {
209 if(hash_find_resv(name))
210 {
211 sendto_one_notice(source_p,
212 ":A RESV has already been placed on channel: %s", name);
213 return;
214 }
215
216 if(strlen(name) > CHANNELLEN)
217 {
218 sendto_one_notice(source_p, ":Invalid RESV length: %s", name);
219 return;
220 }
221
222 if(strchr(reason, '"'))
223 {
224 sendto_one_notice(source_p, ":Invalid character '\"' in comment");
225 return;
226 }
227
228 aconf = make_conf();
229 aconf->status = CONF_RESV_CHANNEL;
230 aconf->port = 0;
231 aconf->created = rb_current_time();
232 aconf->host = rb_strdup(name);
233 aconf->passwd = rb_strdup(reason);
234 aconf->info.oper = operhash_add(get_oper_name(source_p));
235
236 if(propagated)
237 {
238 aconf->flags |= CONF_FLAGS_MYOPER | CONF_FLAGS_TEMPORARY;
239 aconf->hold = rb_current_time() + temp_time;
240 aconf->lifetime = aconf->hold;
241 replace_old_ban(aconf);
242 rb_dlinkAddAlloc(aconf, &prop_bans);
243
244 sendto_realops_snomask(SNO_GENERAL, L_ALL,
245 "%s added global %d min. RESV for [%s] [%s]",
246 get_oper_name(source_p), temp_time / 60,
247 name, reason);
248 ilog(L_KLINE, "R %s %d %s %s",
249 get_oper_name(source_p), temp_time / 60, name, reason);
250 sendto_one_notice(source_p, ":Added global %d min. RESV [%s]",
251 temp_time / 60, name);
252 sendto_server(NULL, NULL, CAP_BAN|CAP_TS6, NOCAPS,
253 ":%s BAN R * %s %lu %d %d * :%s",
254 source_p->id, aconf->host,
255 (unsigned long)aconf->created,
256 (int)(aconf->hold - aconf->created),
257 (int)(aconf->lifetime - aconf->created),
258 reason);
259 }
260 else if(temp_time > 0)
261 {
262 aconf->hold = rb_current_time() + temp_time;
263
264 sendto_realops_snomask(SNO_GENERAL, L_ALL,
265 "%s added temporary %d min. RESV for [%s] [%s]",
266 get_oper_name(source_p), temp_time / 60,
267 name, reason);
268 ilog(L_KLINE, "R %s %d %s %s",
269 get_oper_name(source_p), temp_time / 60, name, reason);
270 sendto_one_notice(source_p, ":Added temporary %d min. RESV [%s]",
271 temp_time / 60, name);
272 }
273 else
274 {
275 sendto_realops_snomask(SNO_GENERAL, L_ALL,
276 "%s added RESV for [%s] [%s]",
277 get_oper_name(source_p), name, reason);
278 ilog(L_KLINE, "R %s 0 %s %s",
279 get_oper_name(source_p), name, reason);
280 sendto_one_notice(source_p, ":Added RESV [%s]", name);
281
282 bandb_add(BANDB_RESV, source_p, aconf->host, NULL, aconf->passwd, NULL, 0);
283 }
284
285 add_to_resv_hash(aconf->host, aconf);
286 resv_chan_forcepart(aconf->host, aconf->passwd, temp_time);
287 }
288 else if(clean_resv_nick(name))
289 {
290 if(strlen(name) > NICKLEN * 2)
291 {
292 sendto_one_notice(source_p, ":Invalid RESV length: %s", name);
293 return;
294 }
295
296 if(strchr(reason, '"'))
297 {
298 sendto_one_notice(source_p, ":Invalid character '\"' in comment");
299 return;
300 }
301
302 if(!valid_wild_card_simple(name))
303 {
304 sendto_one_notice(source_p,
305 ":Please include at least %d non-wildcard "
306 "characters with the resv",
307 ConfigFileEntry.min_nonwildcard_simple);
308 return;
309 }
310
311 if(find_nick_resv_mask(name))
312 {
313 sendto_one_notice(source_p,
314 ":A RESV has already been placed on nick: %s", name);
315 return;
316 }
317
318 aconf = make_conf();
319 aconf->status = CONF_RESV_NICK;
320 aconf->port = 0;
321 aconf->created = rb_current_time();
322 aconf->host = rb_strdup(name);
323 aconf->passwd = rb_strdup(reason);
324 aconf->info.oper = operhash_add(get_oper_name(source_p));
325
326 if(propagated)
327 {
328 aconf->flags |= CONF_FLAGS_MYOPER | CONF_FLAGS_TEMPORARY;
329 aconf->hold = rb_current_time() + temp_time;
330 aconf->lifetime = aconf->hold;
331 replace_old_ban(aconf);
332 rb_dlinkAddAlloc(aconf, &prop_bans);
333
334 sendto_realops_snomask(SNO_GENERAL, L_ALL,
335 "%s added global %d min. RESV for [%s] [%s]",
336 get_oper_name(source_p), temp_time / 60,
337 name, reason);
338 ilog(L_KLINE, "R %s %d %s %s",
339 get_oper_name(source_p), temp_time / 60, name, reason);
340 sendto_one_notice(source_p, ":Added global %d min. RESV [%s]",
341 temp_time / 60, name);
342 sendto_server(NULL, NULL, CAP_BAN|CAP_TS6, NOCAPS,
343 ":%s BAN R * %s %lu %d %d * :%s",
344 source_p->id, aconf->host,
345 (unsigned long)aconf->created,
346 (int)(aconf->hold - aconf->created),
347 (int)(aconf->lifetime - aconf->created),
348 reason);
349 }
350 else if(temp_time > 0)
351 {
352 aconf->hold = rb_current_time() + temp_time;
353
354 sendto_realops_snomask(SNO_GENERAL, L_ALL,
355 "%s added temporary %d min. RESV for [%s] [%s]",
356 get_oper_name(source_p), temp_time / 60,
357 name, reason);
358 ilog(L_KLINE, "R %s %d %s %s",
359 get_oper_name(source_p), temp_time / 60, name, reason);
360 sendto_one_notice(source_p, ":Added temporary %d min. RESV [%s]",
361 temp_time / 60, name);
362 }
363 else
364 {
365 sendto_realops_snomask(SNO_GENERAL, L_ALL,
366 "%s added RESV for [%s] [%s]",
367 get_oper_name(source_p), name, reason);
368 ilog(L_KLINE, "R %s 0 %s %s",
369 get_oper_name(source_p), name, reason);
370 sendto_one_notice(source_p, ":Added RESV [%s]", name);
371
372 bandb_add(BANDB_RESV, source_p, aconf->host, NULL, aconf->passwd, NULL, 0);
373 }
374
375 rb_dlinkAddAlloc(aconf, &resv_conf_list);
376 }
377 else
378 sendto_one_notice(source_p, ":You have specified an invalid resv: [%s]", name);
379 }
380
381 static void
382 propagate_resv(struct Client *source_p, const char *target,
383 int temp_time, const char *name, const char *reason)
384 {
385 if(!temp_time)
386 {
387 sendto_match_servs(source_p, target,
388 CAP_CLUSTER, NOCAPS, "RESV %s %s :%s", target, name, reason);
389 sendto_match_servs(source_p, target,
390 CAP_ENCAP, CAP_CLUSTER,
391 "ENCAP %s RESV %d %s 0 :%s", target, temp_time, name, reason);
392 }
393 else
394 sendto_match_servs(source_p, target,
395 CAP_ENCAP, NOCAPS,
396 "ENCAP %s RESV %d %s 0 :%s", target, temp_time, name, reason);
397 }
398
399 static void
400 cluster_resv(struct Client *source_p, int temp_time, const char *name, const char *reason)
401 {
402 struct remote_conf *shared_p;
403 rb_dlink_node *ptr;
404
405 RB_DLINK_FOREACH(ptr, cluster_conf_list.head)
406 {
407 shared_p = ptr->data;
408
409 /* old protocol cant handle temps, and we dont really want
410 * to convert them to perm.. --fl
411 */
412 if(!temp_time)
413 {
414 if(!(shared_p->flags & SHARED_PRESV))
415 continue;
416
417 sendto_match_servs(source_p, shared_p->server,
418 CAP_CLUSTER, NOCAPS,
419 "RESV %s %s :%s", shared_p->server, name, reason);
420 sendto_match_servs(source_p, shared_p->server,
421 CAP_ENCAP, CAP_CLUSTER,
422 "ENCAP %s RESV 0 %s 0 :%s",
423 shared_p->server, name, reason);
424 }
425 else if(shared_p->flags & SHARED_TRESV)
426 sendto_match_servs(source_p, shared_p->server,
427 CAP_ENCAP, NOCAPS,
428 "ENCAP %s RESV %d %s 0 :%s",
429 shared_p->server, temp_time, name, reason);
430 }
431 }
432
433
434 /*
435 * mo_unresv()
436 * parv[0] = sender prefix
437 * parv[1] = channel/nick to unforbid
438 */
439 static int
440 mo_unresv(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
441 {
442 int propagated = 1;
443
444 if(!IsOperResv(source_p))
445 {
446 sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "resv");
447 return 0;
448 }
449
450 if((parc == 4) && (irccmp(parv[2], "ON") == 0))
451 {
452 if(!IsOperRemoteBan(source_p))
453 {
454 sendto_one(source_p, form_str(ERR_NOPRIVS),
455 me.name, source_p->name, "remoteban");
456 return 0;
457 }
458
459 propagate_generic(source_p, "UNRESV", parv[3], CAP_CLUSTER, "%s", parv[1]);
460
461 if(match(parv[3], me.name) == 0)
462 return 0;
463
464 propagated = 0;
465 }
466 #if 0
467 else if(rb_dlink_list_length(&cluster_conf_list) > 0)
468 cluster_generic(source_p, "UNRESV", SHARED_UNRESV, CAP_CLUSTER, "%s", parv[1]);
469 #endif
470 /* cluster{} moved to remove_resv */
471
472 remove_resv(source_p, parv[1], propagated);
473 return 0;
474 }
475
476 /* ms_unresv()
477 * parv[0] = sender prefix
478 * parv[1] = target server
479 * parv[2] = resv to remove
480 */
481 static int
482 ms_unresv(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
483 {
484 /* parv[0] parv[1] parv[2]
485 * oper target server resv to remove
486 */
487 propagate_generic(source_p, "UNRESV", parv[1], CAP_CLUSTER, "%s", parv[2]);
488
489 if(!match(parv[1], me.name))
490 return 0;
491
492 if(!IsPerson(source_p))
493 return 0;
494
495 handle_remote_unresv(source_p, parv[2]);
496 return 0;
497 }
498
499 static int
500 me_unresv(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
501 {
502 /* name */
503 if(!IsPerson(source_p))
504 return 0;
505
506 handle_remote_unresv(source_p, parv[1]);
507 return 0;
508 }
509
510 static void
511 handle_remote_unresv(struct Client *source_p, const char *name)
512 {
513 if(!find_shared_conf(source_p->username, source_p->host,
514 source_p->servptr->name, SHARED_UNRESV))
515 return;
516
517 remove_resv(source_p, name, 0);
518
519 return;
520 }
521
522 static void
523 remove_resv(struct Client *source_p, const char *name, int propagated)
524 {
525 struct ConfItem *aconf = NULL;
526 rb_dlink_node *ptr;
527
528 if(IsChannelName(name))
529 {
530 if((aconf = hash_find_resv(name)) == NULL)
531 {
532 if(propagated && rb_dlink_list_length(&cluster_conf_list))
533 cluster_generic(source_p, "UNXLINE", SHARED_UNXLINE, CAP_CLUSTER, "%s", name);
534
535 sendto_one_notice(source_p, ":No RESV for %s", name);
536 return;
537 }
538
539 if(aconf->lifetime)
540 {
541 if(!propagated)
542 {
543 sendto_one_notice(source_p, ":Cannot remove global RESV %s on specific servers", name);
544 return;
545 }
546 ptr = rb_dlinkFind(aconf, &prop_bans);
547 if(ptr == NULL)
548 return;
549 sendto_one_notice(source_p, ":RESV for [%s] is removed", name);
550 sendto_realops_snomask(SNO_GENERAL, L_ALL,
551 "%s has removed the global RESV for: [%s]",
552 get_oper_name(source_p), name);
553 ilog(L_KLINE, "UR %s %s", get_oper_name(source_p), name);
554 if(aconf->created < rb_current_time())
555 aconf->created = rb_current_time();
556 else
557 aconf->created++;
558 aconf->hold = aconf->created;
559 operhash_delete(aconf->info.oper);
560 aconf->info.oper = operhash_add(get_oper_name(source_p));
561 aconf->flags |= CONF_FLAGS_MYOPER | CONF_FLAGS_TEMPORARY;
562 sendto_server(NULL, NULL, CAP_BAN|CAP_TS6, NOCAPS,
563 ":%s BAN R * %s %lu %d %d * :*",
564 source_p->id, aconf->host,
565 (unsigned long)aconf->created,
566 0,
567 (int)(aconf->lifetime - aconf->created));
568 deactivate_conf(aconf, ptr);
569 return;
570 }
571 else if(propagated && rb_dlink_list_length(&cluster_conf_list) > 0)
572 cluster_generic(source_p, "UNRESV", SHARED_UNRESV, CAP_CLUSTER, "%s", name);
573
574 sendto_one_notice(source_p, ":RESV for [%s] is removed", name);
575 ilog(L_KLINE, "UR %s %s", get_oper_name(source_p), name);
576 if(!aconf->hold)
577 {
578 bandb_del(BANDB_RESV, aconf->host, NULL);
579 sendto_realops_snomask(SNO_GENERAL, L_ALL,
580 "%s has removed the RESV for: [%s]",
581 get_oper_name(source_p), name);
582 }
583 else
584 {
585 sendto_realops_snomask(SNO_GENERAL, L_ALL,
586 "%s has removed the temporary RESV for: [%s]",
587 get_oper_name(source_p), name);
588 }
589 del_from_resv_hash(name, aconf);
590 }
591 else
592 {
593 RB_DLINK_FOREACH(ptr, resv_conf_list.head)
594 {
595 aconf = ptr->data;
596
597 if(irccmp(aconf->host, name))
598 aconf = NULL;
599 else
600 break;
601 }
602
603 if(aconf == NULL)
604 {
605 if(propagated && rb_dlink_list_length(&cluster_conf_list))
606 cluster_generic(source_p, "UNXLINE", SHARED_UNXLINE, CAP_CLUSTER, "%s", name);
607
608 sendto_one_notice(source_p, ":No RESV for %s", name);
609 return;
610 }
611
612 if(aconf->lifetime)
613 {
614 if(!propagated)
615 {
616 sendto_one_notice(source_p, ":Cannot remove global RESV %s on specific servers", name);
617 return;
618 }
619 ptr = rb_dlinkFind(aconf, &prop_bans);
620 if(ptr == NULL)
621 return;
622 sendto_one_notice(source_p, ":RESV for [%s] is removed", name);
623 sendto_realops_snomask(SNO_GENERAL, L_ALL,
624 "%s has removed the global RESV for: [%s]",
625 get_oper_name(source_p), name);
626 ilog(L_KLINE, "UR %s %s", get_oper_name(source_p), name);
627 if(aconf->created < rb_current_time())
628 aconf->created = rb_current_time();
629 else
630 aconf->created++;
631 aconf->hold = aconf->created;
632 operhash_delete(aconf->info.oper);
633 aconf->info.oper = operhash_add(get_oper_name(source_p));
634 aconf->flags |= CONF_FLAGS_MYOPER | CONF_FLAGS_TEMPORARY;
635 sendto_server(NULL, NULL, CAP_BAN|CAP_TS6, NOCAPS,
636 ":%s BAN R * %s %lu %d %d * :*",
637 source_p->id, aconf->host,
638 (unsigned long)aconf->created,
639 0,
640 (int)(aconf->lifetime - aconf->created));
641 deactivate_conf(aconf, ptr);
642 return;
643 }
644 else if(propagated && rb_dlink_list_length(&cluster_conf_list) > 0)
645 cluster_generic(source_p, "UNRESV", SHARED_UNRESV, CAP_CLUSTER, "%s", name);
646
647 sendto_one_notice(source_p, ":RESV for [%s] is removed", name);
648 ilog(L_KLINE, "UR %s %s", get_oper_name(source_p), name);
649 if(!aconf->hold)
650 {
651 bandb_del(BANDB_RESV, aconf->host, NULL);
652 sendto_realops_snomask(SNO_GENERAL, L_ALL,
653 "%s has removed the RESV for: [%s]",
654 get_oper_name(source_p), name);
655 }
656 else
657 {
658 sendto_realops_snomask(SNO_GENERAL, L_ALL,
659 "%s has removed the temporary RESV for: [%s]",
660 get_oper_name(source_p), name);
661 }
662 /* already have ptr from the loop above.. */
663 rb_dlinkDestroy(ptr, &resv_conf_list);
664 }
665 free_conf(aconf);
666
667 return;
668 }