Fix a possible net ride.
[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$
24  */
25
26 #include "config.h"
27
28 #include "channel.h"
29 #include "client.h"
30 #include "gline.h"
31 #include "hash.h"
32 #include "ircd.h"
33 #include "ircd_chattr.h"
34 #include "ircd_features.h"
35 #include "ircd_log.h"
36 #include "ircd_reply.h"
37 #include "ircd_string.h"
38 #include "msg.h"
39 #include "numeric.h"
40 #include "numnicks.h"
41 #include "s_debug.h"
42 #include "s_user.h"
43 #include "send.h"
44 #include "sys.h"
45
46 /* #include <assert.h> -- Now using assert in ircd_log.h */
47 #include <stdlib.h>
48 #include <string.h>
49
50 /** Searches for and handles a 0 in a join list.
51  * @param[in] cptr Client that sent us the message.
52  * @param[in] sptr Original source of message.
53  * @param[in] chanlist List of channels to join.
54  * @return First token in \a chanlist after the final 0 entry, which
55  * may be its nul terminator (if the final entry is a 0 entry).
56  */
57 static char *
58 last0(struct Client *cptr, struct Client *sptr, char *chanlist)
59 {
60   char *p;
61   int join0 = 0;
62
63   for (p = chanlist; p[0]; p++) /* find last "JOIN 0" */
64     if (p[0] == '0' && (p[1] == ',' || p[1] == '\0')) {
65       if (p[1] == ',')
66         p++;
67       chanlist = p + 1;
68       join0 = 1;
69     } else {
70       while (p[0] != ',' && p[0] != '\0') /* skip past channel name */
71         p++;
72
73       if (!p[0]) /* hit the end */
74         break;
75     }
76
77   if (join0) {
78     struct JoinBuf part;
79     struct Membership *member;
80
81     joinbuf_init(&part, sptr, cptr, JOINBUF_TYPE_PARTALL,
82                  "Left all channels", 0);
83
84     joinbuf_join(&part, 0, 0);
85
86     while ((member = cli_user(sptr)->channel))
87       joinbuf_join(&part, member->channel,
88                    IsZombie(member) ? CHFL_ZOMBIE :
89                    IsDelayedJoin(member) ? CHFL_DELAYED :
90                    0);
91
92     joinbuf_flush(&part);
93   }
94
95   return chanlist;
96 }
97
98 /** Handle a JOIN message from a client connection.
99  * See @ref m_functions for discussion of the arguments.
100  * @param[in] cptr Client that sent us the message.
101  * @param[in] sptr Original source of message.
102  * @param[in] parc Number of arguments.
103  * @param[in] parv Argument vector.
104  */
105 int m_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
106 {
107   struct Channel *chptr;
108   struct JoinBuf join;
109   struct JoinBuf create;
110   struct Gline *gline;
111   char *p = 0;
112   char *chanlist;
113   char *name;
114   char *keys;
115
116   if (parc < 2 || *parv[1] == '\0')
117     return need_more_params(sptr, "JOIN");
118
119   joinbuf_init(&join, sptr, cptr, JOINBUF_TYPE_JOIN, 0, 0);
120   joinbuf_init(&create, sptr, cptr, JOINBUF_TYPE_CREATE, 0, TStime());
121
122   chanlist = last0(cptr, sptr, parv[1]); /* find last "JOIN 0" */
123
124   keys = parv[2]; /* remember where keys are */
125
126   for (name = ircd_strtok(&p, chanlist, ","); name;
127        name = ircd_strtok(&p, 0, ",")) {
128     char *key = 0;
129
130     /* If we have any more keys, take the first for this channel. */
131     if (!BadPtr(keys)
132         && (keys = strchr(key = keys, ',')))
133       *keys++ = '\0';
134
135     /* Empty keys are the same as no keys. */
136     if (key && !key[0])
137       key = 0;
138
139     if (!IsChannelName(name) || !strIsIrcCh(name))
140     {
141       /* bad channel name */
142       send_reply(sptr, ERR_NOSUCHCHANNEL, name);
143       continue;
144     }
145
146     if (cli_user(sptr)->joined >= feature_int(FEAT_MAXCHANNELSPERUSER)
147         && !HasPriv(sptr, PRIV_CHAN_LIMIT)) {
148       send_reply(sptr, ERR_TOOMANYCHANNELS, name);
149       break; /* no point processing the other channels */
150     }
151
152     /* BADCHANed channel */
153     if ((gline = gline_find(name, GLINE_BADCHAN | GLINE_EXACT)) &&
154         GlineIsActive(gline) && !IsAnOper(sptr)) {
155       send_reply(sptr, ERR_BANNEDFROMCHAN, name);
156       continue;
157     }
158
159     if (!(chptr = FindChannel(name))) {
160       if (((name[0] == '&') && !feature_bool(FEAT_LOCAL_CHANNELS))
161           || strlen(name) >= IRCD_MIN(CHANNELLEN, feature_int(FEAT_CHANNELLEN))) {
162         send_reply(sptr, ERR_NOSUCHCHANNEL, name);
163         continue;
164       }
165
166       if (!(chptr = get_channel(sptr, name, CGT_CREATE)))
167         continue;
168
169       /* Try to add the new channel as a recent target for the user. */
170       if (check_target_limit(sptr, chptr, chptr->chname, 0)) {
171         chptr->members = 0;
172         destruct_channel(chptr);
173         continue;
174       }
175
176       joinbuf_join(&create, chptr, CHFL_CHANOP | CHFL_CHANNEL_MANAGER);
177     } else if (find_member_link(chptr, sptr)) {
178       continue; /* already on channel */
179     } else if (check_target_limit(sptr, chptr, chptr->chname, 0)) {
180       continue;
181     } else {
182       int flags = CHFL_DEOPPED;
183       int err = 0;
184
185       /* Check Apass/Upass -- since we only ever look at a single
186        * "key" per channel now, this hampers brute force attacks. */
187       if (key && !strcmp(key, chptr->mode.apass))
188         flags = CHFL_CHANOP | CHFL_CHANNEL_MANAGER;
189       else if (key && !strcmp(key, chptr->mode.upass))
190         flags = CHFL_CHANOP;
191       else if (chptr->users == 0 && !chptr->mode.apass[0]) {
192         /* Joining a zombie channel (zannel): give ops and increment TS. */
193         flags = CHFL_CHANOP;
194         chptr->creationtime++;
195       } else if (IsInvited(sptr, chptr)) {
196         /* Invites bypass these other checks. */
197       } else if (chptr->mode.mode & MODE_INVITEONLY)
198         err = ERR_INVITEONLYCHAN;
199       else if (chptr->mode.limit && (chptr->users >= chptr->mode.limit))
200         err = ERR_CHANNELISFULL;
201       else if ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
202         err = ERR_NEEDREGGEDNICK;
203       else if (find_ban(sptr, chptr->banlist))
204         err = ERR_BANNEDFROMCHAN;
205       else if (*chptr->mode.key && (!key || strcmp(key, chptr->mode.key)))
206         err = ERR_BADCHANNELKEY;
207
208       /* An oper with WALK_LCHAN privilege can join a local channel
209        * he otherwise could not join by using "OVERRIDE" as the key.
210        * This will generate a HACK(4) notice, but fails if the oper
211        * could normally join the channel. */
212       if (IsLocalChannel(chptr->chname)
213           && HasPriv(sptr, PRIV_WALK_LCHAN)
214           && !(flags & CHFL_CHANOP)
215           && key && !strcmp(key, "OVERRIDE"))
216       {
217         switch (err) {
218         case 0:
219           if (strcmp(chptr->mode.key, "OVERRIDE")
220               && strcmp(chptr->mode.apass, "OVERRIDE")
221               && strcmp(chptr->mode.upass, "OVERRIDE")) {
222             send_reply(sptr, ERR_DONTCHEAT, chptr->chname);
223             continue;
224           }
225           break;
226         case ERR_INVITEONLYCHAN: err = 'i'; break;
227         case ERR_CHANNELISFULL:  err = 'l'; break;
228         case ERR_BANNEDFROMCHAN: err = 'b'; break;
229         case ERR_BADCHANNELKEY:  err = 'k'; break;
230         case ERR_NEEDREGGEDNICK: err = 'r'; break;
231         default: err = '?'; break;
232         }
233         /* send accountability notice */
234         if (err)
235           sendto_opmask_butone(0, SNO_HACK4, "OPER JOIN: %C JOIN %H "
236                                "(overriding +%c)", sptr, chptr, err);
237         err = 0;
238       }
239
240       /* Is there some reason the user may not join? */
241       if (err) {
242         send_reply(sptr, err, chptr->chname);
243         continue;
244       }
245
246       joinbuf_join(&join, chptr, flags);
247       if (flags & CHFL_CHANOP) {
248         struct ModeBuf mbuf;
249 #if 0
250         /* Send a MODE to the other servers. If the user used the A/U pass,
251          * let his server op him, otherwise let him op himself. */
252         modebuf_init(&mbuf, chptr->mode.apass[0] ? &me : sptr, cptr, chptr, MODEBUF_DEST_SERVER);
253 #else
254         /* Always let the server op him: this is needed on a net with older servers
255            because they 'destruct' channels immediately when they become empty without
256            sending out a DESTRUCT message. As a result, they would always bounce a mode
257            (as HACK(2)) when the user ops himself. */
258         modebuf_init(&mbuf, &me, cptr, chptr, MODEBUF_DEST_SERVER);
259 #endif
260         modebuf_mode_client(&mbuf, MODE_ADD | MODE_CHANOP, sptr,
261                             chptr->mode.apass[0] ? ((flags & CHFL_CHANNEL_MANAGER) ? 0 : 1) : MAXOPLEVEL);
262         modebuf_flush(&mbuf);
263       }
264     }
265
266     del_invite(sptr, chptr);
267
268     if (chptr->topic[0]) {
269       send_reply(sptr, RPL_TOPIC, chptr->chname, chptr->topic);
270       send_reply(sptr, RPL_TOPICWHOTIME, chptr->chname, chptr->topic_nick,
271                  chptr->topic_time);
272     }
273
274     do_names(sptr, chptr, NAMES_ALL|NAMES_EON); /* send /names list */
275   }
276
277   joinbuf_flush(&join); /* must be first, if there's a JOIN 0 */
278   joinbuf_flush(&create);
279
280   return 0;
281 }
282
283 /** Handle a JOIN message from a server connection.
284  * See @ref m_functions for discussion of the arguments.
285  * @param[in] cptr Client that sent us the message.
286  * @param[in] sptr Original source of message.
287  * @param[in] parc Number of arguments.
288  * @param[in] parv Argument vector.
289  */
290 int ms_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
291 {
292   struct Membership *member;
293   struct Channel *chptr;
294   struct JoinBuf join;
295   unsigned int flags;
296   time_t creation = 0;
297   char *p = 0;
298   char *chanlist;
299   char *name;
300
301   if (IsServer(sptr))
302   {
303     return protocol_violation(cptr,
304                               "%s tried to JOIN %s, duh!",
305                               cli_name(sptr),
306                               (parc < 2 || *parv[1] == '\0') ? "a channel" :
307                                                                parv[1]
308                               );
309   }
310
311   if (parc < 2 || *parv[1] == '\0')
312     return need_more_params(sptr, "JOIN");
313
314   if (parc > 2 && parv[2])
315     creation = atoi(parv[2]);
316
317   joinbuf_init(&join, sptr, cptr, JOINBUF_TYPE_JOIN, 0, 0);
318
319   chanlist = last0(cptr, sptr, parv[1]); /* find last "JOIN 0" */
320
321   for (name = ircd_strtok(&p, chanlist, ","); name;
322        name = ircd_strtok(&p, 0, ",")) {
323
324     flags = CHFL_DEOPPED;
325
326     if (IsLocalChannel(name) || !IsChannelName(name))
327     {
328       protocol_violation(cptr, "%s tried to join %s", cli_name(sptr), name);
329       continue;
330     }
331
332     if (!(chptr = FindChannel(name)))
333     {
334       /* No channel exists, so create one */
335       if (!(chptr = get_channel(sptr, name, CGT_CREATE)))
336       {
337         protocol_violation(sptr,"couldn't get channel %s for %s",
338                            name,cli_name(sptr));
339         continue;
340       }
341       flags |= HasFlag(sptr, FLAG_TS8) ? CHFL_SERVOPOK : 0;
342
343       /* when the network is 2.10.11+ then remove MAGIC_REMOTE_JOIN_TS */
344       chptr->creationtime = creation ? creation : MAGIC_REMOTE_JOIN_TS;
345     }
346     else { /* We have a valid channel? */
347       if ((member = find_member_link(chptr, sptr)))
348       {
349         /* It is impossible to get here --Run */
350         if (!IsZombie(member)) /* already on channel */
351           continue;
352
353         flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK);
354         remove_user_from_channel(sptr, chptr);
355         chptr = FindChannel(name);
356       }
357       else
358         flags |= HasFlag(sptr, FLAG_TS8) ? CHFL_SERVOPOK : 0;
359       /* Always copy the timestamp when it is older, that is the only way to
360          ensure network-wide synchronization of creation times.
361          We now also copy a creation time that only 1 second younger...
362          this is needed because the timestamp must be incremented
363          by one when someone joins an existing, but empty, channel.
364          However, this is only necessary when the channel is still
365          empty (also here) and when this channel doesn't have +A set.
366
367          To prevent this from allowing net-rides on the channel, we
368          clear all ops from the channel.
369
370          (Scenario for a net ride: c1 - s1 - s2 - c2, with c1 the only
371          user in the channel; c1 parts and rejoins, gaining ops.
372          Before s2 sees c1's part, c2 joins the channel and parts
373          immediately.  s1 sees c1 part, c1 create, c2 join, c2 part;
374          c2's join resets the timestamp.  s2 sees c2 join, c2 part, c1
375          part, c1 create; but since s2 sees the channel as a zannel or
376          non-existent, it does not bounce the create with the newer
377          timestamp.)
378       */
379       if (creation && creation - ((!chptr->mode.apass[0] && chptr->users == 0) ? 1 : 0) <= chptr->creationtime)
380       {
381         struct Membership *member;
382         struct ModeBuf mbuf;
383
384         chptr->creationtime = creation;
385         /* Deop the current ops.  (This will go in both directions on
386          * the network, and revise the channel timestamp as it goes,
387          * avoiding further traffic due to the JOIN.)
388          */
389         modebuf_init(&mbuf, sptr, cptr, chptr, MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK3 | MODEBUF_DEST_SERVER);
390         for (member = chptr->members; member; member = member->next_member)
391         {
392           if (IsChanOp(member))
393             modebuf_mode_client(&mbuf, MODE_DEL | MODE_CHANOP, member->user, OpLevel(member));
394         }
395         modebuf_flush(&mbuf);
396       }
397     }
398
399     joinbuf_join(&join, chptr, flags);
400   }
401
402   joinbuf_flush(&join); /* flush joins... */
403
404   return 0;
405 }