]> jfr.im git - solanum.git/blob - src/channel.c
override: only engage override code if we're needing to authorize a WRITE to a channe...
[solanum.git] / src / channel.c
1 /*
2 * ircd-ratbox: A slightly useful ircd.
3 * channel.c: Controls channels.
4 *
5 * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
6 * Copyright (C) 1996-2002 Hybrid Development Team
7 * Copyright (C) 2002-2005 ircd-ratbox development team
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 * USA
23 *
24 * $Id: channel.c 3580 2007-11-07 23:45:14Z jilles $
25 */
26
27 #include "stdinc.h"
28 #include "channel.h"
29 #include "chmode.h"
30 #include "client.h"
31 #include "common.h"
32 #include "hash.h"
33 #include "hook.h"
34 #include "match.h"
35 #include "ircd.h"
36 #include "numeric.h"
37 #include "s_serv.h" /* captab */
38 #include "s_user.h"
39 #include "send.h"
40 #include "whowas.h"
41 #include "s_conf.h" /* ConfigFileEntry, ConfigChannel */
42 #include "s_newconf.h"
43 #include "logger.h"
44 #include "ipv4_from_ipv6.h"
45 #include "s_assert.h"
46
47 struct config_channel_entry ConfigChannel;
48 rb_dlink_list global_channel_list;
49 static rb_bh *channel_heap;
50 static rb_bh *ban_heap;
51 static rb_bh *topic_heap;
52 static rb_bh *member_heap;
53
54 static void free_topic(struct Channel *chptr);
55
56 static int h_can_join;
57 static int h_can_send;
58 int h_get_channel_access;
59
60 /* init_channels()
61 *
62 * input -
63 * output -
64 * side effects - initialises the various blockheaps
65 */
66 void
67 init_channels(void)
68 {
69 channel_heap = rb_bh_create(sizeof(struct Channel), CHANNEL_HEAP_SIZE, "channel_heap");
70 ban_heap = rb_bh_create(sizeof(struct Ban), BAN_HEAP_SIZE, "ban_heap");
71 topic_heap = rb_bh_create(TOPICLEN + 1 + USERHOST_REPLYLEN, TOPIC_HEAP_SIZE, "topic_heap");
72 member_heap = rb_bh_create(sizeof(struct membership), MEMBER_HEAP_SIZE, "member_heap");
73
74 h_can_join = register_hook("can_join");
75 h_can_send = register_hook("can_send");
76 h_get_channel_access = register_hook("get_channel_access");
77 }
78
79 /*
80 * allocate_channel - Allocates a channel
81 */
82 struct Channel *
83 allocate_channel(const char *chname)
84 {
85 struct Channel *chptr;
86 chptr = rb_bh_alloc(channel_heap);
87 chptr->chname = rb_strdup(chname);
88 return (chptr);
89 }
90
91 void
92 free_channel(struct Channel *chptr)
93 {
94 rb_free(chptr->chname);
95 rb_free(chptr->mode_lock);
96 rb_bh_free(channel_heap, chptr);
97 }
98
99 struct Ban *
100 allocate_ban(const char *banstr, const char *who, const char *forward)
101 {
102 struct Ban *bptr;
103 bptr = rb_bh_alloc(ban_heap);
104 bptr->banstr = rb_strdup(banstr);
105 bptr->who = rb_strdup(who);
106 bptr->forward = forward ? rb_strdup(forward) : NULL;
107
108 return (bptr);
109 }
110
111 void
112 free_ban(struct Ban *bptr)
113 {
114 rb_free(bptr->banstr);
115 rb_free(bptr->who);
116 rb_free(bptr->forward);
117 rb_bh_free(ban_heap, bptr);
118 }
119
120 /*
121 * send_channel_join()
122 *
123 * input - channel to join, client joining.
124 * output - none
125 * side effects - none
126 */
127 void
128 send_channel_join(struct Channel *chptr, struct Client *client_p)
129 {
130 if (!IsClient(client_p))
131 return;
132
133 sendto_channel_local_with_capability(ALL_MEMBERS, NOCAPS, CLICAP_EXTENDED_JOIN, chptr, ":%s!%s@%s JOIN %s",
134 client_p->name, client_p->username, client_p->host, chptr->chname);
135
136 sendto_channel_local_with_capability(ALL_MEMBERS, CLICAP_EXTENDED_JOIN, NOCAPS, chptr, ":%s!%s@%s JOIN %s %s :%s",
137 client_p->name, client_p->username, client_p->host, chptr->chname,
138 EmptyString(client_p->user->suser) ? "*" : client_p->user->suser,
139 client_p->info);
140
141 /* Send away message to away-notify enabled clients. */
142 if (client_p->user->away)
143 sendto_channel_local_with_capability_butone(client_p, ALL_MEMBERS, CLICAP_AWAY_NOTIFY, NOCAPS, chptr,
144 ":%s!%s@%s AWAY :%s", client_p->name, client_p->username,
145 client_p->host, client_p->user->away);
146 }
147
148 /* find_channel_membership()
149 *
150 * input - channel to find them in, client to find
151 * output - membership of client in channel, else NULL
152 * side effects -
153 */
154 struct membership *
155 find_channel_membership(struct Channel *chptr, struct Client *client_p)
156 {
157 struct membership *msptr;
158 rb_dlink_node *ptr;
159
160 if(!IsClient(client_p))
161 return NULL;
162
163 /* Pick the most efficient list to use to be nice to things like
164 * CHANSERV which could be in a large number of channels
165 */
166 if(rb_dlink_list_length(&chptr->members) < rb_dlink_list_length(&client_p->user->channel))
167 {
168 RB_DLINK_FOREACH(ptr, chptr->members.head)
169 {
170 msptr = ptr->data;
171
172 if(msptr->client_p == client_p)
173 return msptr;
174 }
175 }
176 else
177 {
178 RB_DLINK_FOREACH(ptr, client_p->user->channel.head)
179 {
180 msptr = ptr->data;
181
182 if(msptr->chptr == chptr)
183 return msptr;
184 }
185 }
186
187 return NULL;
188 }
189
190 /* find_channel_status()
191 *
192 * input - membership to get status for, whether we can combine flags
193 * output - flags of user on channel
194 * side effects -
195 */
196 const char *
197 find_channel_status(struct membership *msptr, int combine)
198 {
199 static char buffer[3];
200 char *p;
201
202 p = buffer;
203
204 if(is_chanop(msptr))
205 {
206 if(!combine)
207 return "@";
208 *p++ = '@';
209 }
210
211 if(is_voiced(msptr))
212 *p++ = '+';
213
214 *p = '\0';
215 return buffer;
216 }
217
218 /* add_user_to_channel()
219 *
220 * input - channel to add client to, client to add, channel flags
221 * output -
222 * side effects - user is added to channel
223 */
224 void
225 add_user_to_channel(struct Channel *chptr, struct Client *client_p, int flags)
226 {
227 struct membership *msptr;
228
229 s_assert(client_p->user != NULL);
230 if(client_p->user == NULL)
231 return;
232
233 msptr = rb_bh_alloc(member_heap);
234
235 msptr->chptr = chptr;
236 msptr->client_p = client_p;
237 msptr->flags = flags;
238
239 rb_dlinkAdd(msptr, &msptr->usernode, &client_p->user->channel);
240 rb_dlinkAdd(msptr, &msptr->channode, &chptr->members);
241
242 if(MyClient(client_p))
243 rb_dlinkAdd(msptr, &msptr->locchannode, &chptr->locmembers);
244 }
245
246 /* remove_user_from_channel()
247 *
248 * input - membership pointer to remove from channel
249 * output -
250 * side effects - membership (thus user) is removed from channel
251 */
252 void
253 remove_user_from_channel(struct membership *msptr)
254 {
255 struct Client *client_p;
256 struct Channel *chptr;
257 s_assert(msptr != NULL);
258 if(msptr == NULL)
259 return;
260
261 client_p = msptr->client_p;
262 chptr = msptr->chptr;
263
264 rb_dlinkDelete(&msptr->usernode, &client_p->user->channel);
265 rb_dlinkDelete(&msptr->channode, &chptr->members);
266
267 if(client_p->servptr == &me)
268 rb_dlinkDelete(&msptr->locchannode, &chptr->locmembers);
269
270 if(!(chptr->mode.mode & MODE_PERMANENT) && rb_dlink_list_length(&chptr->members) <= 0)
271 destroy_channel(chptr);
272
273 rb_bh_free(member_heap, msptr);
274
275 return;
276 }
277
278 /* remove_user_from_channels()
279 *
280 * input - user to remove from all channels
281 * output -
282 * side effects - user is removed from all channels
283 */
284 void
285 remove_user_from_channels(struct Client *client_p)
286 {
287 struct Channel *chptr;
288 struct membership *msptr;
289 rb_dlink_node *ptr;
290 rb_dlink_node *next_ptr;
291
292 if(client_p == NULL)
293 return;
294
295 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, client_p->user->channel.head)
296 {
297 msptr = ptr->data;
298 chptr = msptr->chptr;
299
300 rb_dlinkDelete(&msptr->channode, &chptr->members);
301
302 if(client_p->servptr == &me)
303 rb_dlinkDelete(&msptr->locchannode, &chptr->locmembers);
304
305 if(!(chptr->mode.mode & MODE_PERMANENT) && rb_dlink_list_length(&chptr->members) <= 0)
306 destroy_channel(chptr);
307
308 rb_bh_free(member_heap, msptr);
309 }
310
311 client_p->user->channel.head = client_p->user->channel.tail = NULL;
312 client_p->user->channel.length = 0;
313 }
314
315 /* invalidate_bancache_user()
316 *
317 * input - user to invalidate ban cache for
318 * output -
319 * side effects - ban cache is invalidated for all memberships of that user
320 * to be used after a nick change
321 */
322 void
323 invalidate_bancache_user(struct Client *client_p)
324 {
325 struct membership *msptr;
326 rb_dlink_node *ptr;
327
328 if(client_p == NULL)
329 return;
330
331 RB_DLINK_FOREACH(ptr, client_p->user->channel.head)
332 {
333 msptr = ptr->data;
334 msptr->bants = 0;
335 msptr->flags &= ~CHFL_BANNED;
336 }
337 }
338
339 /* check_channel_name()
340 *
341 * input - channel name
342 * output - 1 if valid channel name, else 0
343 * side effects -
344 */
345 int
346 check_channel_name(const char *name)
347 {
348 s_assert(name != NULL);
349 if(name == NULL)
350 return 0;
351
352 for (; *name; ++name)
353 {
354 if(!IsChanChar(*name))
355 return 0;
356 }
357
358 return 1;
359 }
360
361 /* free_channel_list()
362 *
363 * input - rb_dlink list to free
364 * output -
365 * side effects - list of b/e/I modes is cleared
366 */
367 void
368 free_channel_list(rb_dlink_list * list)
369 {
370 rb_dlink_node *ptr;
371 rb_dlink_node *next_ptr;
372 struct Ban *actualBan;
373
374 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, list->head)
375 {
376 actualBan = ptr->data;
377 free_ban(actualBan);
378 }
379
380 list->head = list->tail = NULL;
381 list->length = 0;
382 }
383
384 /* destroy_channel()
385 *
386 * input - channel to destroy
387 * output -
388 * side effects - channel is obliterated
389 */
390 void
391 destroy_channel(struct Channel *chptr)
392 {
393 rb_dlink_node *ptr, *next_ptr;
394
395 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, chptr->invites.head)
396 {
397 del_invite(chptr, ptr->data);
398 }
399
400 /* free all bans/exceptions/denies */
401 free_channel_list(&chptr->banlist);
402 free_channel_list(&chptr->exceptlist);
403 free_channel_list(&chptr->invexlist);
404 free_channel_list(&chptr->quietlist);
405
406 /* Free the topic */
407 free_topic(chptr);
408
409 rb_dlinkDelete(&chptr->node, &global_channel_list);
410 del_from_channel_hash(chptr->chname, chptr);
411 free_channel(chptr);
412 }
413
414 /* channel_pub_or_secret()
415 *
416 * input - channel
417 * output - "=" if public, "@" if secret, else "*"
418 * side effects -
419 */
420 static const char *
421 channel_pub_or_secret(struct Channel *chptr)
422 {
423 if(PubChannel(chptr))
424 return ("=");
425 else if(SecretChannel(chptr))
426 return ("@");
427 return ("*");
428 }
429
430 /* channel_member_names()
431 *
432 * input - channel to list, client to list to, show endofnames
433 * output -
434 * side effects - client is given list of users on channel
435 */
436 void
437 channel_member_names(struct Channel *chptr, struct Client *client_p, int show_eon)
438 {
439 struct membership *msptr;
440 struct Client *target_p;
441 rb_dlink_node *ptr;
442 char lbuf[BUFSIZE];
443 char *t;
444 int mlen;
445 int tlen;
446 int cur_len;
447 int is_member;
448 int stack = IsCapable(client_p, CLICAP_MULTI_PREFIX);
449
450 if(ShowChannel(client_p, chptr))
451 {
452 is_member = IsMember(client_p, chptr);
453
454 cur_len = mlen = rb_sprintf(lbuf, form_str(RPL_NAMREPLY),
455 me.name, client_p->name,
456 channel_pub_or_secret(chptr), chptr->chname);
457
458 t = lbuf + cur_len;
459
460 RB_DLINK_FOREACH(ptr, chptr->members.head)
461 {
462 msptr = ptr->data;
463 target_p = msptr->client_p;
464
465 if(IsInvisible(target_p) && !is_member)
466 continue;
467
468 if (IsCapable(client_p, CLICAP_USERHOST_IN_NAMES))
469 {
470 /* space, possible "@+" prefix */
471 if (cur_len + strlen(target_p->name) + strlen(target_p->username) + strlen(target_p->host) + 5 >= BUFSIZE - 5)
472 {
473 *(t - 1) = '\0';
474 sendto_one(client_p, "%s", lbuf);
475 cur_len = mlen;
476 t = lbuf + mlen;
477 }
478
479 tlen = rb_sprintf(t, "%s%s!%s@%s ", find_channel_status(msptr, stack),
480 target_p->name, target_p->username, target_p->host);
481 }
482 else
483 {
484 /* space, possible "@+" prefix */
485 if(cur_len + strlen(target_p->name) + 3 >= BUFSIZE - 3)
486 {
487 *(t - 1) = '\0';
488 sendto_one(client_p, "%s", lbuf);
489 cur_len = mlen;
490 t = lbuf + mlen;
491 }
492
493 tlen = rb_sprintf(t, "%s%s ", find_channel_status(msptr, stack),
494 target_p->name);
495 }
496
497 cur_len += tlen;
498 t += tlen;
499 }
500
501 /* The old behaviour here was to always output our buffer,
502 * even if there are no clients we can show. This happens
503 * when a client does "NAMES" with no parameters, and all
504 * the clients on a -sp channel are +i. I dont see a good
505 * reason for keeping that behaviour, as it just wastes
506 * bandwidth. --anfl
507 */
508 if(cur_len != mlen)
509 {
510 *(t - 1) = '\0';
511 sendto_one(client_p, "%s", lbuf);
512 }
513 }
514
515 if(show_eon)
516 sendto_one(client_p, form_str(RPL_ENDOFNAMES),
517 me.name, client_p->name, chptr->chname);
518 }
519
520 /* del_invite()
521 *
522 * input - channel to remove invite from, client to remove
523 * output -
524 * side effects - user is removed from invite list, if exists
525 */
526 void
527 del_invite(struct Channel *chptr, struct Client *who)
528 {
529 rb_dlinkFindDestroy(who, &chptr->invites);
530 rb_dlinkFindDestroy(chptr, &who->user->invited);
531 }
532
533 /* is_banned_list()
534 *
535 * input - channel to check bans for, ban list (banlist or quietlist),
536 * user to check bans against, optional prebuilt buffers,
537 * optional forward channel pointer
538 * output - 1 if banned, else 0
539 * side effects -
540 */
541 static int
542 is_banned_list(struct Channel *chptr, rb_dlink_list *list,
543 struct Client *who, struct membership *msptr,
544 const char *s, const char *s2, const char **forward)
545 {
546 char src_host[NICKLEN + USERLEN + HOSTLEN + 6];
547 char src_iphost[NICKLEN + USERLEN + HOSTLEN + 6];
548 char src_althost[NICKLEN + USERLEN + HOSTLEN + 6];
549 char src_ip4host[NICKLEN + USERLEN + HOSTLEN + 6];
550 char *s3 = NULL;
551 char *s4 = NULL;
552 struct sockaddr_in ip4;
553 rb_dlink_node *ptr;
554 struct Ban *actualBan = NULL;
555 struct Ban *actualExcept = NULL;
556
557 if(!MyClient(who))
558 return 0;
559
560 /* if the buffers havent been built, do it here */
561 if(s == NULL)
562 {
563 rb_sprintf(src_host, "%s!%s@%s", who->name, who->username, who->host);
564 rb_sprintf(src_iphost, "%s!%s@%s", who->name, who->username, who->sockhost);
565
566 s = src_host;
567 s2 = src_iphost;
568 }
569 if(who->localClient->mangledhost != NULL)
570 {
571 /* if host mangling mode enabled, also check their real host */
572 if(!strcmp(who->host, who->localClient->mangledhost))
573 {
574 rb_sprintf(src_althost, "%s!%s@%s", who->name, who->username, who->orighost);
575 s3 = src_althost;
576 }
577 /* if host mangling mode not enabled and no other spoof,
578 * also check the mangled form of their host */
579 else if (!IsDynSpoof(who))
580 {
581 rb_sprintf(src_althost, "%s!%s@%s", who->name, who->username, who->localClient->mangledhost);
582 s3 = src_althost;
583 }
584 }
585 #ifdef RB_IPV6
586 if(who->localClient->ip.ss_family == AF_INET6 &&
587 ipv4_from_ipv6((const struct sockaddr_in6 *)&who->localClient->ip, &ip4))
588 {
589 rb_sprintf(src_ip4host, "%s!%s@", who->name, who->username);
590 s4 = src_ip4host + strlen(src_ip4host);
591 rb_inet_ntop_sock((struct sockaddr *)&ip4,
592 s4, src_ip4host + sizeof src_ip4host - s4);
593 s4 = src_ip4host;
594 }
595 #endif
596
597 RB_DLINK_FOREACH(ptr, list->head)
598 {
599 actualBan = ptr->data;
600 if(match(actualBan->banstr, s) ||
601 match(actualBan->banstr, s2) ||
602 match_cidr(actualBan->banstr, s2) ||
603 match_extban(actualBan->banstr, who, chptr, CHFL_BAN) ||
604 (s3 != NULL && match(actualBan->banstr, s3))
605 #ifdef RB_IPV6
606 ||
607 (s4 != NULL && (match(actualBan->banstr, s4) || match_cidr(actualBan->banstr, s4)))
608 #endif
609 )
610 break;
611 else
612 actualBan = NULL;
613 }
614
615 if((actualBan != NULL) && ConfigChannel.use_except)
616 {
617 RB_DLINK_FOREACH(ptr, chptr->exceptlist.head)
618 {
619 actualExcept = ptr->data;
620
621 /* theyre exempted.. */
622 if(match(actualExcept->banstr, s) ||
623 match(actualExcept->banstr, s2) ||
624 match_cidr(actualExcept->banstr, s2) ||
625 match_extban(actualExcept->banstr, who, chptr, CHFL_EXCEPTION) ||
626 (s3 != NULL && match(actualExcept->banstr, s3)))
627 {
628 /* cache the fact theyre not banned */
629 if(msptr != NULL)
630 {
631 msptr->bants = chptr->bants;
632 msptr->flags &= ~CHFL_BANNED;
633 }
634
635 return CHFL_EXCEPTION;
636 }
637 }
638 }
639
640 /* cache the banned/not banned status */
641 if(msptr != NULL)
642 {
643 msptr->bants = chptr->bants;
644
645 if(actualBan != NULL)
646 {
647 msptr->flags |= CHFL_BANNED;
648 return CHFL_BAN;
649 }
650 else
651 {
652 msptr->flags &= ~CHFL_BANNED;
653 return 0;
654 }
655 }
656
657 if (actualBan && actualBan->forward && forward)
658 *forward = actualBan->forward;
659
660 return ((actualBan ? CHFL_BAN : 0));
661 }
662
663 /* is_banned()
664 *
665 * input - channel to check bans for, user to check bans against
666 * optional prebuilt buffers, optional forward channel pointer
667 * output - 1 if banned, else 0
668 * side effects -
669 */
670 int
671 is_banned(struct Channel *chptr, struct Client *who, struct membership *msptr,
672 const char *s, const char *s2, const char **forward)
673 {
674 return is_banned_list(chptr, &chptr->banlist, who, msptr, s, s2,
675 forward);
676 }
677
678 /* is_quieted()
679 *
680 * input - channel to check bans for, user to check bans against
681 * optional prebuilt buffers
682 * output - 1 if banned, else 0
683 * side effects -
684 */
685 int
686 is_quieted(struct Channel *chptr, struct Client *who, struct membership *msptr,
687 const char *s, const char *s2)
688 {
689 return is_banned_list(chptr, &chptr->quietlist, who, msptr, s, s2,
690 NULL);
691 }
692
693 /* can_join()
694 *
695 * input - client to check, channel to check for, key
696 * output - reason for not being able to join, else 0, channel name to forward to
697 * side effects -
698 * caveats - this function should only be called on a local user.
699 */
700 int
701 can_join(struct Client *source_p, struct Channel *chptr, const char *key, const char **forward)
702 {
703 rb_dlink_node *invite = NULL;
704 rb_dlink_node *ptr;
705 struct Ban *invex = NULL;
706 char src_host[NICKLEN + USERLEN + HOSTLEN + 6];
707 char src_iphost[NICKLEN + USERLEN + HOSTLEN + 6];
708 char src_althost[NICKLEN + USERLEN + HOSTLEN + 6];
709 int use_althost = 0;
710 int i = 0;
711 hook_data_channel moduledata;
712
713 s_assert(source_p->localClient != NULL);
714
715 moduledata.client = source_p;
716 moduledata.chptr = chptr;
717 moduledata.approved = 0;
718
719 rb_sprintf(src_host, "%s!%s@%s", source_p->name, source_p->username, source_p->host);
720 rb_sprintf(src_iphost, "%s!%s@%s", source_p->name, source_p->username, source_p->sockhost);
721 if(source_p->localClient->mangledhost != NULL)
722 {
723 /* if host mangling mode enabled, also check their real host */
724 if(!strcmp(source_p->host, source_p->localClient->mangledhost))
725 {
726 rb_sprintf(src_althost, "%s!%s@%s", source_p->name, source_p->username, source_p->orighost);
727 use_althost = 1;
728 }
729 /* if host mangling mode not enabled and no other spoof,
730 * also check the mangled form of their host */
731 else if (!IsDynSpoof(source_p))
732 {
733 rb_sprintf(src_althost, "%s!%s@%s", source_p->name, source_p->username, source_p->localClient->mangledhost);
734 use_althost = 1;
735 }
736 }
737
738 if((is_banned(chptr, source_p, NULL, src_host, src_iphost, forward)) == CHFL_BAN)
739 {
740 moduledata.approved = ERR_BANNEDFROMCHAN;
741 goto finish_join_check;
742 }
743
744 if(*chptr->mode.key && (EmptyString(key) || irccmp(chptr->mode.key, key)))
745 {
746 moduledata.approved = ERR_BADCHANNELKEY;
747 goto finish_join_check;
748 }
749
750 /* All checks from this point on will forward... */
751 if(forward)
752 *forward = chptr->mode.forward;
753
754 if(chptr->mode.mode & MODE_INVITEONLY)
755 {
756 RB_DLINK_FOREACH(invite, source_p->user->invited.head)
757 {
758 if(invite->data == chptr)
759 break;
760 }
761 if(invite == NULL)
762 {
763 if(!ConfigChannel.use_invex)
764 moduledata.approved = ERR_INVITEONLYCHAN;
765 RB_DLINK_FOREACH(ptr, chptr->invexlist.head)
766 {
767 invex = ptr->data;
768 if(match(invex->banstr, src_host)
769 || match(invex->banstr, src_iphost)
770 || match_cidr(invex->banstr, src_iphost)
771 || match_extban(invex->banstr, source_p, chptr, CHFL_INVEX)
772 || (use_althost && match(invex->banstr, src_althost)))
773 break;
774 }
775 if(ptr == NULL)
776 moduledata.approved = ERR_INVITEONLYCHAN;
777 }
778 }
779
780 if(chptr->mode.limit &&
781 rb_dlink_list_length(&chptr->members) >= (unsigned long) chptr->mode.limit)
782 i = ERR_CHANNELISFULL;
783 if(chptr->mode.mode & MODE_REGONLY && EmptyString(source_p->user->suser))
784 i = ERR_NEEDREGGEDNICK;
785 /* join throttling stuff --nenolod */
786 else if(chptr->mode.join_num > 0 && chptr->mode.join_time > 0)
787 {
788 if ((rb_current_time() - chptr->join_delta <=
789 chptr->mode.join_time) && (chptr->join_count >=
790 chptr->mode.join_num))
791 i = ERR_THROTTLE;
792 }
793
794 /* allow /invite to override +l/+r/+j also -- jilles */
795 if (i != 0 && invite == NULL)
796 {
797 RB_DLINK_FOREACH(invite, source_p->user->invited.head)
798 {
799 if(invite->data == chptr)
800 break;
801 }
802 if (invite == NULL)
803 moduledata.approved = i;
804 }
805
806 finish_join_check:
807 call_hook(h_can_join, &moduledata);
808
809 return moduledata.approved;
810 }
811
812 /* can_send()
813 *
814 * input - user to check in channel, membership pointer
815 * output - whether can explicitly send or not, else CAN_SEND_NONOP
816 * side effects -
817 */
818 int
819 can_send(struct Channel *chptr, struct Client *source_p, struct membership *msptr)
820 {
821 hook_data_channel_approval moduledata;
822
823 moduledata.approved = CAN_SEND_NONOP;
824 moduledata.dir = MODE_QUERY;
825
826 if(IsServer(source_p) || IsService(source_p))
827 return CAN_SEND_OPV;
828
829 if(MyClient(source_p) && hash_find_resv(chptr->chname) &&
830 !IsOper(source_p) && !IsExemptResv(source_p))
831 moduledata.approved = CAN_SEND_NO;
832
833 if(msptr == NULL)
834 {
835 msptr = find_channel_membership(chptr, source_p);
836
837 if(msptr == NULL)
838 {
839 /* if its +m or +n and theyre not in the channel,
840 * they cant send. we dont check bans here because
841 * theres no possibility of caching them --fl
842 */
843 if(chptr->mode.mode & MODE_NOPRIVMSGS || chptr->mode.mode & MODE_MODERATED)
844 moduledata.approved = CAN_SEND_NO;
845 else
846 moduledata.approved = CAN_SEND_NONOP;
847
848 return moduledata.approved;
849 }
850 }
851
852 if(chptr->mode.mode & MODE_MODERATED)
853 moduledata.approved = CAN_SEND_NO;
854
855 if(MyClient(source_p))
856 {
857 /* cached can_send */
858 if(msptr->bants == chptr->bants)
859 {
860 if(can_send_banned(msptr))
861 moduledata.approved = CAN_SEND_NO;
862 }
863 else if(is_banned(chptr, source_p, msptr, NULL, NULL, NULL) == CHFL_BAN
864 || is_quieted(chptr, source_p, msptr, NULL, NULL) == CHFL_BAN)
865 moduledata.approved = CAN_SEND_NO;
866 }
867
868 if(is_chanop_voiced(msptr))
869 moduledata.approved = CAN_SEND_OPV;
870
871 moduledata.client = source_p;
872 moduledata.chptr = msptr->chptr;
873 moduledata.msptr = msptr;
874 moduledata.target = NULL;
875 moduledata.dir = (moduledata.approved == CAN_SEND_NO) ? MODE_ADD : MODE_QUERY;
876
877 call_hook(h_can_send, &moduledata);
878
879 return moduledata.approved;
880 }
881
882 /*
883 * flood_attack_channel
884 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
885 * says NOTICE must not auto reply
886 * - pointer to source Client
887 * - pointer to target channel
888 * output - 1 if target is under flood attack
889 * side effects - check for flood attack on target chptr
890 */
891 int
892 flood_attack_channel(int p_or_n, struct Client *source_p, struct Channel *chptr, char *chname)
893 {
894 int delta;
895
896 if(GlobalSetOptions.floodcount && MyClient(source_p))
897 {
898 if((chptr->first_received_message_time + 1) < rb_current_time())
899 {
900 delta = rb_current_time() - chptr->first_received_message_time;
901 chptr->received_number_of_privmsgs -= delta;
902 chptr->first_received_message_time = rb_current_time();
903 if(chptr->received_number_of_privmsgs <= 0)
904 {
905 chptr->received_number_of_privmsgs = 0;
906 chptr->flood_noticed = 0;
907 }
908 }
909
910 if((chptr->received_number_of_privmsgs >= GlobalSetOptions.floodcount)
911 || chptr->flood_noticed)
912 {
913 if(chptr->flood_noticed == 0)
914 {
915 sendto_realops_snomask(SNO_BOTS, *chptr->chname == '&' ? L_ALL : L_NETWIDE,
916 "Possible Flooder %s[%s@%s] on %s target: %s",
917 source_p->name, source_p->username,
918 source_p->orighost,
919 source_p->servptr->name, chptr->chname);
920 chptr->flood_noticed = 1;
921
922 /* Add a bit of penalty */
923 chptr->received_number_of_privmsgs += 2;
924 }
925 if(MyClient(source_p) && (p_or_n != 1))
926 sendto_one(source_p,
927 ":%s NOTICE %s :*** Message to %s throttled due to flooding",
928 me.name, source_p->name, chptr->chname);
929 return 1;
930 }
931 else
932 chptr->received_number_of_privmsgs++;
933 }
934
935 return 0;
936 }
937
938 /* find_bannickchange_channel()
939 * Input: client to check
940 * Output: channel preventing nick change
941 */
942 struct Channel *
943 find_bannickchange_channel(struct Client *client_p)
944 {
945 struct Channel *chptr;
946 struct membership *msptr;
947 rb_dlink_node *ptr;
948 char src_host[NICKLEN + USERLEN + HOSTLEN + 6];
949 char src_iphost[NICKLEN + USERLEN + HOSTLEN + 6];
950
951 if (!MyClient(client_p))
952 return NULL;
953
954 rb_sprintf(src_host, "%s!%s@%s", client_p->name, client_p->username, client_p->host);
955 rb_sprintf(src_iphost, "%s!%s@%s", client_p->name, client_p->username, client_p->sockhost);
956
957 RB_DLINK_FOREACH(ptr, client_p->user->channel.head)
958 {
959 msptr = ptr->data;
960 chptr = msptr->chptr;
961 if (is_chanop_voiced(msptr))
962 continue;
963 /* cached can_send */
964 if (msptr->bants == chptr->bants)
965 {
966 if (can_send_banned(msptr))
967 return chptr;
968 }
969 else if (is_banned(chptr, client_p, msptr, src_host, src_iphost, NULL) == CHFL_BAN
970 || is_quieted(chptr, client_p, msptr, src_host, src_iphost) == CHFL_BAN)
971 return chptr;
972 }
973 return NULL;
974 }
975
976 /* void check_spambot_warning(struct Client *source_p)
977 * Input: Client to check, channel name or NULL if this is a part.
978 * Output: none
979 * Side-effects: Updates the client's oper_warn_count_down, warns the
980 * IRC operators if necessary, and updates join_leave_countdown as
981 * needed.
982 */
983 void
984 check_spambot_warning(struct Client *source_p, const char *name)
985 {
986 int t_delta;
987 int decrement_count;
988 if((GlobalSetOptions.spam_num &&
989 (source_p->localClient->join_leave_count >= GlobalSetOptions.spam_num)))
990 {
991 if(source_p->localClient->oper_warn_count_down > 0)
992 source_p->localClient->oper_warn_count_down--;
993 else
994 source_p->localClient->oper_warn_count_down = 0;
995 if(source_p->localClient->oper_warn_count_down == 0 &&
996 name != NULL)
997 {
998 /* Its already known as a possible spambot */
999 sendto_realops_snomask(SNO_BOTS, L_NETWIDE,
1000 "User %s (%s@%s) trying to join %s is a possible spambot",
1001 source_p->name,
1002 source_p->username, source_p->orighost, name);
1003 source_p->localClient->oper_warn_count_down = OPER_SPAM_COUNTDOWN;
1004 }
1005 }
1006 else
1007 {
1008 if((t_delta =
1009 (rb_current_time() - source_p->localClient->last_leave_time)) >
1010 JOIN_LEAVE_COUNT_EXPIRE_TIME)
1011 {
1012 decrement_count = (t_delta / JOIN_LEAVE_COUNT_EXPIRE_TIME);
1013 if(name != NULL)
1014 ;
1015 else if(decrement_count > source_p->localClient->join_leave_count)
1016 source_p->localClient->join_leave_count = 0;
1017 else
1018 source_p->localClient->join_leave_count -= decrement_count;
1019 }
1020 else
1021 {
1022 if((rb_current_time() -
1023 (source_p->localClient->last_join_time)) < GlobalSetOptions.spam_time)
1024 {
1025 /* oh, its a possible spambot */
1026 source_p->localClient->join_leave_count++;
1027 }
1028 }
1029 if(name != NULL)
1030 source_p->localClient->last_join_time = rb_current_time();
1031 else
1032 source_p->localClient->last_leave_time = rb_current_time();
1033 }
1034 }
1035
1036 /* check_splitmode()
1037 *
1038 * input -
1039 * output -
1040 * side effects - compares usercount and servercount against their split
1041 * values and adjusts splitmode accordingly
1042 */
1043 void
1044 check_splitmode(void *unused)
1045 {
1046 if(splitchecking && (ConfigChannel.no_join_on_split || ConfigChannel.no_create_on_split))
1047 {
1048 /* not split, we're being asked to check now because someone
1049 * has left
1050 */
1051 if(!splitmode)
1052 {
1053 if(eob_count < split_servers || Count.total < split_users)
1054 {
1055 splitmode = 1;
1056 sendto_realops_snomask(SNO_GENERAL, L_ALL,
1057 "Network split, activating splitmode");
1058 check_splitmode_ev = rb_event_addish("check_splitmode", check_splitmode, NULL, 2);
1059 }
1060 }
1061 /* in splitmode, check whether its finished */
1062 else if(eob_count >= split_servers && Count.total >= split_users)
1063 {
1064 splitmode = 0;
1065
1066 sendto_realops_snomask(SNO_GENERAL, L_ALL,
1067 "Network rejoined, deactivating splitmode");
1068
1069 rb_event_delete(check_splitmode_ev);
1070 check_splitmode_ev = NULL;
1071 }
1072 }
1073 }
1074
1075
1076 /* allocate_topic()
1077 *
1078 * input - channel to allocate topic for
1079 * output - 1 on success, else 0
1080 * side effects - channel gets a topic allocated
1081 */
1082 static void
1083 allocate_topic(struct Channel *chptr)
1084 {
1085 void *ptr;
1086
1087 if(chptr == NULL)
1088 return;
1089
1090 ptr = rb_bh_alloc(topic_heap);
1091
1092 /* Basically we allocate one large block for the topic and
1093 * the topic info. We then split it up into two and shove it
1094 * in the chptr
1095 */
1096 chptr->topic = ptr;
1097 chptr->topic_info = (char *) ptr + TOPICLEN + 1;
1098 *chptr->topic = '\0';
1099 *chptr->topic_info = '\0';
1100 }
1101
1102 /* free_topic()
1103 *
1104 * input - channel which has topic to free
1105 * output -
1106 * side effects - channels topic is free'd
1107 */
1108 static void
1109 free_topic(struct Channel *chptr)
1110 {
1111 void *ptr;
1112
1113 if(chptr == NULL || chptr->topic == NULL)
1114 return;
1115
1116 /* This is safe for now - If you change allocate_topic you
1117 * MUST change this as well
1118 */
1119 ptr = chptr->topic;
1120 rb_bh_free(topic_heap, ptr);
1121 chptr->topic = NULL;
1122 chptr->topic_info = NULL;
1123 }
1124
1125 /* set_channel_topic()
1126 *
1127 * input - channel, topic to set, topic info and topic ts
1128 * output -
1129 * side effects - channels topic, topic info and TS are set.
1130 */
1131 void
1132 set_channel_topic(struct Channel *chptr, const char *topic, const char *topic_info, time_t topicts)
1133 {
1134 if(strlen(topic) > 0)
1135 {
1136 if(chptr->topic == NULL)
1137 allocate_topic(chptr);
1138 rb_strlcpy(chptr->topic, topic, TOPICLEN + 1);
1139 rb_strlcpy(chptr->topic_info, topic_info, USERHOST_REPLYLEN);
1140 chptr->topic_time = topicts;
1141 }
1142 else
1143 {
1144 if(chptr->topic != NULL)
1145 free_topic(chptr);
1146 chptr->topic_time = 0;
1147 }
1148 }
1149
1150 /* channel_modes()
1151 *
1152 * inputs - pointer to channel
1153 * - pointer to client
1154 * output - string with simple modes
1155 * side effects - result from previous calls overwritten
1156 *
1157 * Stolen from ShadowIRCd 4 --nenolod
1158 */
1159 const char *
1160 channel_modes(struct Channel *chptr, struct Client *client_p)
1161 {
1162 int i;
1163 char buf1[BUFSIZE];
1164 char buf2[BUFSIZE];
1165 static char final[BUFSIZE];
1166 char *mbuf = buf1;
1167 char *pbuf = buf2;
1168
1169 *mbuf++ = '+';
1170 *pbuf = '\0';
1171
1172 for (i = 0; i < 256; i++)
1173 if(chptr->mode.mode & chmode_flags[i])
1174 *mbuf++ = i;
1175
1176 if(chptr->mode.limit)
1177 {
1178 *mbuf++ = 'l';
1179
1180 if(!IsClient(client_p) || IsMember(client_p, chptr))
1181 pbuf += rb_sprintf(pbuf, " %d", chptr->mode.limit);
1182 }
1183
1184 if(*chptr->mode.key)
1185 {
1186 *mbuf++ = 'k';
1187
1188 if(pbuf > buf2 || !IsClient(client_p) || IsMember(client_p, chptr))
1189 pbuf += rb_sprintf(pbuf, " %s", chptr->mode.key);
1190 }
1191
1192 if(chptr->mode.join_num)
1193 {
1194 *mbuf++ = 'j';
1195
1196 if(pbuf > buf2 || !IsClient(client_p) || IsMember(client_p, chptr))
1197 pbuf += rb_sprintf(pbuf, " %d:%d", chptr->mode.join_num,
1198 chptr->mode.join_time);
1199 }
1200
1201 if(*chptr->mode.forward &&
1202 (ConfigChannel.use_forward || !IsClient(client_p)))
1203 {
1204 *mbuf++ = 'f';
1205
1206 if(pbuf > buf2 || !IsClient(client_p) || IsMember(client_p, chptr))
1207 pbuf += rb_sprintf(pbuf, " %s", chptr->mode.forward);
1208 }
1209
1210 *mbuf = '\0';
1211
1212 rb_strlcpy(final, buf1, sizeof final);
1213 rb_strlcat(final, buf2, sizeof final);
1214 return final;
1215 }
1216
1217 /* void send_cap_mode_changes(struct Client *client_p,
1218 * struct Client *source_p,
1219 * struct Channel *chptr, int cap, int nocap)
1220 * Input: The client sending(client_p), the source client(source_p),
1221 * the channel to send mode changes for(chptr)
1222 * Output: None.
1223 * Side-effects: Sends the appropriate mode changes to capable servers.
1224 *
1225 * Reverted back to my original design, except that we now keep a count
1226 * of the number of servers which each combination as an optimisation, so
1227 * the capabs combinations which are not needed are not worked out. -A1kmm
1228 *
1229 * Removed most code here because we don't need to be compatible with ircd
1230 * 2.8.21+CSr and stuff. --nenolod
1231 */
1232 void
1233 send_cap_mode_changes(struct Client *client_p, struct Client *source_p,
1234 struct Channel *chptr, struct ChModeChange mode_changes[], int mode_count)
1235 {
1236 static char modebuf[BUFSIZE];
1237 static char parabuf[BUFSIZE];
1238 int i, mbl, pbl, nc, mc, preflen, len;
1239 char *pbuf;
1240 const char *arg;
1241 int dir;
1242 int arglen;
1243
1244 /* Now send to servers... */
1245 mc = 0;
1246 nc = 0;
1247 pbl = 0;
1248 parabuf[0] = 0;
1249 pbuf = parabuf;
1250 dir = MODE_QUERY;
1251
1252 mbl = preflen = rb_sprintf(modebuf, ":%s TMODE %ld %s ",
1253 use_id(source_p), (long) chptr->channelts,
1254 chptr->chname);
1255
1256 /* loop the list of - modes we have */
1257 for (i = 0; i < mode_count; i++)
1258 {
1259 /* if they dont support the cap we need, or they do support a cap they
1260 * cant have, then dont add it to the modebuf.. that way they wont see
1261 * the mode
1262 */
1263 if (mode_changes[i].letter == 0)
1264 continue;
1265
1266 if (!EmptyString(mode_changes[i].id))
1267 arg = mode_changes[i].id;
1268 else
1269 arg = mode_changes[i].arg;
1270
1271 if(arg)
1272 {
1273 arglen = strlen(arg);
1274
1275 /* dont even think about it! --fl */
1276 if(arglen > MODEBUFLEN - 5)
1277 continue;
1278 }
1279
1280 /* if we're creeping past the buf size, we need to send it and make
1281 * another line for the other modes
1282 * XXX - this could give away server topology with uids being
1283 * different lengths, but not much we can do, except possibly break
1284 * them as if they were the longest of the nick or uid at all times,
1285 * which even then won't work as we don't always know the uid -A1kmm.
1286 */
1287 if(arg && ((mc == MAXMODEPARAMSSERV) ||
1288 ((mbl + pbl + arglen + 4) > (BUFSIZE - 3))))
1289 {
1290 if(nc != 0)
1291 sendto_server(client_p, chptr, NOCAPS, NOCAPS,
1292 "%s %s", modebuf, parabuf);
1293 nc = 0;
1294 mc = 0;
1295
1296 mbl = preflen;
1297 pbl = 0;
1298 pbuf = parabuf;
1299 parabuf[0] = 0;
1300 dir = MODE_QUERY;
1301 }
1302
1303 if(dir != mode_changes[i].dir)
1304 {
1305 modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
1306 dir = mode_changes[i].dir;
1307 }
1308
1309 modebuf[mbl++] = mode_changes[i].letter;
1310 modebuf[mbl] = 0;
1311 nc++;
1312
1313 if(arg != NULL)
1314 {
1315 len = rb_sprintf(pbuf, "%s ", arg);
1316 pbuf += len;
1317 pbl += len;
1318 mc++;
1319 }
1320 }
1321
1322 if(pbl && parabuf[pbl - 1] == ' ')
1323 parabuf[pbl - 1] = 0;
1324
1325 if(nc != 0)
1326 sendto_server(client_p, chptr, NOCAPS, NOCAPS, "%s %s", modebuf, parabuf);
1327 }
1328
1329 void
1330 resv_chan_forcepart(const char *name, const char *reason, int temp_time)
1331 {
1332 rb_dlink_node *ptr;
1333 rb_dlink_node *next_ptr;
1334 struct Channel *chptr;
1335 struct membership *msptr;
1336 struct Client *target_p;
1337
1338 if(!ConfigChannel.resv_forcepart)
1339 return;
1340
1341 /* for each user on our server in the channel list
1342 * send them a PART, and notify opers.
1343 */
1344 chptr = find_channel(name);
1345 if(chptr != NULL)
1346 {
1347 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, chptr->locmembers.head)
1348 {
1349 msptr = ptr->data;
1350 target_p = msptr->client_p;
1351
1352 if(IsExemptResv(target_p))
1353 continue;
1354
1355 sendto_server(target_p, chptr, CAP_TS6, NOCAPS,
1356 ":%s PART %s", target_p->id, chptr->chname);
1357
1358 sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s PART %s :%s",
1359 target_p->name, target_p->username,
1360 target_p->host, chptr->chname, target_p->name);
1361
1362 remove_user_from_channel(msptr);
1363
1364 /* notify opers & user they were removed from the channel */
1365 sendto_realops_snomask(SNO_GENERAL, L_ALL,
1366 "Forced PART for %s!%s@%s from %s (%s)",
1367 target_p->name, target_p->username,
1368 target_p->host, name, reason);
1369
1370 if(temp_time > 0)
1371 sendto_one_notice(target_p, ":*** Channel %s is temporarily unavailable on this server.",
1372 name);
1373 else
1374 sendto_one_notice(target_p, ":*** Channel %s is no longer available on this server.",
1375 name);
1376 }
1377 }
1378 }