Author: Ghostwolf <foxxe@wtfs.net>
[ircu2.10.12-pk.git] / ircd / m_server.c
1 /*
2  * IRC - Internet Relay Chat, ircd/m_server.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 /*
27  * m_functions execute protocol messages on this server:
28  *
29  *    cptr    is always NON-NULL, pointing to a *LOCAL* client
30  *            structure (with an open socket connected!). This
31  *            identifies the physical socket where the message
32  *            originated (or which caused the m_function to be
33  *            executed--some m_functions may call others...).
34  *
35  *    sptr    is the source of the message, defined by the
36  *            prefix part of the message if present. If not
37  *            or prefix not found, then sptr==cptr.
38  *
39  *            (!IsServer(cptr)) => (cptr == sptr), because
40  *            prefixes are taken *only* from servers...
41  *
42  *            (IsServer(cptr))
43  *                    (sptr == cptr) => the message didn't
44  *                    have the prefix.
45  *
46  *                    (sptr != cptr && IsServer(sptr) means
47  *                    the prefix specified servername. (?)
48  *
49  *                    (sptr != cptr && !IsServer(sptr) means
50  *                    that message originated from a remote
51  *                    user (not local).
52  *
53  *            combining
54  *
55  *            (!IsServer(sptr)) means that, sptr can safely
56  *            taken as defining the target structure of the
57  *            message in this server.
58  *
59  *    *Always* true (if 'parse' and others are working correct):
60  *
61  *    1)      sptr->from == cptr  (note: cptr->from == cptr)
62  *
63  *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
64  *            *cannot* be a local connection, unless it's
65  *            actually cptr!). [MyConnect(x) should probably
66  *            be defined as (x == x->from) --msa ]
67  *
68  *    parc    number of variable parameter strings (if zero,
69  *            parv is allowed to be NULL)
70  *
71  *    parv    a NULL terminated list of parameter pointers,
72  *
73  *                    parv[0], sender (prefix string), if not present
74  *                            this points to an empty string.
75  *                    parv[1]...parv[parc-1]
76  *                            pointers to additional parameters
77  *                    parv[parc] == NULL, *always*
78  *
79  *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
80  *                    non-NULL pointers.
81  */
82 #include "config.h"
83
84 #include "client.h"
85 #include "hash.h"
86 #include "ircd.h"
87 #include "ircd_log.h"
88 #include "ircd_policy.h"
89 #include "ircd_features.h"
90 #include "ircd_reply.h"
91 #include "ircd_string.h"
92 #include "jupe.h"
93 #include "list.h"
94 #include "match.h"
95 #include "msg.h"
96 #include "numeric.h"
97 #include "numnicks.h"
98 #include "querycmds.h"
99 #include "s_bsd.h"
100 #include "s_conf.h"
101 #include "s_debug.h"
102 #include "s_misc.h"
103 #include "s_serv.h"
104 #include "send.h"
105 #include "userload.h"
106 #include "map.h"
107
108 #include <assert.h>
109 #include <stdlib.h>
110 #include <string.h>
111
112 /*
113  * mr_server - registration message handler
114  *
115  *    parv[0] = sender prefix
116  *    parv[1] = servername
117  *    parv[2] = hopcount
118  *    parv[3] = start timestamp
119  *    parv[4] = link timestamp
120  *    parv[5] = major protocol version: P09/P10
121  *    parv[parc-1] = serverinfo
122  *  If cptr is P10:
123  *    parv[6] = "YMM", where 'Y' is the server numeric and "MM" is the
124  *              numeric nick mask of this server.
125  *    parv[7] = +hs (h == hub, s == service)
126  */
127 int mr_server(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
128 {
129   char*            ch;
130   int              i;
131   char             info[REALLEN + 1];
132   char*            host;
133   struct Client*   acptr;
134   struct Client*   bcptr;
135   struct Client*   LHcptr = 0;
136   struct ConfItem* aconf = 0;
137   struct ConfItem* lhconf = 0;
138   struct Jupe*     ajupe = 0;
139   int              hop;
140   int              ret;
141   int              active_lh_line = 0;
142   unsigned short   prot;
143   time_t           start_timestamp;
144   time_t           timestamp = 0;
145   time_t           recv_time;
146   time_t           ghost = 0;
147
148   if (IsUserPort(cptr))
149     return exit_client_msg(cptr, cptr, &me, 
150                            "Cannot connect a server to a user port");
151
152   recv_time = TStime();
153   info[0] = '\0';
154
155   if (parc < 7)
156   {
157     need_more_params(sptr, "SERVER");
158     return exit_client(cptr, cptr, &me, "Need more parameters");
159   }
160   host = parv[1];
161
162   if ((ajupe = jupe_find(host)) && JupeIsActive(ajupe))
163     return exit_client_msg(cptr, sptr, &me, "Juped: %s", JupeReason(ajupe));
164
165   log_write(LS_NETWORK, L_NOTICE, LOG_NOSNOTICE, "SERVER: %s %s[%s]", parv[1],
166             cli_sockhost(cptr), cli_sock_ip(cptr));
167
168   /*
169    * Detect protocol
170    */
171   if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
172     return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
173
174   *parv[5] = 'J';
175
176   if (*parv[7] == '+') {
177     for (ch = parv[7] + 1; *ch; ch++)
178       switch (*ch) {
179       case 'h':
180         SetHub(cptr);
181         break;
182       case 's':
183         SetService(cptr);
184         break;
185       }
186   }
187
188   prot = atoi(parv[5] + 1);
189   if (prot > atoi(MAJOR_PROTOCOL))
190     prot = atoi(MAJOR_PROTOCOL);
191
192   hop = atoi(parv[2]);
193   start_timestamp = atoi(parv[3]);
194   timestamp = atoi(parv[4]);
195   Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age %Tu (%Tu)",
196          host, parv[4], start_timestamp, cli_serv(&me)->timestamp));
197
198   if ((timestamp < OLDEST_TS || (hop == 1 && start_timestamp < OLDEST_TS)))
199   {
200     return exit_client_msg(cptr, sptr, &me,
201         "Bogus timestamps (%s %s)", parv[3], parv[4]);
202   }
203   ircd_strncpy(info, parv[parc - 1], REALLEN);
204   info[REALLEN] = '\0';
205   if (prot < atoi(MINOR_PROTOCOL)) {
206     sendto_opmask_butone(0, SNO_OLDSNO, "Got incompatible protocol version "
207                          "(%s) from %s", parv[5], cli_name(cptr));
208     return exit_new_server(cptr, sptr, host, timestamp,
209                            "Incompatible protocol: %s", parv[5]);
210   }
211   /*
212    * Check for "FRENCH " infection ;-) (actually this should
213    * be replaced with routine to check the hostname syntax in
214    * general). [ This check is still needed, even after the parse
215    * is fixed, because someone can send "SERVER :foo bar " ].
216    * Also, changed to check other "difficult" characters, now
217    * that parse lets all through... --msa
218    */
219   if (strlen(host) > HOSTLEN)
220     host[HOSTLEN] = '\0';
221
222   for (ch = host; *ch; ch++) {
223     if (*ch <= ' ' || *ch > '~')
224       break;
225   }
226   if (*ch || !strchr(host, '.')) {
227     sendto_opmask_butone(0, SNO_OLDSNO, "Bogus server name (%s) from %s",
228                          host, cli_name(cptr));
229     return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
230   }
231
232   if (IsUnknown(cptr) || IsHandshake(cptr))
233   {
234     const char* encr;
235
236     /*
237      * A local link that is still in undefined state wants
238      * to be a SERVER. Check if this is allowed and change
239      * status accordingly...
240      */
241     /*
242      * If there is more then one server on the same machine
243      * that we try to connect to, it could be that the /CONNECT
244      * <mask> caused this connect to be put at the wrong place
245      * in the hashtable.        --Run
246      * Same thing for Unknown connections that first send NICK.
247      *                          --Xorath
248      * Better check if the two strings are (caseless) identical 
249      * and not mess with hash internals. 
250      *                          --Nemesi
251      */
252     if (!EmptyString(cli_name(cptr)) && 
253         (IsUnknown(cptr) || IsHandshake(cptr)) &&
254         0 != ircd_strcmp(cli_name(cptr), host))
255       hChangeClient(cptr, host);
256     ircd_strncpy(cli_name(cptr), host, HOSTLEN);
257     ircd_strncpy(cli_info(cptr), info[0] ? info : cli_name(&me), REALLEN);
258     cli_hopcount(cptr) = hop;
259
260     /* check connection rules */
261     if (0 != conf_eval_crule(host, CRULE_ALL)) {
262       ServerStats->is_ref++;
263       sendto_opmask_butone(0, SNO_OLDSNO, "Refused connection from %s.", cli_name(cptr));
264       return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
265     }
266
267     if (conf_check_server(cptr)) {
268       ++ServerStats->is_ref;
269       sendto_opmask_butone(0, SNO_OLDSNO, "Received unauthorized connection "
270                            "from %s.", cli_name(cptr));
271       return exit_client(cptr, cptr, &me, "No C:line");
272     }
273
274     host = cli_name(cptr);
275
276     update_load();
277
278     if (!(aconf = find_conf_byname(cli_confs(cptr), host, CONF_SERVER))) {
279       ++ServerStats->is_ref;
280       sendto_opmask_butone(0, SNO_OLDSNO, "Access denied. No conf line for "
281                            "server %s", cli_name(cptr));
282       return exit_client_msg(cptr, cptr, &me,
283           "Access denied. No conf line for server %s", cli_name(cptr));
284     }
285     encr = cli_passwd(cptr);
286
287     if (*aconf->passwd && !!strcmp(aconf->passwd, encr)) {
288       ++ServerStats->is_ref;
289       sendto_opmask_butone(0, SNO_OLDSNO, "Access denied (passwd mismatch) %s",
290                            cli_name(cptr));
291       return exit_client_msg(cptr, cptr, &me,
292           "No Access (passwd mismatch) %s", cli_name(cptr));
293     }
294
295     memset(cli_passwd(cptr), 0, sizeof(cli_passwd(cptr)));
296
297     if (!feature_bool(FEAT_HUB)) {
298       for (i = 0; i <= HighestFd; i++)
299         if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
300           active_lh_line = 3;
301           LHcptr = 0;
302           break;
303         }
304     }
305   }
306
307   /*
308    *  We want to find IsConnecting() and IsHandshake() too,
309    *  use FindClient().
310    *  The second finds collisions with numeric representation of existing
311    *  servers - these shouldn't happen anymore when all upgraded to 2.10.
312    *  -- Run
313    */
314   while ((acptr = FindClient(host)) || 
315          (parc > 7 && (acptr = FindNServer(parv[6]))))
316   {
317     /*
318      *  This link is trying feed me a server that I already have
319      *  access through another path
320      *
321      *  Do not allow Uworld to do this.
322      *  Do not allow servers that are juped.
323      *  Do not allow servers that have older link timestamps
324      *    then this try.
325      *  Do not allow servers that use the same numeric as an existing
326      *    server, but have a different name.
327      *
328      *  If my ircd.conf sucks, I can try to connect to myself:
329      */
330     if (acptr == &me)
331       return exit_client_msg(cptr, cptr, &me, "nick collision with me (%s), check server number in M:?", host);
332     /*
333      * Detect wrong numeric.
334      */
335     if (0 != ircd_strcmp(cli_name(acptr), host)) {
336       sendcmdto_serv_butone(&me, CMD_WALLOPS, cptr,
337                             ":SERVER Numeric Collision: %s != %s",
338                             cli_name(acptr), host);
339       return exit_client_msg(cptr, cptr, &me,
340           "NUMERIC collision between %s and %s."
341           " Is your server numeric correct ?", host, cli_name(acptr));
342     }
343     /*
344      *  Kill our try, if we had one.
345      */
346     if (IsConnecting(acptr))
347     {
348       if (!active_lh_line && exit_client(cptr, acptr, &me,
349           "Just connected via another link") == CPTR_KILLED)
350         return CPTR_KILLED;
351       /*
352        * We can have only ONE 'IsConnecting', 'IsHandshake' or
353        * 'IsServer', because new 'IsConnecting's are refused to
354        * the same server if we already had it.
355        */
356       break;
357     }
358     /*
359      * Avoid other nick collisions...
360      * This is a doubtfull test though, what else would it be
361      * when it has a server.name ?
362      */
363     else if (!IsServer(acptr) && !IsHandshake(acptr))
364       return exit_client_msg(cptr, cptr, &me,
365                              "Nickname %s already exists!", host);
366     /*
367      * Our new server might be a juped server,
368      * or someone trying abuse a second Uworld:
369      */
370     else if (IsServer(acptr) && (0 == ircd_strncmp(cli_info(acptr), "JUPE", 4) ||
371         find_conf_byhost(cli_confs(cptr), cli_name(acptr), CONF_UWORLD)))
372     {
373       if (!IsServer(sptr))
374         return exit_client(cptr, sptr, &me, cli_info(acptr));
375       sendcmdto_serv_butone(&me, CMD_WALLOPS, cptr,
376                             ":Received :%s SERVER %s from %s !?!", parv[0],
377                             parv[1], cli_name(cptr));
378       return exit_new_server(cptr, sptr, host, timestamp, "%s", cli_info(acptr));
379     }
380     /*
381      * Of course we find the handshake this link was before :)
382      */
383     else if (IsHandshake(acptr) && acptr == cptr)
384       break;
385     /*
386      * Here we have a server nick collision...
387      * We don't want to kill the link that was last /connected,
388      * but we neither want to kill a good (old) link.
389      * Therefor we kill the second youngest link.
390      */
391     if (1)
392     {
393       struct Client* c2ptr = 0;
394       struct Client* c3ptr = acptr;
395       struct Client* ac2ptr;
396       struct Client* ac3ptr;
397
398       /* Search youngest link: */
399       for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up)
400         if (cli_serv(ac3ptr)->timestamp > cli_serv(c3ptr)->timestamp)
401           c3ptr = ac3ptr;
402       if (IsServer(sptr))
403       {
404         for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up)
405           if (cli_serv(ac3ptr)->timestamp > cli_serv(c3ptr)->timestamp)
406             c3ptr = ac3ptr;
407       }
408       if (timestamp > cli_serv(c3ptr)->timestamp)
409       {
410         c3ptr = 0;
411         c2ptr = acptr;          /* Make sure they differ */
412       }
413       /* Search second youngest link: */
414       for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = cli_serv(ac2ptr)->up)
415         if (ac2ptr != c3ptr &&
416             cli_serv(ac2ptr)->timestamp >
417             (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
418           c2ptr = ac2ptr;
419       if (IsServer(sptr))
420       {
421         for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = cli_serv(ac2ptr)->up)
422           if (ac2ptr != c3ptr &&
423               cli_serv(ac2ptr)->timestamp >
424               (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
425             c2ptr = ac2ptr;
426       }
427       if (c3ptr && timestamp > (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
428         c2ptr = 0;
429       /* If timestamps are equal, decide which link to break
430        *  by name.
431        */
432       if ((c2ptr ? cli_serv(c2ptr)->timestamp : timestamp) ==
433           (c3ptr ? cli_serv(c3ptr)->timestamp : timestamp))
434       {
435         char* n2;
436         char* n2up;
437         char* n3;
438         char* n3up;
439         if (c2ptr)
440         {
441           n2 = cli_name(c2ptr);
442           n2up = MyConnect(c2ptr) ? cli_name(&me) : cli_name(cli_serv(c2ptr)->up);
443         }
444         else
445         {
446           n2 = host;
447           n2up = IsServer(sptr) ? cli_name(sptr) : cli_name(&me);
448         }
449         if (c3ptr)
450         {
451           n3 = cli_name(c3ptr);
452           n3up = MyConnect(c3ptr) ? cli_name(&me) : cli_name(cli_serv(c3ptr)->up);
453         }
454         else
455         {
456           n3 = host;
457           n3up = IsServer(sptr) ? cli_name(sptr) : cli_name(&me);
458         }
459         if (strcmp(n2, n2up) > 0)
460           n2 = n2up;
461         if (strcmp(n3, n3up) > 0)
462           n3 = n3up;
463         if (strcmp(n3, n2) > 0)
464         {
465           ac2ptr = c2ptr;
466           c2ptr = c3ptr;
467           c3ptr = ac2ptr;
468         }
469       }
470       /* Now squit the second youngest link: */
471       if (!c2ptr)
472         return exit_new_server(cptr, sptr, host, timestamp,
473                                "server %s already exists and is %ld seconds younger.",
474                                host, (long)cli_serv(acptr)->timestamp - (long)timestamp);
475       else if (cli_from(c2ptr) == cptr || IsServer(sptr))
476       {
477         struct Client *killedptrfrom = cli_from(c2ptr);
478         if (active_lh_line)
479         {
480           /*
481            * If the L: or H: line also gets rid of this link,
482            * we sent just one squit.
483            */
484           if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
485             break;
486           /*
487            * If breaking the loop here solves the L: or H:
488            * line problem, we don't squit that.
489            */
490           if (cli_from(c2ptr) == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
491             active_lh_line = 0;
492           else
493           {
494             /*
495              * If we still have a L: or H: line problem,
496              * we prefer to squit the new server, solving
497              * loop and L:/H: line problem with only one squit.
498              */
499             LHcptr = 0;
500             break;
501           }
502         }
503         /*
504          * If the new server was introduced by a server that caused a
505          * Ghost less then 20 seconds ago, this is probably also
506          * a Ghost... (20 seconds is more then enough because all
507          * SERVER messages are at the beginning of a net.burst). --Run
508          */
509         if (CurrentTime - cli_serv(cptr)->ghost < 20)
510         {
511           killedptrfrom = cli_from(acptr);
512           if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
513             return CPTR_KILLED;
514         }
515         else if (exit_client_msg(cptr, c2ptr, &me,
516             "Loop <-- %s (new link is %ld seconds younger)", host,
517             (c3ptr ? (long)cli_serv(c3ptr)->timestamp : timestamp) -
518             (long)cli_serv(c2ptr)->timestamp) == CPTR_KILLED)
519           return CPTR_KILLED;
520         /*
521          * Did we kill the incoming server off already ?
522          */
523         if (killedptrfrom == cptr)
524           return 0;
525       }
526       else
527       {
528         if (active_lh_line)
529         {
530           if (LHcptr && a_kills_b_too(LHcptr, acptr))
531             break;
532           if (cli_from(acptr) == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
533             active_lh_line = 0;
534           else
535           {
536             LHcptr = 0;
537             break;
538           }
539         }
540         /*
541          * We can't believe it is a lagged server message
542          * when it directly connects to us...
543          * kill the older link at the ghost, rather then
544          * at the second youngest link, assuming it isn't
545          * a REAL loop.
546          */
547         ghost = CurrentTime;            /* Mark that it caused a ghost */
548         if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
549           return CPTR_KILLED;
550         break;
551       }
552     }
553   }
554
555   if (active_lh_line)
556   {
557     if (LHcptr == 0) {
558       return exit_new_server(cptr, sptr, host, timestamp,
559           (active_lh_line == 2) ?  "Non-Hub link %s <- %s(%s), check H:" : 
560                                    "Leaf-only link %s <- %s(%s), check L:",
561           cli_name(cptr), host, 
562           lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
563     }
564     else
565     {
566       int killed = a_kills_b_too(LHcptr, sptr);
567       if (active_lh_line < 3)
568       {
569         if (exit_client_msg(cptr, LHcptr, &me,
570             (active_lh_line == 2) ?  "Non-Hub link %s <- %s(%s), check H:" : 
571                                      "Leaf-only link %s <- %s(%s), check L:",
572             cli_name(cptr), host,
573             lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
574           return CPTR_KILLED;
575       }
576       else
577       {
578         ServerStats->is_ref++;
579         if (exit_client(cptr, LHcptr, &me, "I'm a leaf, define HUB") == CPTR_KILLED)
580           return CPTR_KILLED;
581       }
582       /*
583        * Did we kill the incoming server off already ?
584        */
585       if (killed)
586         return 0;
587     }
588   }
589
590   if (IsUnknown(cptr) || IsHandshake(cptr))
591   {
592     make_server(cptr);
593     cli_serv(cptr)->timestamp = timestamp;
594     cli_serv(cptr)->prot = prot;
595     cli_serv(cptr)->ghost = ghost;
596     SetServerYXX(cptr, cptr, parv[6]);
597     if (start_timestamp > OLDEST_TS)
598     {
599       Debug((DEBUG_DEBUG, "My start time: %Tu; other's start time: %Tu",
600              cli_serv(&me)->timestamp, start_timestamp));
601       Debug((DEBUG_DEBUG, "Receive time: %Tu; received timestamp: %Tu; "
602              "difference %ld", recv_time, timestamp, timestamp - recv_time));
603       if (feature_bool(FEAT_RELIABLE_CLOCK)) {
604         if (start_timestamp < cli_serv(&me)->timestamp)
605           cli_serv(&me)->timestamp = start_timestamp;
606         if (IsUnknown(cptr))
607           cli_serv(cptr)->timestamp = TStime();
608       } else {
609         if (start_timestamp < cli_serv(&me)->timestamp) {
610           sendto_opmask_butone(0, SNO_OLDSNO, "got earlier start time: "
611                                "%Tu < %Tu", start_timestamp,
612                                cli_serv(&me)->timestamp);
613           cli_serv(&me)->timestamp = start_timestamp;
614           TSoffset += timestamp - recv_time;
615           sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
616                                (int)(timestamp - recv_time));
617         } else if ((start_timestamp > cli_serv(&me)->timestamp) &&
618                  IsUnknown(cptr))
619           cli_serv(cptr)->timestamp = TStime();
620
621         else if (timestamp != recv_time) {
622           /*
623            * Equal start times, we have a collision.  Let the connected-to
624            * server decide. This assumes leafs issue more than half of the
625            * connection attempts.
626            */
627           if (IsUnknown(cptr))
628             cli_serv(cptr)->timestamp = TStime();
629           else if (IsHandshake(cptr)) {
630             sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
631                                  (int)(timestamp - recv_time));
632             TSoffset += timestamp - recv_time;
633           }
634         }
635       }
636     }
637
638     ret = server_estab(cptr, aconf);
639   }
640   else
641     ret = 0;
642
643 #ifdef HEAD_IN_SAND_MAP
644   map_update(cptr);
645 #endif
646
647   if (feature_bool(FEAT_RELIABLE_CLOCK) &&
648       abs(cli_serv(cptr)->timestamp - recv_time) > 30) {
649     sendto_opmask_butone(0, SNO_OLDSNO, "Connected to a net with a "
650                          "timestamp-clock difference of %Td seconds! "
651                          "Used SETTIME to correct this.",
652                          timestamp - recv_time);
653     sendcmdto_prio_one(&me, CMD_SETTIME, cptr, "%Tu :%s", TStime(),
654                        cli_name(&me));
655   }
656
657   return ret;
658 }
659
660 /*
661  * ms_server - server message handler
662  *
663  *    parv[0] = sender prefix
664  *    parv[1] = servername
665  *    parv[2] = hopcount
666  *    parv[3] = start timestamp
667  *    parv[4] = link timestamp
668  *    parv[5] = major protocol version: P09/P10
669  *    parv[parc-1] = serverinfo
670  *  If cptr is P10:
671  *    parv[6] = "YMM", where 'Y' is the server numeric and "MM" is the
672  *              numeric nick mask of this server.
673  *    parv[7] = +hs (h == hub, s == service)
674  */
675 int ms_server(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
676 {
677   char*            ch;
678   int              i;
679   char             info[REALLEN + 1];
680   char*            host;
681   struct Client*   acptr;
682   struct Client*   bcptr;
683   struct Client*   LHcptr = 0;
684   struct ConfItem* aconf = 0;
685   struct ConfItem* lhconf = 0;
686   int              hop;
687   int              ret;
688   int              active_lh_line = 0;
689   unsigned short   prot;
690   time_t           start_timestamp;
691   time_t           timestamp = 0;
692   time_t           recv_time;
693   time_t           ghost = 0;
694
695   recv_time = TStime();
696   info[0] = '\0';
697   if (parc < 7)
698   {
699     return need_more_params(sptr, "SERVER");
700     return exit_client(cptr, cptr, &me, "Need more parameters");
701   }
702   host = parv[1];
703
704   /*
705    * Detect protocol
706    */
707   if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
708     return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
709
710   *parv[5] = 'J';
711
712   if (*parv[7] == '+') {
713     for (ch = parv[7] + 1; *ch; ch++)
714       switch (*ch) {
715       case 'h':
716         SetHub(cptr);
717         break;
718       case 's':
719         SetService(cptr);
720         break;
721       }
722   }
723
724   prot = atoi(parv[5] + 1);
725   if (prot > atoi(MAJOR_PROTOCOL))
726     prot = atoi(MAJOR_PROTOCOL);
727   hop = atoi(parv[2]);
728   start_timestamp = atoi(parv[3]);
729   timestamp = atoi(parv[4]);
730
731   Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age %Tu (%Tu)",
732          host, parv[4], start_timestamp, cli_serv(&me)->timestamp));
733
734   if ((timestamp < OLDEST_TS || (hop == 1 && start_timestamp < OLDEST_TS)))
735   {
736     return exit_client_msg(cptr, sptr, &me,
737         "Bogus timestamps (%s %s)", parv[3], parv[4]);
738   }
739
740   ircd_strncpy(info, parv[parc - 1], REALLEN);
741   info[REALLEN] = '\0';
742
743   if (prot < atoi(MINOR_PROTOCOL)) {
744     sendto_opmask_butone(0, SNO_OLDSNO, "Got incompatible protocol version "
745                          "(%s) from %s", parv[5], cli_name(cptr));
746     return exit_new_server(cptr, sptr, host, timestamp,
747                            "Incompatible protocol: %s", parv[5]);
748   }
749
750   /*
751    * Check for "FRENCH " infection ;-) (actually this should
752    * be replaced with routine to check the hostname syntax in
753    * general). [ This check is still needed, even after the parse
754    * is fixed, because someone can send "SERVER :foo bar " ].
755    * Also, changed to check other "difficult" characters, now
756    * that parse lets all through... --msa
757    */
758   if (strlen(host) > HOSTLEN)
759     host[HOSTLEN] = '\0';
760   for (ch = host; *ch; ch++)
761     if (*ch <= ' ' || *ch > '~')
762       break;
763   if (*ch || !strchr(host, '.')) {
764     sendto_opmask_butone(0, SNO_OLDSNO, "Bogus server name (%s) from %s",
765                          host, cli_name(cptr));
766     return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
767   }
768
769   /*
770    *  We want to find IsConnecting() and IsHandshake() too,
771    *  use FindClient().
772    *  The second finds collisions with numeric representation of existing
773    *  servers - these shouldn't happen anymore when all upgraded to 2.10.
774    *  -- Run
775    */
776   while ((acptr = FindClient(host)) || 
777          (parc > 7 && (acptr = FindNServer(parv[6]))))
778   {
779     /*
780      *  This link is trying feed me a server that I already have
781      *  access through another path
782      *
783      *  Do not allow Uworld to do this.
784      *  Do not allow servers that are juped.
785      *  Do not allow servers that have older link timestamps
786      *    then this try.
787      *  Do not allow servers that use the same numeric as an existing
788      *    server, but have a different name.
789      *
790      *  If my ircd.conf sucks, I can try to connect to myself:
791      */
792     if (acptr == &me)
793       return exit_client_msg(cptr, cptr, &me,
794           "nick collision with me, check server number in M:? (%s)", host);
795     /*
796      * Detect wrong numeric.
797      */
798     if (0 != ircd_strcmp(cli_name(acptr), host))
799     {
800       sendcmdto_serv_butone(&me, CMD_WALLOPS, cptr,
801                             ":SERVER Numeric Collision: %s != %s", cli_name(acptr),
802                             host);
803       return exit_client_msg(cptr, cptr, &me,
804           "NUMERIC collision between %s and %s."
805           " Is your server numeric correct ?", host, cli_name(acptr));
806     }
807
808     /*
809      *  Kill our try, if we had one.
810      */
811     if (IsConnecting(acptr))
812     {
813       if (!active_lh_line && exit_client(cptr, acptr, &me,
814           "Just connected via another link") == CPTR_KILLED)
815         return CPTR_KILLED;
816       /*
817        * We can have only ONE 'IsConnecting', 'IsHandshake' or
818        * 'IsServer', because new 'IsConnecting's are refused to
819        * the same server if we already had it.
820        */
821       break;
822     }
823     /*
824      * Avoid other nick collisions...
825      * This is a doubtfull test though, what else would it be
826      * when it has a server.name ?
827      */
828     else if (!IsServer(acptr) && !IsHandshake(acptr))
829       return exit_client_msg(cptr, cptr, &me,
830           "Nickname %s already exists!", host);
831     /*
832      * Our new server might be a juped server,
833      * or someone trying abuse a second Uworld:
834      */
835     else if (IsServer(acptr) && (0 == ircd_strncmp(cli_info(acptr), "JUPE", 4) ||
836         find_conf_byhost(cli_confs(cptr), cli_name(acptr), CONF_UWORLD)))
837     {
838       if (!IsServer(sptr))
839         return exit_client(cptr, sptr, &me, cli_info(acptr));
840       sendcmdto_one(&me, CMD_WALLOPS, cptr, ":Received :%s SERVER %s "
841                     "from %s !?!", parv[0], parv[1], cli_name(cptr));
842       return exit_new_server(cptr, sptr, host, timestamp, "%s", cli_info(acptr));
843     }
844     /*
845      * Of course we find the handshake this link was before :)
846      */
847     else if (IsHandshake(acptr) && acptr == cptr)
848       break;
849     /*
850      * Here we have a server nick collision...
851      * We don't want to kill the link that was last /connected,
852      * but we neither want to kill a good (old) link.
853      * Therefor we kill the second youngest link.
854      */
855     if (1)
856     {
857       struct Client* c2ptr = 0;
858       struct Client* c3ptr = acptr;
859       struct Client* ac2ptr;
860       struct Client* ac3ptr;
861
862       /* Search youngest link: */
863       for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up)
864         if (cli_serv(ac3ptr)->timestamp > cli_serv(c3ptr)->timestamp)
865           c3ptr = ac3ptr;
866
867       if (IsServer(sptr))
868       {
869         for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up)
870           if (cli_serv(ac3ptr)->timestamp > cli_serv(c3ptr)->timestamp)
871             c3ptr = ac3ptr;
872       }
873
874       if (timestamp > cli_serv(c3ptr)->timestamp)
875       {
876         c3ptr = 0;
877         c2ptr = acptr;          /* Make sure they differ */
878       }
879
880       /* Search second youngest link: */
881       for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = cli_serv(ac2ptr)->up)
882         if (ac2ptr != c3ptr &&
883             cli_serv(ac2ptr)->timestamp >
884             (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
885           c2ptr = ac2ptr;
886
887       if (IsServer(sptr))
888       {
889         for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = cli_serv(ac2ptr)->up)
890           if (ac2ptr != c3ptr &&
891               cli_serv(ac2ptr)->timestamp >
892               (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
893             c2ptr = ac2ptr;
894       }
895
896       if (c3ptr && timestamp > (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
897         c2ptr = 0;
898
899       /* If timestamps are equal, decide which link to break
900        *  by name.
901        */
902       if ((c2ptr ? cli_serv(c2ptr)->timestamp : timestamp) ==
903           (c3ptr ? cli_serv(c3ptr)->timestamp : timestamp))
904       {
905         char* n2;
906         char* n2up;
907         char* n3;
908         char* n3up;
909
910         if (c2ptr)
911         {
912           n2 = cli_name(c2ptr);
913           n2up = MyConnect(c2ptr) ? cli_name(&me) : cli_name(cli_serv(c2ptr)->up);
914         }
915         else
916         {
917           n2 = host;
918           n2up = IsServer(sptr) ? cli_name(sptr) : cli_name(&me);
919         }
920
921         if (c3ptr)
922         {
923           n3 = cli_name(c3ptr);
924           n3up = MyConnect(c3ptr) ? cli_name(&me) : cli_name(cli_serv(c3ptr)->up);
925         }
926         else
927         {
928           n3 = host;
929           n3up = IsServer(sptr) ? cli_name(sptr) : cli_name(&me);
930         }
931
932         if (strcmp(n2, n2up) > 0)
933           n2 = n2up;
934         if (strcmp(n3, n3up) > 0)
935           n3 = n3up;
936
937         if (strcmp(n3, n2) > 0)
938         {
939           ac2ptr = c2ptr;
940           c2ptr = c3ptr;
941           c3ptr = ac2ptr;
942         }
943       }
944       /* Now squit the second youngest link: */
945       if (!c2ptr)
946         return exit_new_server(cptr, sptr, host, timestamp,
947             "server %s already exists and is %ld seconds younger.",
948             host, (long)cli_serv(acptr)->timestamp - (long)timestamp);
949       else if (cli_from(c2ptr) == cptr || IsServer(sptr))
950       {
951         struct Client *killedptrfrom = cli_from(c2ptr);
952         if (active_lh_line)
953         {
954           /*
955            * If the L: or H: line also gets rid of this link,
956            * we sent just one squit.
957            */
958           if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
959             break;
960           /*
961            * If breaking the loop here solves the L: or H:
962            * line problem, we don't squit that.
963            */
964           if (cli_from(c2ptr) == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
965             active_lh_line = 0;
966           else
967           {
968             /*
969              * If we still have a L: or H: line problem,
970              * we prefer to squit the new server, solving
971              * loop and L:/H: line problem with only one squit.
972              */
973             LHcptr = 0;
974             break;
975           }
976         }
977         /*
978          * If the new server was introduced by a server that caused a
979          * Ghost less then 20 seconds ago, this is probably also
980          * a Ghost... (20 seconds is more then enough because all
981          * SERVER messages are at the beginning of a net.burst). --Run
982          */
983         if (CurrentTime - cli_serv(cptr)->ghost < 20)
984         {
985           killedptrfrom = cli_from(acptr);
986           if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
987             return CPTR_KILLED;
988         }
989         else if (exit_client_msg(cptr, c2ptr, &me,
990             "Loop <-- %s (new link is %ld seconds younger)", host,
991             (c3ptr ? (long)cli_serv(c3ptr)->timestamp : timestamp) -
992             (long)cli_serv(c2ptr)->timestamp) == CPTR_KILLED)
993           return CPTR_KILLED;
994         /*
995          * Did we kill the incoming server off already ?
996          */
997         if (killedptrfrom == cptr)
998           return 0;
999       }
1000       else
1001       {
1002         if (active_lh_line)
1003         {
1004           if (LHcptr && a_kills_b_too(LHcptr, acptr))
1005             break;
1006           if (cli_from(acptr) == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
1007             active_lh_line = 0;
1008           else
1009           {
1010             LHcptr = 0;
1011             break;
1012           }
1013         }
1014         /*
1015          * We can't believe it is a lagged server message
1016          * when it directly connects to us...
1017          * kill the older link at the ghost, rather then
1018          * at the second youngest link, assuming it isn't
1019          * a REAL loop.
1020          */
1021         ghost = CurrentTime;            /* Mark that it caused a ghost */
1022         if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
1023           return CPTR_KILLED;
1024         break;
1025       }
1026     }
1027   }
1028
1029   if (active_lh_line)
1030   {
1031     if (LHcptr == 0) {
1032       return exit_new_server(cptr, sptr, host, timestamp,
1033           (active_lh_line == 2) ?  "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1034           cli_name(cptr), host,
1035           lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
1036     }
1037     else
1038     {
1039       int killed = a_kills_b_too(LHcptr, sptr);
1040       if (active_lh_line < 3)
1041       {
1042         if (exit_client_msg(cptr, LHcptr, &me,
1043             (active_lh_line == 2) ?  "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1044             cli_name(cptr), host,
1045             lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
1046           return CPTR_KILLED;
1047       }
1048       else
1049       {
1050         ServerStats->is_ref++;
1051         if (exit_client(cptr, LHcptr, &me, "I'm a leaf") == CPTR_KILLED)
1052           return CPTR_KILLED;
1053       }
1054       /*
1055        * Did we kill the incoming server off already ?
1056        */
1057       if (killed)
1058         return 0;
1059     }
1060   }
1061
1062   /*
1063    * Server is informing about a new server behind
1064    * this link. Create REMOTE server structure,
1065    * add it to list and propagate word to my other
1066    * server links...
1067    */
1068
1069   acptr = make_client(cptr, STAT_SERVER);
1070   make_server(acptr);
1071   cli_serv(acptr)->prot = prot;
1072   cli_serv(acptr)->timestamp = timestamp;
1073   cli_hopcount(acptr) = hop;
1074   ircd_strncpy(cli_name(acptr), host, HOSTLEN);
1075   ircd_strncpy(cli_info(acptr), info, REALLEN);
1076   cli_serv(acptr)->up = sptr;
1077   cli_serv(acptr)->updown = add_dlink(&(cli_serv(sptr))->down, acptr);
1078   /* Use cptr, because we do protocol 9 -> 10 translation
1079      for numeric nicks ! */
1080   SetServerYXX(cptr, acptr, parv[6]);
1081
1082   Count_newremoteserver(UserStats);
1083   add_client_to_list(acptr);
1084   hAddClient(acptr);
1085 #ifdef HEAD_IN_SAND_MAP
1086   map_update(acptr);
1087 #endif
1088
1089   if (*parv[5] == 'J')
1090   {
1091     SetBurst(acptr);
1092     sendto_opmask_butone(0, SNO_NETWORK, "Net junction: %s %s",
1093            cli_name(sptr), cli_name(acptr));
1094     SetJunction(acptr);
1095   }
1096
1097   /*
1098    * Old sendto_serv_but_one() call removed because we now need to send
1099    * different names to different servers (domain name matching).
1100    */
1101   for (i = 0; i <= HighestFd; i++)
1102   {
1103     if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
1104         bcptr == cptr || IsMe(bcptr))
1105       continue;
1106     if (0 == match(cli_name(&me), cli_name(acptr)))
1107       continue;
1108     sendcmdto_one(sptr, CMD_SERVER, bcptr, "%s %d 0 %s %s %s%s +%s%s :%s",
1109                   cli_name(acptr), hop + 1, parv[4], parv[5],
1110                   NumServCap(acptr), IsHub(acptr) ? "h" : "",
1111                   IsService(acptr) ? "s" : "", cli_info(acptr));
1112   }
1113   return 0;
1114
1115 }