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