Author: Bleep <tomh@inxpress.net>
[ircu2.10.12-pk.git] / ircd / s_serv.c
1 /*
2  * IRC - Internet Relay Chat, ircd/s_serv.c (formerly ircd/s_msg.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 #include "s_serv.h"
26 #include "IPcheck.h"
27 #include "channel.h"
28 #include "client.h"
29 #include "crule.h"
30 #include "hash.h"
31 #include "ircd.h"
32 #include "ircd_alloc.h"
33 #include "ircd_reply.h"
34 #include "ircd_string.h"
35 #include "ircd_xopen.h"
36 #include "list.h"
37 #include "msg.h"
38 #include "match.h"
39 #include "numeric.h"
40 #include "numnicks.h"
41 #include "parse.h"
42 #include "querycmds.h"
43 #include "s_bsd.h"
44 #include "s_conf.h"
45 #include "s_debug.h"
46 #include "s_misc.h"
47 #include "s_user.h"
48 #include "send.h"
49 #include "sprintf_irc.h"
50 #include "struct.h"
51 #include "sys.h"
52 #include "userload.h"
53
54 #include <assert.h>
55 #include <stdlib.h>
56 #include <string.h>
57
58 unsigned int max_connection_count = 0;
59 unsigned int max_client_count = 0;
60
61 int exit_new_server(struct Client *cptr, struct Client *sptr,
62     char *host, time_t timestamp, char *fmt, ...)
63 {
64   va_list vl;
65   char *buf =
66       (char*) MyMalloc(strlen(me.name) + strlen(host) + 22 + strlen(fmt));
67   assert(0 != buf);
68   va_start(vl, fmt);
69   if (!IsServer(sptr))
70     return vexit_client_msg(cptr, cptr, &me, fmt, vl);
71   sprintf_irc(buf, ":%s SQUIT %s " TIME_T_FMT " :", me.name, host, timestamp);
72   strcat(buf, fmt);
73   vsendto_one(cptr, buf, vl);
74   va_end(vl);
75   MyFree(buf);
76   return 0;
77 }
78
79 int a_kills_b_too(struct Client *a, struct Client *b)
80 {
81   for (; b != a && b != &me; b = b->serv->up);
82   return (a == b ? 1 : 0);
83 }
84
85 /*
86  * server_estab
87  *
88  * May only be called after a SERVER was received from cptr,
89  * and thus make_server was called, and serv->prot set. --Run
90  */
91 int server_estab(struct Client *cptr, struct ConfItem *aconf)
92 {
93   struct Client* acptr = 0;
94   const char*    inpath;
95   int split,     i;
96
97   assert(0 != cptr);
98   assert(0 != cptr->local);
99
100   split = (0 != ircd_strcmp(cptr->name, cptr->sockhost)
101       &&   0 != ircd_strncmp(cptr->info, "JUPE", 4));
102   inpath = cptr->name;
103
104   if (IsUnknown(cptr)) {
105     if (aconf->passwd[0])
106       sendto_one(cptr, "PASS :%s", aconf->passwd);
107     /*
108      *  Pass my info to the new server
109      */
110     sendto_one(cptr, "SERVER %s 1 " TIME_T_FMT " " TIME_T_FMT " J%s %s%s :%s",
111         me.name, me.serv->timestamp, cptr->serv->timestamp,
112         MAJOR_PROTOCOL, NumServCap(&me),
113         (me.info[0]) ? (me.info) : "IRCers United");
114     /*
115      * Don't charge this IP# for connecting
116      * XXX - if this comes from a server port, it will not have been added
117      * to the IP check registry, see add_connection in s_bsd.c 
118      */
119     IPcheck_connect_fail(cptr->ip);
120   }
121
122   det_confs_butmask(cptr, CONF_LEAF | CONF_HUB | CONF_SERVER | CONF_UWORLD);
123
124   if (!IsHandshake(cptr))
125     hAddClient(cptr);
126   SetServer(cptr);
127   cptr->handler = SERVER_HANDLER;
128   Count_unknownbecomesserver(UserStats);
129
130   release_dns_reply(cptr);
131
132   SetBurst(cptr);
133
134   nextping = CurrentTime;
135
136   /*
137    * NOTE: check for acptr->user == cptr->serv->user is necessary to insure
138    * that we got the same one... bleah
139    */
140   if (cptr->serv->user && *cptr->serv->by &&
141       (acptr = findNUser(cptr->serv->by))) {
142     if (acptr->user == cptr->serv->user) {
143       if (MyUser(acptr))
144         sendto_one(acptr, ":%s NOTICE %s :Link with %s established.",
145                    me.name, acptr->name, inpath);
146       else
147         sendto_one(acptr, "%s NOTICE %s%s :Link with %s established.",
148                    NumServ(&me), NumNick(acptr), inpath);
149     }
150     else {
151       /*
152        * if not the same client, set by to empty string
153        */
154       acptr = 0;
155       *cptr->serv->by = '\0';
156     }
157   }
158
159   sendto_lops_butone(acptr, "Link with %s established.", inpath);
160   cptr->serv->up = &me;
161   cptr->serv->updown = add_dlink(&me.serv->down, cptr);
162   sendto_op_mask(SNO_NETWORK, "Net junction: %s %s", me.name, cptr->name);
163   SetJunction(cptr);
164   /*
165    * Old sendto_serv_but_one() call removed because we now
166    * need to send different names to different servers
167    * (domain name matching) Send new server to other servers.
168    */
169   for (i = 0; i <= HighestFd; i++)
170   {
171     if (!(acptr = LocalClientArray[i]) || !IsServer(acptr) ||
172         acptr == cptr || IsMe(acptr))
173       continue;
174     if (!match(me.name, cptr->name))
175       continue;
176     if (split)
177     {
178         sendto_one(acptr, "%s " TOK_SERVER " %s 2 0 " TIME_T_FMT " %s%u %s%s 0 :%s",
179             NumServ(&me), cptr->name, cptr->serv->timestamp,
180             (Protocol(cptr) > 9) ? "J" : "J0", Protocol(cptr),
181             NumServCap(cptr), cptr->info);
182     }
183     else
184     {
185         sendto_one(acptr, "%s " TOK_SERVER " %s 2 0 " TIME_T_FMT " %s%u %s%s 0 :%s",
186             NumServ(&me), cptr->name, cptr->serv->timestamp,
187             (Protocol(cptr) > 9) ? "J" : "J0", Protocol(cptr),
188             NumServCap(cptr), cptr->info);
189     }
190   }
191
192   /*
193    * Pass on my client information to the new server
194    *
195    * First, pass only servers (idea is that if the link gets
196    * cancelled beacause the server was already there,
197    * there are no NICK's to be cancelled...). Of course,
198    * if cancellation occurs, all this info is sent anyway,
199    * and I guess the link dies when a read is attempted...? --msa
200    *
201    * Note: Link cancellation to occur at this point means
202    * that at least two servers from my fragment are building
203    * up connection this other fragment at the same time, it's
204    * a race condition, not the normal way of operation...
205    */
206
207   for (acptr = &me; acptr; acptr = acptr->prev) {
208     /* acptr->from == acptr for acptr == cptr */
209     if (acptr->from == cptr)
210       continue;
211     if (IsServer(acptr))
212     {
213       char *protocol_str = IsBurst(acptr) ? "J" : "P";
214       if (0 == match(me.name, acptr->name))
215         continue;
216       split = (MyConnect(acptr) && 
217                0 != ircd_strcmp(acptr->name, acptr->sockhost) &&
218                0 != ircd_strncmp(acptr->info, "JUPE", 4));
219       if (split)
220       {
221           sendto_one(cptr,
222               "%s " TOK_SERVER " %s %d 0 " TIME_T_FMT " %s%u %s%s 0 :%s",
223               NumServ(acptr->serv->up), acptr->name,
224               acptr->hopcount + 1, acptr->serv->timestamp,
225               protocol_str, Protocol(acptr),
226               NumServCap(acptr), acptr->info);
227       }
228       else
229       {
230           sendto_one(cptr,
231               "%s " TOK_SERVER " %s %d 0 " TIME_T_FMT " %s%u %s%s 0 :%s",
232               NumServ(acptr->serv->up), acptr->name,
233               acptr->hopcount + 1, acptr->serv->timestamp,
234               protocol_str, Protocol(acptr), 
235               NumServCap(acptr), acptr->info);
236       }
237     }
238   }
239
240   for (acptr = &me; acptr; acptr = acptr->prev)
241   {
242     /* acptr->from == acptr for acptr == cptr */
243     if (acptr->from == cptr)
244       continue;
245     if (IsUser(acptr))
246     {
247       char xxx_buf[8];
248       char *s = umode_str(acptr);
249       sendto_one(cptr, *s ?
250             "%s N %s %d " TIME_T_FMT " %s %s +%s %s %s%s :%s" :
251             "%s N %s %d " TIME_T_FMT " %s %s %s%s %s%s :%s",
252             NumServ(acptr->user->server),
253             acptr->name, acptr->hopcount + 1, acptr->lastnick,
254             acptr->user->username, acptr->user->host,
255             s, inttobase64(xxx_buf, ntohl(acptr->ip.s_addr), 6),
256             NumNick(acptr), acptr->info);
257     }
258   }
259   /*
260    * Last, send the BURST.
261    * (Or for 2.9 servers: pass all channels plus statuses)
262    */
263   {
264     struct Channel *chptr;
265     for (chptr = GlobalChannelList; chptr; chptr = chptr->next)
266       send_channel_modes(cptr, chptr);
267   }
268   sendto_one(cptr, "%s EB", NumServ(&me));
269   return 0;
270 }
271