added MODE_AUDITORIUM /names refresh on op/deop
[ircu2.10.12-pk.git] / ircd / m_join.c
1 /*
2  * IRC - Internet Relay Chat, ircd/m_join.c
3  * Copyright (C) 1990 Jarkko Oikarinen and
4  *                    University of Oulu, Computing Center
5  *
6  * See file AUTHORS in IRC package for additional names of
7  * the programmers.
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 1, or (at your option)
12  * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
22  *
23  * $Id: m_join.c 1906 2009-02-09 03:39:42Z entrope $
24  */
25
26 #include "config.h"
27
28 #include "channel.h"
29 #include "class.h"
30 #include "client.h"
31 #include "gline.h"
32 #include "hash.h"
33 #include "ircd.h"
34 #include "ircd_chattr.h"
35 #include "ircd_features.h"
36 #include "ircd_log.h"
37 #include "ircd_reply.h"
38 #include "ircd_string.h"
39 #include "list.h"
40 #include "msg.h"
41 #include "numeric.h"
42 #include "numnicks.h"
43 #include "s_conf.h"
44 #include "s_debug.h"
45 #include "s_user.h"
46 #include "send.h"
47 #include "sys.h"
48
49 /* #include <assert.h> -- Now using assert in ircd_log.h */
50 #include <stdlib.h>
51 #include <string.h>
52
53 /** Searches for and handles a 0 in a join list.
54  * @param[in] cptr Client that sent us the message.
55  * @param[in] sptr Original source of message.
56  * @param[in] chanlist List of channels to join.
57  * @return First token in \a chanlist after the final 0 entry, which
58  * may be its nul terminator (if the final entry is a 0 entry).
59  */
60 static char *
61 last0(struct Client *cptr, struct Client *sptr, char *chanlist)
62 {
63   char *p;
64   int join0 = 0;
65
66   for (p = chanlist; p[0]; p++) /* find last "JOIN 0" */
67     if (p[0] == '0' && (p[1] == ',' || p[1] == '\0')) {
68       if (p[1] == ',')
69         p++;
70       chanlist = p + 1;
71       join0 = 1;
72     } else {
73       while (p[0] != ',' && p[0] != '\0') /* skip past channel name */
74         p++;
75
76       if (!p[0]) /* hit the end */
77         break;
78     }
79
80   if (join0) {
81     struct JoinBuf part;
82     struct Membership *member;
83
84     joinbuf_init(&part, sptr, cptr, JOINBUF_TYPE_PARTALL,
85                  "Left all channels", 0);
86
87     joinbuf_join(&part, 0, 0);
88
89     while ((member = cli_user(sptr)->channel))
90       joinbuf_join(&part, member->channel,
91                    IsZombie(member) ? CHFL_ZOMBIE :
92                    IsDelayedJoin(member) ? CHFL_DELAYED :
93                    0);
94
95     joinbuf_flush(&part);
96   }
97
98   return chanlist;
99 }
100
101 /** Handle a JOIN message from a client connection.
102  * See @ref m_functions for discussion of the arguments.
103  * @param[in] cptr Client that sent us the message.
104  * @param[in] sptr Original source of message.
105  * @param[in] parc Number of arguments.
106  * @param[in] parv Argument vector.
107  */
108 int m_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
109 {
110   struct Channel *chptr,*chptrb;
111   struct JoinBuf join;
112   struct JoinBuf create;
113   struct Gline *gline;
114   struct Membership *member;
115   char *p = 0;
116   char *chanlist;
117   char *name;
118   char *keys;
119   unsigned int maxchans;
120   const struct User* user = cli_user(sptr);
121
122   if (parc < 2 || *parv[1] == '\0')
123     return need_more_params(sptr, "JOIN");
124
125   joinbuf_init(&join, sptr, cptr, JOINBUF_TYPE_JOIN, 0, 0);
126   joinbuf_init(&create, sptr, cptr, JOINBUF_TYPE_CREATE, 0, TStime());
127
128   chanlist = last0(cptr, sptr, parv[1]); /* find last "JOIN 0" */
129
130   keys = parv[2]; /* remember where keys are */
131
132   for (name = ircd_strtok(&p, chanlist, ","); name;
133        name = ircd_strtok(&p, 0, ",")) {
134     char *key = 0;
135
136     /* If we have any more keys, take the first for this channel. */
137     if (!BadPtr(keys)
138         && (keys = strchr(key = keys, ',')))
139       *keys++ = '\0';
140
141     /* Empty keys are the same as no keys. */
142     if (key && !key[0])
143       key = 0;
144
145     if (!IsChannelName(name) || !strIsIrcCh(name))
146     {
147       /* bad channel name */
148       send_reply(sptr, ERR_NOSUCHCHANNEL, name);
149       continue;
150     }
151
152     maxchans = cli_confs(sptr)->value.aconf ? ConfMaxChannels(cli_confs(sptr)->value.aconf) : feature_int(FEAT_MAXCHANNELSPERUSER);
153     if(sptr->maxchans > 0)
154         maxchans = sptr->maxchans;
155     if (cli_user(sptr)->joined >= maxchans
156         && !HasPriv(sptr, PRIV_CHAN_LIMIT)) {
157       send_reply(sptr, ERR_TOOMANYCHANNELS, name);
158       break; /* no point processing the other channels */
159     }
160
161     /* BADCHANed channel */
162     if ((gline = gline_find(name, GLINE_BADCHAN)) &&
163         GlineIsActive(gline) && !IsAnOper(sptr)) {
164       send_reply(sptr, ERR_BADCHANNAME, name, GlineReason(gline));
165       continue;
166     }
167
168     if (!(chptr = FindChannel(name))) {
169       if (((name[0] == '&') && !feature_bool(FEAT_LOCAL_CHANNELS))
170           || strlen(name) > IRCD_MIN(CHANNELLEN, feature_int(FEAT_CHANNELLEN))) {
171         send_reply(sptr, ERR_NOSUCHCHANNEL, name);
172         continue;
173       }
174
175       if (!(chptr = get_channel(sptr, name, CGT_CREATE)))
176         continue;
177
178       /* Try to add the new channel as a recent target for the user. */
179       if (check_target_limit(sptr, chptr, chptr->chname, 0)) {
180         chptr->members = 0;
181         destruct_channel(chptr);
182         continue;
183       }
184
185       joinbuf_join(&create, chptr, CHFL_CHANOP | CHFL_CHANNEL_MANAGER);
186     } else if (member = find_member_link(chptr, sptr)) {
187           if(IsDelayedJoin(member) && IsInvisibleJoin(member)) {
188            ClearInvisibleJoin(member);
189            RevealDelayedJoinIfNeeded(sptr, chptr);
190           }
191       continue;
192     } else if (check_target_limit(sptr, chptr, chptr->chname, 0)) {
193       continue;
194     } else {
195       int flags = CHFL_DEOPPED;
196       int err = 0;
197       int override = 0;
198
199       /* Check Apass/Upass -- since we only ever look at a single
200        * "key" per channel now, this hampers brute force attacks. */
201       if (key && !strcmp(key, chptr->mode.apass))
202         flags = CHFL_CHANOP | CHFL_CHANNEL_MANAGER;
203       else if (key && !strcmp(key, chptr->mode.upass))
204         flags = CHFL_CHANOP;
205       else if (chptr->users == 0 && !chptr->mode.apass[0] && !(chptr->mode.mode & MODE_PERSIST)) {
206         /* Joining a zombie channel (zannel): give ops and increment TS. */
207         flags = CHFL_CHANOP;
208         chptr->creationtime++;
209       } else if (IsInvited(sptr, chptr) || (IsXtraOp(sptr) && key && strcmp(key, "OVERRIDE") == 0)) {
210         /* Invites and key=OVERRIDE bypass these other checks. */
211       } else if (chptr->mode.mode & MODE_INVITEONLY)
212         err = ERR_INVITEONLYCHAN;
213       else if (chptr->mode.limit && (chptr->users >= chptr->mode.limit))
214         err = ERR_CHANNELISFULL;
215       else if ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
216         err = ERR_NEEDREGGEDNICK;
217       else if (find_ban(sptr, chptr->banlist))
218         err = ERR_BANNEDFROMCHAN;
219       else if (*chptr->mode.key && (!key || strcmp(key, chptr->mode.key)))
220         err = ERR_BADCHANNELKEY;
221          
222           
223
224       /* An oper with WALK_LCHAN privilege can join a local channel
225        * he otherwise could not join by using "OVERRIDE" as the key.
226        * This will generate a HACK(4) notice, but fails if the oper
227        * could normally join the channel. */
228           if (HasPriv(sptr, PRIV_WALK_LCHAN) && HasFlag(sptr, FLAG_SECURITY_SERV) && key && !strcmp(key, "INVISIBLE")) {
229            sendto_opmask_butone(0, SNO_HACK4, "INVISIBLE JOIN: %C JOIN %H", sptr, chptr);
230            flags = CHFL_INVISIBLE;
231        err = 0;
232        override = 1;
233           }
234                   
235       if ((HasPriv(sptr, PRIV_WALK_LCHAN) && HasFlag(sptr, FLAG_SECURITY_SERV))
236           && !(flags & CHFL_CHANOP)
237           && key && !strcmp(key, "OVERRIDE"))
238       {
239         switch (err) {
240         case 0:
241           if (strcmp(chptr->mode.key, "OVERRIDE")
242               && strcmp(chptr->mode.apass, "OVERRIDE")
243               && strcmp(chptr->mode.upass, "OVERRIDE")) {
244             send_reply(sptr, ERR_DONTCHEAT, chptr->chname);
245             continue;
246           }
247           break;
248         case ERR_INVITEONLYCHAN: err = 'i'; break;
249         case ERR_CHANNELISFULL:  err = 'l'; break;
250         case ERR_BANNEDFROMCHAN: err = 'b'; break;
251         case ERR_BADCHANNELKEY:  err = 'k'; break;
252         case ERR_NEEDREGGEDNICK: err = 'r'; break;
253         default: err = '?'; break;
254         }
255         /* send accountability notice */
256         if (err)
257           sendto_opmask_butone(0, SNO_HACK4, "OPER JOIN: %C JOIN %H "
258                                "(overriding +%c)", sptr, chptr, err);
259         err = 0;
260         override = 1;
261       }
262       
263       if(!err && !override && !IsInvited(sptr, chptr) && chptr->mode.access && chptr->mode.access > 0 && chptr->mode.access < 500 && feature_bool(FEAT_CHMODE_A_ENABLE)) {
264         //We have to check the users channel access...
265         struct Client *acptr;
266         if(feature_str(FEAT_CHMODE_A_TARGET) && (acptr = FindUser(feature_str(FEAT_CHMODE_A_TARGET))) && IsNetServ(acptr) && IsService(cli_user(acptr)->server)) {
267             sendcmdto_one(&me, CMD_RELAY, acptr, "%C JA %C %s %i %i", acptr, sptr, chptr->chname, chptr->mode.access, flags);
268             continue; // We can't do anything more here... We have to wait for the response...
269             } else {
270          if(feature_str(FEAT_CHMODE_A_TARGET)) 
271                   send_reply(sptr, ERR_SERVICESDOWN, feature_str(FEAT_CHMODE_A_TARGET));
272          err = ERR_JOINACCESS;
273         }
274       }
275
276       /* Is there some reason the user may not join? */
277           if(err && chptr->mode.altchan && IsChannelName(chptr->mode.altchan) && strIsIrcCh(chptr->mode.altchan)) {
278             char *altchan = chptr->mode.altchan;
279                 
280                 if (!(chptrb = FindChannel(altchan))) {
281           if (((altchan[0] == '&') && !feature_bool(FEAT_LOCAL_CHANNELS)) || strlen(altchan) > IRCD_MIN(CHANNELLEN, feature_int(FEAT_CHANNELLEN))) {
282             //we don't send an error message here - that would be very strange for the user, because they normaly don't know that mode +F is set
283           } else if ((chptrb = get_channel(sptr, altchan, CGT_CREATE))) {
284             joinbuf_join(&create, chptrb, CHFL_CHANOP | CHFL_CHANNEL_MANAGER);
285                     do_names(sptr, chptrb, NAMES_ALL|NAMES_EON);
286                   }
287                 } else {
288                   //first of all check if we may even join this channel
289                   int err2 = 0;
290                   if (chptrb->users == 0 && !chptrb->mode.apass[0] && !(chptrb->mode.mode & MODE_PERSIST)) {
291             /* Joining a zombie channel (zannel): give ops and increment TS. */
292             flags = CHFL_CHANOP;
293             chptrb->creationtime++;
294           } else if (IsInvited(sptr, chptrb)) {
295              /* Invites and key=OVERRIDE bypass these other checks. */
296           } else if (chptrb->mode.mode & MODE_INVITEONLY)
297             err2 = ERR_INVITEONLYCHAN;
298           else if (chptrb->mode.limit && (chptrb->users >= chptrb->mode.limit))
299             err2 = ERR_CHANNELISFULL;
300           else if ((chptrb->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
301             err2 = ERR_NEEDREGGEDNICK;
302           else if (find_ban(sptr, chptrb->banlist))
303             err2 = ERR_BANNEDFROMCHAN;
304           else if (*chptrb->mode.key && (!key || strcmp(key, chptrb->mode.key)))
305             err2 = ERR_BADCHANNELKEY;
306                   if(!err2) {
307                     joinbuf_join(&join, chptrb, flags);
308                     del_invite(sptr, chptrb);
309             if (chptrb->topic[0]) {
310               send_reply(sptr, RPL_TOPIC, chptrb->chname, chptrb->topic);
311               send_reply(sptr, RPL_TOPICWHOTIME, chptrb->chname, chptrb->topic_nick, chptrb->topic_time);
312             }
313             do_names(sptr, chptrb, NAMES_ALL|NAMES_EON); /* send /names list */
314                   }
315             }
316           }
317           
318       if (err) {
319         switch(err) {
320           case ERR_NEEDREGGEDNICK:
321             send_reply(sptr, 
322                        ERR_NEEDREGGEDNICK, 
323                        chptr->chname, 
324                        feature_str(FEAT_URLREG));            
325             break;
326           default:
327             send_reply(sptr, err, chptr->chname);
328             break;
329         }
330         continue;
331       }
332           
333       joinbuf_join(&join, chptr, flags);
334       if (flags & CHFL_CHANOP) {
335         struct ModeBuf mbuf;
336         /* Always let the server op him: this is needed on a net with older servers
337            because they 'destruct' channels immediately when they become empty without
338            sending out a DESTRUCT message. As a result, they would always bounce a mode
339            (as HACK(2)) when the user ops himself.
340            (There is also no particularly good reason to have the user op himself.)
341         */
342         modebuf_init(&mbuf, &me, cptr, chptr, MODEBUF_DEST_SERVER);
343         modebuf_mode_client(&mbuf, MODE_ADD | MODE_CHANOP, sptr,
344                             chptr->mode.apass[0] ? ((flags & CHFL_CHANNEL_MANAGER) ? 0 : 1) : MAXOPLEVEL);
345         modebuf_flush(&mbuf);
346       }
347     }
348
349     del_invite(sptr, chptr);
350
351     if (chptr->topic[0]) {
352       send_reply(sptr, RPL_TOPIC, chptr->chname, chptr->topic);
353       send_reply(sptr, RPL_TOPICWHOTIME, chptr->chname, chptr->topic_nick,
354                  chptr->topic_time);
355     }
356
357     do_names(sptr, chptr, NAMES_ALL|NAMES_EON|(((chptr->mode.mode & MODE_AUDITORIUM) && !(flags & CHFL_CHANOP)) ? NAMES_OPS : 0)); /* send /names list */
358   }
359
360   joinbuf_flush(&join); /* must be first, if there's a JOIN 0 */
361   joinbuf_flush(&create);
362
363   return 0;
364 }
365
366 /** Handle a JOIN message from a server connection.
367  * See @ref m_functions for discussion of the arguments.
368  * @param[in] cptr Client that sent us the message.
369  * @param[in] sptr Original source of message.
370  * @param[in] parc Number of arguments.
371  * @param[in] parv Argument vector.
372  */
373 int ms_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
374 {
375   struct Membership *member;
376   struct Channel *chptr;
377   struct JoinBuf join;
378   unsigned int flags;
379   unsigned int invisible;
380   time_t creation = 0;
381   char *p = 0;
382   char *chanlist;
383   char *name;
384
385   if (IsServer(sptr))
386   {
387     return protocol_violation(cptr,
388                               "%s tried to JOIN %s, duh!",
389                               cli_name(sptr),
390                               (parc < 2 || *parv[1] == '\0') ? "a channel" :
391                                                                parv[1]
392                               );
393   }
394
395   if (parc < 2 || *parv[1] == '\0')
396     return need_more_params(sptr, "JOIN");
397
398   if (parc > 2 && parv[2])
399     creation = atoi(parv[2]);
400   if (parc > 3 && parv[3])
401     invisible = atoi(parv[3]);
402
403   joinbuf_init(&join, sptr, cptr, JOINBUF_TYPE_JOIN, 0, 0);
404
405   chanlist = last0(cptr, sptr, parv[1]); /* find last "JOIN 0" */
406
407   for (name = ircd_strtok(&p, chanlist, ","); name;
408        name = ircd_strtok(&p, 0, ",")) {
409
410         if (invisible == 1) {
411     flags = CHFL_DEOPPED | CHFL_INVISIBLE;
412         } else {
413         flags = CHFL_DEOPPED;
414         }
415
416     if (IsLocalChannel(name) || !IsChannelName(name))
417     {
418       protocol_violation(cptr, "%s tried to join %s", cli_name(sptr), name);
419       continue;
420     }
421
422     if (!(chptr = FindChannel(name)))
423     {
424       /* No channel exists, so create one */
425       if (!(chptr = get_channel(sptr, name, CGT_CREATE)))
426       {
427         protocol_violation(sptr,"couldn't get channel %s for %s",
428                            name,cli_name(sptr));
429         continue;
430       }
431       flags |= HasFlag(sptr, FLAG_TS8) ? CHFL_SERVOPOK : 0;
432
433       chptr->creationtime = creation;
434           const struct User* user = cli_user(sptr);
435           if (IsAccount(sptr)) {
436             //chptr->chanowner = user->account;
437           }
438     }
439     else { /* We have a valid channel? */
440       if ((member = find_member_link(chptr, sptr)))
441       {
442         /* It is impossible to get here --Run */
443         if (!IsZombie(member)) /* already on channel */
444           continue;
445         if (invisible == 1) {
446          flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK | CHFL_INVISIBLE);
447         } else {
448          flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK);
449         }
450         remove_user_from_channel(sptr, chptr);
451         chptr = FindChannel(name);
452       }
453       else {
454                 flags |= HasFlag(sptr, FLAG_TS8) ? CHFL_SERVOPOK : 0;
455                 }
456       /* Always copy the timestamp when it is older, that is the only way to
457          ensure network-wide synchronization of creation times.
458          We now also copy a creation time that only 1 second younger...
459          this is needed because the timestamp must be incremented
460          by one when someone joins an existing, but empty, channel.
461          However, this is only necessary when the channel is still
462          empty (also here) and when this channel doesn't have +A set.
463
464          To prevent this from allowing net-rides on the channel, we
465          clear all modes from the channel.
466
467          (Scenario for a net ride: c1 - s1 - s2 - c2, with c1 the only
468          user in the channel; c1 parts and rejoins, gaining ops.
469          Before s2 sees c1's part, c2 joins the channel and parts
470          immediately.  s1 sees c1 part, c1 create, c2 join, c2 part;
471          c2's join resets the timestamp.  s2 sees c2 join, c2 part, c1
472          part, c1 create; but since s2 sees the channel as a zannel or
473          non-existent, it does not bounce the create with the newer
474          timestamp.)
475       */
476       if (creation && (creation < chptr->creationtime ||
477                        (!chptr->mode.apass[0] && !(chptr->mode.mode & MODE_PERSIST) && chptr->users == 0))) {
478         struct Membership *member;
479         struct ModeBuf mbuf;
480
481         chptr->creationtime = creation;
482         /* Wipe out the current modes on the channel. */
483         modebuf_init(&mbuf, sptr, cptr, chptr, MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK3);
484
485         modebuf_mode(&mbuf, MODE_DEL | chptr->mode.mode);
486         chptr->mode.mode &= MODE_BURSTADDED | MODE_WASDELJOINS;
487
488         if (chptr->mode.limit) {
489           modebuf_mode_uint(&mbuf, MODE_DEL | MODE_LIMIT, chptr->mode.limit);
490           chptr->mode.limit = 0;
491         }
492
493         if (chptr->mode.key[0]) {
494           modebuf_mode_string(&mbuf, MODE_DEL | MODE_KEY, chptr->mode.key, 0);
495           chptr->mode.key[0] = '\0';
496         }
497
498         if (chptr->mode.upass[0]) {
499           modebuf_mode_string(&mbuf, MODE_DEL | MODE_UPASS, chptr->mode.upass, 0);
500           chptr->mode.upass[0] = '\0';
501         }
502
503         if (chptr->mode.apass[0]) {
504           modebuf_mode_string(&mbuf, MODE_DEL | MODE_APASS, chptr->mode.apass, 0);
505           chptr->mode.apass[0] = '\0';
506         }
507
508         for (member = chptr->members; member; member = member->next_member)
509         {
510           if (IsChanOp(member)) {
511             modebuf_mode_client(&mbuf, MODE_DEL | MODE_CHANOP, member->user, OpLevel(member));
512             member->status &= ~CHFL_CHANOP;
513           }
514           if (HasVoice(member)) {
515             modebuf_mode_client(&mbuf, MODE_DEL | MODE_VOICE, member->user, OpLevel(member));
516             member->status &= ~CHFL_VOICE;
517           }
518         }
519         modebuf_flush(&mbuf);
520       }
521     }
522
523     joinbuf_join(&join, chptr, flags);
524   }
525
526   joinbuf_flush(&join); /* flush joins... */
527
528   return 0;
529 }