m_join.c flag variable fix
[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         int flags = 0;
162         
163     /* BADCHANed channel */
164     if ((gline = gline_find(name, GLINE_BADCHAN)) &&
165         GlineIsActive(gline) && !IsAnOper(sptr)) {
166       send_reply(sptr, ERR_BADCHANNAME, name, GlineReason(gline));
167       continue;
168     }
169
170     if (!(chptr = FindChannel(name))) {
171       if (((name[0] == '&') && !feature_bool(FEAT_LOCAL_CHANNELS))
172           || strlen(name) > IRCD_MIN(CHANNELLEN, feature_int(FEAT_CHANNELLEN))) {
173         send_reply(sptr, ERR_NOSUCHCHANNEL, name);
174         continue;
175       }
176
177       if (!(chptr = get_channel(sptr, name, CGT_CREATE)))
178         continue;
179
180       /* Try to add the new channel as a recent target for the user. */
181       if (check_target_limit(sptr, chptr, chptr->chname, 0)) {
182         chptr->members = 0;
183         destruct_channel(chptr);
184         continue;
185       }
186
187       joinbuf_join(&create, chptr, CHFL_CHANOP | CHFL_CHANNEL_MANAGER);
188     } else if (member = find_member_link(chptr, sptr)) {
189           if(IsDelayedJoin(member) && IsInvisibleJoin(member)) {
190            ClearInvisibleJoin(member);
191            RevealDelayedJoinIfNeeded(sptr, chptr);
192           }
193       continue;
194     } else if (check_target_limit(sptr, chptr, chptr->chname, 0)) {
195       continue;
196     } else {
197       flags = CHFL_DEOPPED;
198       int err = 0;
199       int override = 0;
200
201       /* Check Apass/Upass -- since we only ever look at a single
202        * "key" per channel now, this hampers brute force attacks. */
203       if (key && !strcmp(key, chptr->mode.apass))
204         flags = CHFL_CHANOP | CHFL_CHANNEL_MANAGER;
205       else if (key && !strcmp(key, chptr->mode.upass))
206         flags = CHFL_CHANOP;
207       else if (chptr->users == 0 && !chptr->mode.apass[0] && !(chptr->mode.mode & MODE_PERSIST)) {
208         /* Joining a zombie channel (zannel): give ops and increment TS. */
209         flags = CHFL_CHANOP;
210         chptr->creationtime++;
211       } else if (IsInvited(sptr, chptr) || (IsXtraOp(sptr) && key && strcmp(key, "OVERRIDE") == 0)) {
212         /* Invites and key=OVERRIDE bypass these other checks. */
213       } else if (chptr->mode.mode & MODE_INVITEONLY)
214         err = ERR_INVITEONLYCHAN;
215       else if (chptr->mode.limit && (chptr->users >= chptr->mode.limit))
216         err = ERR_CHANNELISFULL;
217       else if ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
218         err = ERR_NEEDREGGEDNICK;
219       else if (find_ban(sptr, chptr->banlist))
220         err = ERR_BANNEDFROMCHAN;
221       else if (*chptr->mode.key && (!key || strcmp(key, chptr->mode.key)))
222         err = ERR_BADCHANNELKEY;
223          
224           
225
226       /* An oper with WALK_LCHAN privilege can join a local channel
227        * he otherwise could not join by using "OVERRIDE" as the key.
228        * This will generate a HACK(4) notice, but fails if the oper
229        * could normally join the channel. */
230           if (HasPriv(sptr, PRIV_WALK_LCHAN) && HasFlag(sptr, FLAG_SECURITY_SERV) && key && !strcmp(key, "INVISIBLE")) {
231            sendto_opmask_butone(0, SNO_HACK4, "INVISIBLE JOIN: %C JOIN %H", sptr, chptr);
232            flags = CHFL_INVISIBLE;
233        err = 0;
234        override = 1;
235           }
236                   
237       if ((HasPriv(sptr, PRIV_WALK_LCHAN) && HasFlag(sptr, FLAG_SECURITY_SERV))
238           && !(flags & CHFL_CHANOP)
239           && key && !strcmp(key, "OVERRIDE"))
240       {
241         switch (err) {
242         case 0:
243           if (strcmp(chptr->mode.key, "OVERRIDE")
244               && strcmp(chptr->mode.apass, "OVERRIDE")
245               && strcmp(chptr->mode.upass, "OVERRIDE")) {
246             send_reply(sptr, ERR_DONTCHEAT, chptr->chname);
247             continue;
248           }
249           break;
250         case ERR_INVITEONLYCHAN: err = 'i'; break;
251         case ERR_CHANNELISFULL:  err = 'l'; break;
252         case ERR_BANNEDFROMCHAN: err = 'b'; break;
253         case ERR_BADCHANNELKEY:  err = 'k'; break;
254         case ERR_NEEDREGGEDNICK: err = 'r'; break;
255         default: err = '?'; break;
256         }
257         /* send accountability notice */
258         if (err)
259           sendto_opmask_butone(0, SNO_HACK4, "OPER JOIN: %C JOIN %H "
260                                "(overriding +%c)", sptr, chptr, err);
261         err = 0;
262         override = 1;
263       }
264       
265       if(!err && !override && !IsInvited(sptr, chptr) && chptr->mode.access && chptr->mode.access > 0 && chptr->mode.access < 500 && feature_bool(FEAT_CHMODE_A_ENABLE)) {
266         //We have to check the users channel access...
267         struct Client *acptr;
268         if(feature_str(FEAT_CHMODE_A_TARGET) && (acptr = FindUser(feature_str(FEAT_CHMODE_A_TARGET))) && IsNetServ(acptr) && IsService(cli_user(acptr)->server)) {
269             sendcmdto_one(&me, CMD_RELAY, acptr, "%C JA %C %s %i %i", acptr, sptr, chptr->chname, chptr->mode.access, flags);
270             continue; // We can't do anything more here... We have to wait for the response...
271             } else {
272          if(feature_str(FEAT_CHMODE_A_TARGET)) 
273                   send_reply(sptr, ERR_SERVICESDOWN, feature_str(FEAT_CHMODE_A_TARGET));
274          err = ERR_JOINACCESS;
275         }
276       }
277
278       /* Is there some reason the user may not join? */
279           if(err && chptr->mode.altchan && IsChannelName(chptr->mode.altchan) && strIsIrcCh(chptr->mode.altchan)) {
280             char *altchan = chptr->mode.altchan;
281                 
282                 if (!(chptrb = FindChannel(altchan))) {
283           if (((altchan[0] == '&') && !feature_bool(FEAT_LOCAL_CHANNELS)) || strlen(altchan) > IRCD_MIN(CHANNELLEN, feature_int(FEAT_CHANNELLEN))) {
284             //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
285           } else if ((chptrb = get_channel(sptr, altchan, CGT_CREATE))) {
286             joinbuf_join(&create, chptrb, CHFL_CHANOP | CHFL_CHANNEL_MANAGER);
287                     do_names(sptr, chptrb, NAMES_ALL|NAMES_EON);
288                   }
289                 } else {
290                   //first of all check if we may even join this channel
291                   int err2 = 0;
292                   if (chptrb->users == 0 && !chptrb->mode.apass[0] && !(chptrb->mode.mode & MODE_PERSIST)) {
293             /* Joining a zombie channel (zannel): give ops and increment TS. */
294             flags = CHFL_CHANOP;
295             chptrb->creationtime++;
296           } else if (IsInvited(sptr, chptrb)) {
297              /* Invites and key=OVERRIDE bypass these other checks. */
298           } else if (chptrb->mode.mode & MODE_INVITEONLY)
299             err2 = ERR_INVITEONLYCHAN;
300           else if (chptrb->mode.limit && (chptrb->users >= chptrb->mode.limit))
301             err2 = ERR_CHANNELISFULL;
302           else if ((chptrb->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
303             err2 = ERR_NEEDREGGEDNICK;
304           else if (find_ban(sptr, chptrb->banlist))
305             err2 = ERR_BANNEDFROMCHAN;
306           else if (*chptrb->mode.key && (!key || strcmp(key, chptrb->mode.key)))
307             err2 = ERR_BADCHANNELKEY;
308                   if(!err2) {
309                     joinbuf_join(&join, chptrb, flags);
310                     del_invite(sptr, chptrb);
311             if (chptrb->topic[0]) {
312               send_reply(sptr, RPL_TOPIC, chptrb->chname, chptrb->topic);
313               send_reply(sptr, RPL_TOPICWHOTIME, chptrb->chname, chptrb->topic_nick, chptrb->topic_time);
314             }
315             do_names(sptr, chptrb, NAMES_ALL|NAMES_EON); /* send /names list */
316                   }
317             }
318           }
319           
320       if (err) {
321         switch(err) {
322           case ERR_NEEDREGGEDNICK:
323             send_reply(sptr, 
324                        ERR_NEEDREGGEDNICK, 
325                        chptr->chname, 
326                        feature_str(FEAT_URLREG));            
327             break;
328           default:
329             send_reply(sptr, err, chptr->chname);
330             break;
331         }
332         continue;
333       }
334           
335       joinbuf_join(&join, chptr, flags);
336       if (flags & CHFL_CHANOP) {
337         struct ModeBuf mbuf;
338         /* Always let the server op him: this is needed on a net with older servers
339            because they 'destruct' channels immediately when they become empty without
340            sending out a DESTRUCT message. As a result, they would always bounce a mode
341            (as HACK(2)) when the user ops himself.
342            (There is also no particularly good reason to have the user op himself.)
343         */
344         modebuf_init(&mbuf, &me, cptr, chptr, MODEBUF_DEST_SERVER);
345         modebuf_mode_client(&mbuf, MODE_ADD | MODE_CHANOP, sptr,
346                             chptr->mode.apass[0] ? ((flags & CHFL_CHANNEL_MANAGER) ? 0 : 1) : MAXOPLEVEL);
347         modebuf_flush(&mbuf);
348       }
349     }
350
351     del_invite(sptr, chptr);
352
353     if (chptr->topic[0]) {
354       send_reply(sptr, RPL_TOPIC, chptr->chname, chptr->topic);
355       send_reply(sptr, RPL_TOPICWHOTIME, chptr->chname, chptr->topic_nick,
356                  chptr->topic_time);
357     }
358
359     do_names(sptr, chptr, NAMES_ALL|NAMES_EON|(((chptr->mode.mode & MODE_AUDITORIUM) && !(flags & CHFL_CHANOP)) ? NAMES_OPS : 0)); /* send /names list */
360   }
361
362   joinbuf_flush(&join); /* must be first, if there's a JOIN 0 */
363   joinbuf_flush(&create);
364
365   return 0;
366 }
367
368 /** Handle a JOIN message from a server connection.
369  * See @ref m_functions for discussion of the arguments.
370  * @param[in] cptr Client that sent us the message.
371  * @param[in] sptr Original source of message.
372  * @param[in] parc Number of arguments.
373  * @param[in] parv Argument vector.
374  */
375 int ms_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
376 {
377   struct Membership *member;
378   struct Channel *chptr;
379   struct JoinBuf join;
380   unsigned int flags;
381   unsigned int invisible;
382   time_t creation = 0;
383   char *p = 0;
384   char *chanlist;
385   char *name;
386
387   if (IsServer(sptr))
388   {
389     return protocol_violation(cptr,
390                               "%s tried to JOIN %s, duh!",
391                               cli_name(sptr),
392                               (parc < 2 || *parv[1] == '\0') ? "a channel" :
393                                                                parv[1]
394                               );
395   }
396
397   if (parc < 2 || *parv[1] == '\0')
398     return need_more_params(sptr, "JOIN");
399
400   if (parc > 2 && parv[2])
401     creation = atoi(parv[2]);
402   if (parc > 3 && parv[3])
403     invisible = atoi(parv[3]);
404
405   joinbuf_init(&join, sptr, cptr, JOINBUF_TYPE_JOIN, 0, 0);
406
407   chanlist = last0(cptr, sptr, parv[1]); /* find last "JOIN 0" */
408
409   for (name = ircd_strtok(&p, chanlist, ","); name;
410        name = ircd_strtok(&p, 0, ",")) {
411
412         if (invisible == 1) {
413     flags = CHFL_DEOPPED | CHFL_INVISIBLE;
414         } else {
415         flags = CHFL_DEOPPED;
416         }
417
418     if (IsLocalChannel(name) || !IsChannelName(name))
419     {
420       protocol_violation(cptr, "%s tried to join %s", cli_name(sptr), name);
421       continue;
422     }
423
424     if (!(chptr = FindChannel(name)))
425     {
426       /* No channel exists, so create one */
427       if (!(chptr = get_channel(sptr, name, CGT_CREATE)))
428       {
429         protocol_violation(sptr,"couldn't get channel %s for %s",
430                            name,cli_name(sptr));
431         continue;
432       }
433       flags |= HasFlag(sptr, FLAG_TS8) ? CHFL_SERVOPOK : 0;
434
435       chptr->creationtime = creation;
436           const struct User* user = cli_user(sptr);
437           if (IsAccount(sptr)) {
438             //chptr->chanowner = user->account;
439           }
440     }
441     else { /* We have a valid channel? */
442       if ((member = find_member_link(chptr, sptr)))
443       {
444         /* It is impossible to get here --Run */
445         if (!IsZombie(member)) /* already on channel */
446           continue;
447         if (invisible == 1) {
448          flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK | CHFL_INVISIBLE);
449         } else {
450          flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK);
451         }
452         remove_user_from_channel(sptr, chptr);
453         chptr = FindChannel(name);
454       }
455       else {
456                 flags |= HasFlag(sptr, FLAG_TS8) ? CHFL_SERVOPOK : 0;
457                 }
458       /* Always copy the timestamp when it is older, that is the only way to
459          ensure network-wide synchronization of creation times.
460          We now also copy a creation time that only 1 second younger...
461          this is needed because the timestamp must be incremented
462          by one when someone joins an existing, but empty, channel.
463          However, this is only necessary when the channel is still
464          empty (also here) and when this channel doesn't have +A set.
465
466          To prevent this from allowing net-rides on the channel, we
467          clear all modes from the channel.
468
469          (Scenario for a net ride: c1 - s1 - s2 - c2, with c1 the only
470          user in the channel; c1 parts and rejoins, gaining ops.
471          Before s2 sees c1's part, c2 joins the channel and parts
472          immediately.  s1 sees c1 part, c1 create, c2 join, c2 part;
473          c2's join resets the timestamp.  s2 sees c2 join, c2 part, c1
474          part, c1 create; but since s2 sees the channel as a zannel or
475          non-existent, it does not bounce the create with the newer
476          timestamp.)
477       */
478       if (creation && (creation < chptr->creationtime ||
479                        (!chptr->mode.apass[0] && !(chptr->mode.mode & MODE_PERSIST) && chptr->users == 0))) {
480         struct Membership *member;
481         struct ModeBuf mbuf;
482
483         chptr->creationtime = creation;
484         /* Wipe out the current modes on the channel. */
485         modebuf_init(&mbuf, sptr, cptr, chptr, MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK3);
486
487         modebuf_mode(&mbuf, MODE_DEL | chptr->mode.mode);
488         chptr->mode.mode &= MODE_BURSTADDED | MODE_WASDELJOINS;
489
490         if (chptr->mode.limit) {
491           modebuf_mode_uint(&mbuf, MODE_DEL | MODE_LIMIT, chptr->mode.limit);
492           chptr->mode.limit = 0;
493         }
494
495         if (chptr->mode.key[0]) {
496           modebuf_mode_string(&mbuf, MODE_DEL | MODE_KEY, chptr->mode.key, 0);
497           chptr->mode.key[0] = '\0';
498         }
499
500         if (chptr->mode.upass[0]) {
501           modebuf_mode_string(&mbuf, MODE_DEL | MODE_UPASS, chptr->mode.upass, 0);
502           chptr->mode.upass[0] = '\0';
503         }
504
505         if (chptr->mode.apass[0]) {
506           modebuf_mode_string(&mbuf, MODE_DEL | MODE_APASS, chptr->mode.apass, 0);
507           chptr->mode.apass[0] = '\0';
508         }
509
510         for (member = chptr->members; member; member = member->next_member)
511         {
512           if (IsChanOp(member)) {
513             modebuf_mode_client(&mbuf, MODE_DEL | MODE_CHANOP, member->user, OpLevel(member));
514             member->status &= ~CHFL_CHANOP;
515           }
516           if (HasVoice(member)) {
517             modebuf_mode_client(&mbuf, MODE_DEL | MODE_VOICE, member->user, OpLevel(member));
518             member->status &= ~CHFL_VOICE;
519           }
520         }
521         modebuf_flush(&mbuf);
522       }
523     }
524
525     joinbuf_join(&join, chptr, flags);
526   }
527
528   joinbuf_flush(&join); /* flush joins... */
529
530   return 0;
531 }