added gnutls backend and moved backend code into new files
[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         switch(err) {
243           case ERR_NEEDREGGEDNICK:
244             send_reply(sptr, 
245                        ERR_NEEDREGGEDNICK, 
246                        chptr->chname, 
247                        feature_str(FEAT_URLREG));            
248             break;
249           default:
250             send_reply(sptr, err, chptr->chname);
251             break;
252         }
253         continue;
254       }
255
256       joinbuf_join(&join, chptr, flags);
257       if (flags & CHFL_CHANOP) {
258         struct ModeBuf mbuf;
259         /* Always let the server op him: this is needed on a net with older servers
260            because they 'destruct' channels immediately when they become empty without
261            sending out a DESTRUCT message. As a result, they would always bounce a mode
262            (as HACK(2)) when the user ops himself.
263            (There is also no particularly good reason to have the user op himself.)
264         */
265         modebuf_init(&mbuf, &me, cptr, chptr, MODEBUF_DEST_SERVER);
266         modebuf_mode_client(&mbuf, MODE_ADD | MODE_CHANOP, sptr,
267                             chptr->mode.apass[0] ? ((flags & CHFL_CHANNEL_MANAGER) ? 0 : 1) : MAXOPLEVEL);
268         modebuf_flush(&mbuf);
269       }
270     }
271
272     del_invite(sptr, chptr);
273
274     if (chptr->topic[0]) {
275       send_reply(sptr, RPL_TOPIC, chptr->chname, chptr->topic);
276       send_reply(sptr, RPL_TOPICWHOTIME, chptr->chname, chptr->topic_nick,
277                  chptr->topic_time);
278     }
279
280     do_names(sptr, chptr, NAMES_ALL|NAMES_EON); /* send /names list */
281   }
282
283   joinbuf_flush(&join); /* must be first, if there's a JOIN 0 */
284   joinbuf_flush(&create);
285
286   return 0;
287 }
288
289 /** Handle a JOIN message from a server connection.
290  * See @ref m_functions for discussion of the arguments.
291  * @param[in] cptr Client that sent us the message.
292  * @param[in] sptr Original source of message.
293  * @param[in] parc Number of arguments.
294  * @param[in] parv Argument vector.
295  */
296 int ms_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
297 {
298   struct Membership *member;
299   struct Channel *chptr;
300   struct JoinBuf join;
301   unsigned int flags;
302   time_t creation = 0;
303   char *p = 0;
304   char *chanlist;
305   char *name;
306
307   if (IsServer(sptr))
308   {
309     return protocol_violation(cptr,
310                               "%s tried to JOIN %s, duh!",
311                               cli_name(sptr),
312                               (parc < 2 || *parv[1] == '\0') ? "a channel" :
313                                                                parv[1]
314                               );
315   }
316
317   if (parc < 2 || *parv[1] == '\0')
318     return need_more_params(sptr, "JOIN");
319
320   if (parc > 2 && parv[2])
321     creation = atoi(parv[2]);
322
323   joinbuf_init(&join, sptr, cptr, JOINBUF_TYPE_JOIN, 0, 0);
324
325   chanlist = last0(cptr, sptr, parv[1]); /* find last "JOIN 0" */
326
327   for (name = ircd_strtok(&p, chanlist, ","); name;
328        name = ircd_strtok(&p, 0, ",")) {
329
330     flags = CHFL_DEOPPED;
331
332     if (IsLocalChannel(name) || !IsChannelName(name))
333     {
334       protocol_violation(cptr, "%s tried to join %s", cli_name(sptr), name);
335       continue;
336     }
337
338     if (!(chptr = FindChannel(name)))
339     {
340       /* No channel exists, so create one */
341       if (!(chptr = get_channel(sptr, name, CGT_CREATE)))
342       {
343         protocol_violation(sptr,"couldn't get channel %s for %s",
344                            name,cli_name(sptr));
345         continue;
346       }
347       flags |= HasFlag(sptr, FLAG_TS8) ? CHFL_SERVOPOK : 0;
348
349       chptr->creationtime = creation;
350     }
351     else { /* We have a valid channel? */
352       if ((member = find_member_link(chptr, sptr)))
353       {
354         /* It is impossible to get here --Run */
355         if (!IsZombie(member)) /* already on channel */
356           continue;
357
358         flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK);
359         remove_user_from_channel(sptr, chptr);
360         chptr = FindChannel(name);
361       }
362       else
363         flags |= HasFlag(sptr, FLAG_TS8) ? CHFL_SERVOPOK : 0;
364       /* Always copy the timestamp when it is older, that is the only way to
365          ensure network-wide synchronization of creation times.
366          We now also copy a creation time that only 1 second younger...
367          this is needed because the timestamp must be incremented
368          by one when someone joins an existing, but empty, channel.
369          However, this is only necessary when the channel is still
370          empty (also here) and when this channel doesn't have +A set.
371
372          To prevent this from allowing net-rides on the channel, we
373          clear all modes from the channel.
374
375          (Scenario for a net ride: c1 - s1 - s2 - c2, with c1 the only
376          user in the channel; c1 parts and rejoins, gaining ops.
377          Before s2 sees c1's part, c2 joins the channel and parts
378          immediately.  s1 sees c1 part, c1 create, c2 join, c2 part;
379          c2's join resets the timestamp.  s2 sees c2 join, c2 part, c1
380          part, c1 create; but since s2 sees the channel as a zannel or
381          non-existent, it does not bounce the create with the newer
382          timestamp.)
383       */
384       if (creation && (creation < chptr->creationtime ||
385                        (!chptr->mode.apass[0] && chptr->users == 0))) {
386         struct Membership *member;
387         struct ModeBuf mbuf;
388
389         chptr->creationtime = creation;
390         /* Wipe out the current modes on the channel. */
391         modebuf_init(&mbuf, sptr, cptr, chptr, MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK3);
392
393         modebuf_mode(&mbuf, MODE_DEL | chptr->mode.mode);
394         chptr->mode.mode &= MODE_BURSTADDED | MODE_WASDELJOINS;
395
396         if (chptr->mode.limit) {
397           modebuf_mode_uint(&mbuf, MODE_DEL | MODE_LIMIT, chptr->mode.limit);
398           chptr->mode.limit = 0;
399         }
400
401         if (chptr->mode.key[0]) {
402           modebuf_mode_string(&mbuf, MODE_DEL | MODE_KEY, chptr->mode.key, 0);
403           chptr->mode.key[0] = '\0';
404         }
405
406         if (chptr->mode.upass[0]) {
407           modebuf_mode_string(&mbuf, MODE_DEL | MODE_UPASS, chptr->mode.upass, 0);
408           chptr->mode.upass[0] = '\0';
409         }
410
411         if (chptr->mode.apass[0]) {
412           modebuf_mode_string(&mbuf, MODE_DEL | MODE_APASS, chptr->mode.apass, 0);
413           chptr->mode.apass[0] = '\0';
414         }
415
416         for (member = chptr->members; member; member = member->next_member)
417         {
418           if (IsChanOp(member)) {
419             modebuf_mode_client(&mbuf, MODE_DEL | MODE_CHANOP, member->user, OpLevel(member));
420             member->status &= ~CHFL_CHANOP;
421           }
422           if (HasVoice(member)) {
423             modebuf_mode_client(&mbuf, MODE_DEL | MODE_VOICE, member->user, OpLevel(member));
424             member->status &= ~CHFL_VOICE;
425           }
426         }
427         modebuf_flush(&mbuf);
428       }
429     }
430
431     joinbuf_join(&join, chptr, flags);
432   }
433
434   joinbuf_flush(&join); /* flush joins... */
435
436   return 0;
437 }