Author: Kev <klmitch@mit.edu>
[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 #if 0
85 /*
86  * No need to include handlers.h here the signatures must match
87  * and we don't need to force a rebuild of all the handlers everytime
88  * we add a new one to the list. --Bleep
89  */
90 #include "handlers.h"
91 #endif /* 0 */
92 #include "client.h"
93 #include "hash.h"
94 #include "ircd.h"
95 #include "ircd_log.h"
96 #include "ircd_features.h"
97 #include "ircd_reply.h"
98 #include "ircd_string.h"
99 #include "jupe.h"
100 #include "list.h"
101 #include "match.h"
102 #include "msg.h"
103 #include "numeric.h"
104 #include "numnicks.h"
105 #include "querycmds.h"
106 #include "s_bsd.h"
107 #include "s_conf.h"
108 #include "s_debug.h"
109 #include "s_misc.h"
110 #include "s_serv.h"
111 #include "send.h"
112 #include "userload.h"
113
114 #include <assert.h>
115 #include <stdlib.h>
116 #include <string.h>
117
118 /*
119  * mr_server - registration message handler
120  *
121  *    parv[0] = sender prefix
122  *    parv[1] = servername
123  *    parv[2] = hopcount
124  *    parv[3] = start timestamp
125  *    parv[4] = link timestamp
126  *    parv[5] = major protocol version: P09/P10
127  *    parv[parc-1] = serverinfo
128  *  If cptr is P10:
129  *    parv[6] = "YMM", where 'Y' is the server numeric and "MM" is the
130  *              numeric nick mask of this server.
131  *    parv[7] = 0 (not used yet, mandatory unsigned int after u2.10.06)
132  */
133 int mr_server(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
134 {
135   char*            ch;
136   int              i;
137   char             info[REALLEN + 1];
138   char*            host;
139   struct Client*   acptr;
140   struct Client*   bcptr;
141   struct Client*   LHcptr = 0;
142   struct ConfItem* aconf = 0;
143   struct ConfItem* lhconf = 0;
144   struct Jupe*     ajupe = 0;
145   int              hop;
146   int              ret;
147   int              active_lh_line = 0;
148   unsigned short   prot;
149   time_t           start_timestamp;
150   time_t           timestamp = 0;
151   time_t           recv_time;
152   time_t           ghost = 0;
153
154   if (IsUserPort(cptr))
155     return exit_client_msg(cptr, cptr, &me, 
156                            "Cannot connect a server to a user port");
157
158   recv_time = TStime();
159   info[0] = '\0';
160
161   if (parc < 7)
162   {
163     need_more_params(sptr, "SERVER");
164     return exit_client(cptr, cptr, &me, "Need more parameters");
165   }
166   host = parv[1];
167
168   if ((ajupe = jupe_find(host)) && JupeIsActive(ajupe))
169     return exit_client_msg(cptr, sptr, &me, "Juped: %s", JupeReason(ajupe));
170
171   log_write(LS_NETWORK, L_NOTICE, LOG_NOSNOTICE, "SERVER: %s %s[%s]", parv[1],
172             cli_sockhost(cptr), cli_sock_ip(cptr));
173
174   /*
175    * Detect protocol
176    */
177   if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
178     return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
179
180   if (!IsServer(cptr))          /* Don't allow silently connecting a server */
181     *parv[5] = 'J';
182
183   prot = atoi(parv[5] + 1);
184   if (prot > atoi(MAJOR_PROTOCOL))
185     prot = atoi(MAJOR_PROTOCOL);
186   /*
187    * Because the previous test is only in 2.10, the following is needed
188    * till all servers are 2.10:
189    */
190   if (IsServer(cptr) && prot > Protocol(cptr))
191     prot = Protocol(cptr);
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 (IsServer(cptr))
233   {
234     /*
235      * A local server introduces a new server behind this link.
236      * Check if this is allowed according L:, H: and Q: lines.
237      */
238     if (info[0] == '\0')
239       return exit_client_msg(cptr, cptr, &me,
240                              "No server info specified for %s", host);
241     /*
242      * See if the newly found server is behind a guaranteed
243      * leaf (L-line). If so, close the link.
244      */
245     if ((lhconf = find_conf_byhost(cli_confs(cptr), cli_name(cptr), CONF_LEAF)) &&
246         (!lhconf->port || (hop > lhconf->port)))
247     {
248       /*
249        * L: lines normally come in pairs, here we try to
250        * make sure that the oldest link is squitted, not
251        * both.
252        */
253       active_lh_line = 1;
254       if (timestamp <= cli_serv(cptr)->timestamp)
255         LHcptr = 0;          /* Kill incoming server */
256       else
257         LHcptr = cptr;          /* Squit ourselfs */
258     }
259     else if (!(lhconf = find_conf_byname(cli_confs(cptr), cli_name(cptr), CONF_HUB)) ||
260              (lhconf->port && (hop > lhconf->port)))
261     {
262       struct Client *ac3ptr;
263       active_lh_line = 2;
264       /* Look for net junction causing this: */
265       LHcptr = 0;            /* incoming server */
266       if (*parv[5] != 'J') {
267         for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up) {
268           if (IsJunction(ac3ptr)) {
269             LHcptr = ac3ptr;
270             break;
271           }
272         }
273       }
274     }
275   }
276
277   if (IsUnknown(cptr) || IsHandshake(cptr))
278   {
279     const char* encr;
280
281     /*
282      * A local link that is still in undefined state wants
283      * to be a SERVER. Check if this is allowed and change
284      * status accordingly...
285      */
286     /*
287      * If there is more then one server on the same machine
288      * that we try to connect to, it could be that the /CONNECT
289      * <mask> caused this connect to be put at the wrong place
290      * in the hashtable.        --Run
291      * Same thing for Unknown connections that first send NICK.
292      *                          --Xorath
293      * Better check if the two strings are (caseless) identical 
294      * and not mess with hash internals. 
295      *                          --Nemesi
296      */
297     if (!EmptyString(cli_name(cptr)) && 
298         (IsUnknown(cptr) || IsHandshake(cptr)) &&
299         0 != ircd_strcmp(cli_name(cptr), host))
300       hChangeClient(cptr, host);
301     ircd_strncpy(cli_name(cptr), host, HOSTLEN);
302     ircd_strncpy(cli_info(cptr), info[0] ? info : cli_name(&me), REALLEN);
303     cli_hopcount(cptr) = hop;
304
305     /* check connection rules */
306     if (0 != conf_eval_crule(host, CRULE_ALL)) {
307       ServerStats->is_ref++;
308       sendto_opmask_butone(0, SNO_OLDSNO, "Refused connection from %s.", cli_name(cptr));
309       return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
310     }
311
312     if (conf_check_server(cptr)) {
313       ++ServerStats->is_ref;
314       sendto_opmask_butone(0, SNO_OLDSNO, "Received unauthorized connection "
315                            "from %s.", cli_name(cptr));
316       return exit_client(cptr, cptr, &me, "No C:line");
317     }
318
319     host = cli_name(cptr);
320
321     update_load();
322
323     if (!(aconf = find_conf_byname(cli_confs(cptr), host, CONF_SERVER))) {
324       ++ServerStats->is_ref;
325       sendto_opmask_butone(0, SNO_OLDSNO, "Access denied. No conf line for "
326                            "server %s", cli_name(cptr));
327       return exit_client_msg(cptr, cptr, &me,
328           "Access denied. No conf line for server %s", cli_name(cptr));
329     }
330     encr = cli_passwd(cptr);
331
332     if (*aconf->passwd && !!strcmp(aconf->passwd, encr)) {
333       ++ServerStats->is_ref;
334       sendto_opmask_butone(0, SNO_OLDSNO, "Access denied (passwd mismatch) %s",
335                            cli_name(cptr));
336       return exit_client_msg(cptr, cptr, &me,
337           "No Access (passwd mismatch) %s", cli_name(cptr));
338     }
339
340     memset(cli_passwd(cptr), 0, sizeof(cli_passwd(cptr)));
341
342     if (!feature_bool(FEAT_HUB)) {
343       for (i = 0; i <= HighestFd; i++)
344         if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
345           active_lh_line = 3;
346           LHcptr = 0;
347           break;
348         }
349     }
350   }
351
352   /*
353    *  We want to find IsConnecting() and IsHandshake() too,
354    *  use FindClient().
355    *  The second finds collisions with numeric representation of existing
356    *  servers - these shouldn't happen anymore when all upgraded to 2.10.
357    *  -- Run
358    */
359   while ((acptr = FindClient(host)) || 
360          (parc > 7 && (acptr = FindNServer(parv[6]))))
361   {
362     /*
363      *  This link is trying feed me a server that I already have
364      *  access through another path
365      *
366      *  Do not allow Uworld to do this.
367      *  Do not allow servers that are juped.
368      *  Do not allow servers that have older link timestamps
369      *    then this try.
370      *  Do not allow servers that use the same numeric as an existing
371      *    server, but have a different name.
372      *
373      *  If my ircd.conf sucks, I can try to connect to myself:
374      */
375     if (acptr == &me)
376       return exit_client_msg(cptr, cptr, &me, "nick collision with me (%s), check server number in M:?", host);
377     /*
378      * Detect wrong numeric.
379      */
380     if (0 != ircd_strcmp(cli_name(acptr), host)) {
381       sendcmdto_serv_butone(&me, CMD_WALLOPS, cptr,
382                             ":SERVER Numeric Collision: %s != %s",
383                             cli_name(acptr), host);
384       return exit_client_msg(cptr, cptr, &me,
385           "NUMERIC collision between %s and %s."
386           " Is your server numeric correct ?", host, cli_name(acptr));
387     }
388     /*
389      *  Kill our try, if we had one.
390      */
391     if (IsConnecting(acptr))
392     {
393       if (!active_lh_line && exit_client(cptr, acptr, &me,
394           "Just connected via another link") == CPTR_KILLED)
395         return CPTR_KILLED;
396       /*
397        * We can have only ONE 'IsConnecting', 'IsHandshake' or
398        * 'IsServer', because new 'IsConnecting's are refused to
399        * the same server if we already had it.
400        */
401       break;
402     }
403     /*
404      * Avoid other nick collisions...
405      * This is a doubtfull test though, what else would it be
406      * when it has a server.name ?
407      */
408     else if (!IsServer(acptr) && !IsHandshake(acptr))
409       return exit_client_msg(cptr, cptr, &me,
410                              "Nickname %s already exists!", host);
411     /*
412      * Our new server might be a juped server,
413      * or someone trying abuse a second Uworld:
414      */
415     else if (IsServer(acptr) && (0 == ircd_strncmp(cli_info(acptr), "JUPE", 4) ||
416         find_conf_byhost(cli_confs(cptr), cli_name(acptr), CONF_UWORLD)))
417     {
418       if (!IsServer(sptr))
419         return exit_client(cptr, sptr, &me, cli_info(acptr));
420       sendcmdto_serv_butone(&me, CMD_WALLOPS, cptr,
421                             ":Received :%s SERVER %s from %s !?!", parv[0],
422                             parv[1], cli_name(cptr));
423       return exit_new_server(cptr, sptr, host, timestamp, "%s", cli_info(acptr));
424     }
425     /*
426      * Of course we find the handshake this link was before :)
427      */
428     else if (IsHandshake(acptr) && acptr == cptr)
429       break;
430     /*
431      * Here we have a server nick collision...
432      * We don't want to kill the link that was last /connected,
433      * but we neither want to kill a good (old) link.
434      * Therefor we kill the second youngest link.
435      */
436     if (1)
437     {
438       struct Client* c2ptr = 0;
439       struct Client* c3ptr = acptr;
440       struct Client* ac2ptr;
441       struct Client* ac3ptr;
442
443       /* Search youngest link: */
444       for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up)
445         if (cli_serv(ac3ptr)->timestamp > cli_serv(c3ptr)->timestamp)
446           c3ptr = ac3ptr;
447       if (IsServer(sptr))
448       {
449         for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up)
450           if (cli_serv(ac3ptr)->timestamp > cli_serv(c3ptr)->timestamp)
451             c3ptr = ac3ptr;
452       }
453       if (timestamp > cli_serv(c3ptr)->timestamp)
454       {
455         c3ptr = 0;
456         c2ptr = acptr;          /* Make sure they differ */
457       }
458       /* Search second youngest link: */
459       for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = cli_serv(ac2ptr)->up)
460         if (ac2ptr != c3ptr &&
461             cli_serv(ac2ptr)->timestamp >
462             (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
463           c2ptr = ac2ptr;
464       if (IsServer(sptr))
465       {
466         for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = cli_serv(ac2ptr)->up)
467           if (ac2ptr != c3ptr &&
468               cli_serv(ac2ptr)->timestamp >
469               (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
470             c2ptr = ac2ptr;
471       }
472       if (c3ptr && timestamp > (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
473         c2ptr = 0;
474       /* If timestamps are equal, decide which link to break
475        *  by name.
476        */
477       if ((c2ptr ? cli_serv(c2ptr)->timestamp : timestamp) ==
478           (c3ptr ? cli_serv(c3ptr)->timestamp : timestamp))
479       {
480         char* n2;
481         char* n2up;
482         char* n3;
483         char* n3up;
484         if (c2ptr)
485         {
486           n2 = cli_name(c2ptr);
487           n2up = MyConnect(c2ptr) ? cli_name(&me) : cli_name(cli_serv(c2ptr)->up);
488         }
489         else
490         {
491           n2 = host;
492           n2up = IsServer(sptr) ? cli_name(sptr) : cli_name(&me);
493         }
494         if (c3ptr)
495         {
496           n3 = cli_name(c3ptr);
497           n3up = MyConnect(c3ptr) ? cli_name(&me) : cli_name(cli_serv(c3ptr)->up);
498         }
499         else
500         {
501           n3 = host;
502           n3up = IsServer(sptr) ? cli_name(sptr) : cli_name(&me);
503         }
504         if (strcmp(n2, n2up) > 0)
505           n2 = n2up;
506         if (strcmp(n3, n3up) > 0)
507           n3 = n3up;
508         if (strcmp(n3, n2) > 0)
509         {
510           ac2ptr = c2ptr;
511           c2ptr = c3ptr;
512           c3ptr = ac2ptr;
513         }
514       }
515       /* Now squit the second youngest link: */
516       if (!c2ptr)
517         return exit_new_server(cptr, sptr, host, timestamp,
518                                "server %s already exists and is %ld seconds younger.",
519                                host, (long)cli_serv(acptr)->timestamp - (long)timestamp);
520       else if (cli_from(c2ptr) == cptr || IsServer(sptr))
521       {
522         struct Client *killedptrfrom = cli_from(c2ptr);
523         if (active_lh_line)
524         {
525           /*
526            * If the L: or H: line also gets rid of this link,
527            * we sent just one squit.
528            */
529           if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
530             break;
531           /*
532            * If breaking the loop here solves the L: or H:
533            * line problem, we don't squit that.
534            */
535           if (cli_from(c2ptr) == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
536             active_lh_line = 0;
537           else
538           {
539             /*
540              * If we still have a L: or H: line problem,
541              * we prefer to squit the new server, solving
542              * loop and L:/H: line problem with only one squit.
543              */
544             LHcptr = 0;
545             break;
546           }
547         }
548         /*
549          * If the new server was introduced by a server that caused a
550          * Ghost less then 20 seconds ago, this is probably also
551          * a Ghost... (20 seconds is more then enough because all
552          * SERVER messages are at the beginning of a net.burst). --Run
553          */
554         if (CurrentTime - cli_serv(cptr)->ghost < 20)
555         {
556           killedptrfrom = cli_from(acptr);
557           if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
558             return CPTR_KILLED;
559         }
560         else if (exit_client_msg(cptr, c2ptr, &me,
561             "Loop <-- %s (new link is %ld seconds younger)", host,
562             (c3ptr ? (long)cli_serv(c3ptr)->timestamp : timestamp) -
563             (long)cli_serv(c2ptr)->timestamp) == CPTR_KILLED)
564           return CPTR_KILLED;
565         /*
566          * Did we kill the incoming server off already ?
567          */
568         if (killedptrfrom == cptr)
569           return 0;
570       }
571       else
572       {
573         if (active_lh_line)
574         {
575           if (LHcptr && a_kills_b_too(LHcptr, acptr))
576             break;
577           if (cli_from(acptr) == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
578             active_lh_line = 0;
579           else
580           {
581             LHcptr = 0;
582             break;
583           }
584         }
585         /*
586          * We can't believe it is a lagged server message
587          * when it directly connects to us...
588          * kill the older link at the ghost, rather then
589          * at the second youngest link, assuming it isn't
590          * a REAL loop.
591          */
592         ghost = CurrentTime;            /* Mark that it caused a ghost */
593         if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
594           return CPTR_KILLED;
595         break;
596       }
597     }
598   }
599
600   if (active_lh_line)
601   {
602     if (LHcptr == 0) {
603       return exit_new_server(cptr, sptr, host, timestamp,
604           (active_lh_line == 2) ?  "Non-Hub link %s <- %s(%s), check H:" : 
605                                    "Leaf-only link %s <- %s(%s), check L:",
606           cli_name(cptr), host, 
607           lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
608     }
609     else
610     {
611       int killed = a_kills_b_too(LHcptr, sptr);
612       if (active_lh_line < 3)
613       {
614         if (exit_client_msg(cptr, LHcptr, &me,
615             (active_lh_line == 2) ?  "Non-Hub link %s <- %s(%s), check H:" : 
616                                      "Leaf-only link %s <- %s(%s), check L:",
617             cli_name(cptr), host,
618             lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
619           return CPTR_KILLED;
620       }
621       else
622       {
623         ServerStats->is_ref++;
624         if (exit_client(cptr, LHcptr, &me, "I'm a leaf, define HUB") == CPTR_KILLED)
625           return CPTR_KILLED;
626       }
627       /*
628        * Did we kill the incoming server off already ?
629        */
630       if (killed)
631         return 0;
632     }
633   }
634
635   if (IsServer(cptr))
636   {
637     /*
638      * Server is informing about a new server behind
639      * this link. Create REMOTE server structure,
640      * add it to list and propagate word to my other
641      * server links...
642      */
643
644     acptr = make_client(cptr, STAT_SERVER);
645     make_server(acptr);
646     cli_serv(acptr)->prot = prot;
647     cli_serv(acptr)->timestamp = timestamp;
648     cli_hopcount(acptr) = hop;
649     ircd_strncpy(cli_name(acptr), host, HOSTLEN);
650     ircd_strncpy(cli_info(acptr), info, REALLEN);
651     cli_serv(acptr)->up = sptr;
652     cli_serv(acptr)->updown = add_dlink(&(cli_serv(sptr))->down, acptr);
653     /* Use cptr, because we do protocol 9 -> 10 translation
654        for numeric nicks ! */
655     SetServerYXX(cptr, acptr, parv[6]);
656
657     Count_newremoteserver(UserStats);
658     if (Protocol(acptr) < 10)
659       cli_flags(acptr) |= FLAGS_TS8;
660     add_client_to_list(acptr);
661     hAddClient(acptr);
662     if (*parv[5] == 'J')
663     {
664       SetBurst(acptr);
665       sendto_opmask_butone(0, SNO_NETWORK, "Net junction: %s %s",
666           cli_name(sptr), cli_name(acptr));
667       SetJunction(acptr);
668     }
669     /*
670      * Old sendto_serv_but_one() call removed because we now need to send
671      * different names to different servers (domain name matching).
672      *
673      * Personally, I think this is bogus; it's a feature we don't use here.
674      * -Kev
675      */
676     for (i = 0; i <= HighestFd; i++)
677     {
678       if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
679           bcptr == cptr || IsMe(bcptr))
680         continue;
681       if (0 == match(cli_name(&me), cli_name(acptr)))
682         continue;
683       sendcmdto_one(sptr, CMD_SERVER, bcptr, "%s %d 0 %s %s %s%s 0 :%s",
684                     cli_name(acptr), hop + 1, parv[4], parv[5], NumServCap(acptr),
685                     cli_info(acptr));
686     }
687     return 0;
688   }
689
690   if (IsUnknown(cptr) || IsHandshake(cptr))
691   {
692     make_server(cptr);
693     cli_serv(cptr)->timestamp = timestamp;
694     cli_serv(cptr)->prot = prot;
695     cli_serv(cptr)->ghost = ghost;
696     SetServerYXX(cptr, cptr, parv[6]);
697     if (start_timestamp > OLDEST_TS)
698     {
699       Debug((DEBUG_DEBUG, "My start time: %Tu; other's start time: %Tu",
700              cli_serv(&me)->timestamp, start_timestamp));
701       Debug((DEBUG_DEBUG, "Receive time: %Tu; received timestamp: %Tu; "
702              "difference %ld", recv_time, timestamp, timestamp - recv_time));
703       if (feature_bool(FEAT_RELIABLE_CLOCK)) {
704         if (start_timestamp < cli_serv(&me)->timestamp)
705           cli_serv(&me)->timestamp = start_timestamp;
706         if (IsUnknown(cptr))
707           cli_serv(cptr)->timestamp = TStime();
708       } else {
709         if (start_timestamp < cli_serv(&me)->timestamp) {
710           sendto_opmask_butone(0, SNO_OLDSNO, "got earlier start time: "
711                                "%Tu < %Tu", start_timestamp,
712                                cli_serv(&me)->timestamp);
713           cli_serv(&me)->timestamp = start_timestamp;
714           TSoffset += timestamp - recv_time;
715           sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
716                                (int)(timestamp - recv_time));
717         } else if ((start_timestamp > cli_serv(&me)->timestamp) &&
718                  IsUnknown(cptr))
719           cli_serv(cptr)->timestamp = TStime();
720
721         else if (timestamp != recv_time) {
722           /*
723            * Equal start times, we have a collision.  Let the connected-to
724            * server decide. This assumes leafs issue more than half of the
725            * connection attempts.
726            */
727           if (IsUnknown(cptr))
728             cli_serv(cptr)->timestamp = TStime();
729           else if (IsHandshake(cptr)) {
730             sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
731                                  (int)(timestamp - recv_time));
732             TSoffset += timestamp - recv_time;
733           }
734         }
735       }
736     }
737
738     ret = server_estab(cptr, aconf);
739   }
740   else
741     ret = 0;
742
743   if (feature_bool(FEAT_RELIABLE_CLOCK) &&
744       abs(cli_serv(cptr)->timestamp - recv_time) > 30) {
745     sendto_opmask_butone(0, SNO_OLDSNO, "Connected to a net with a "
746                          "timestamp-clock difference of %Td seconds! "
747                          "Used SETTIME to correct this.",
748                          timestamp - recv_time);
749     sendcmdto_one(&me, CMD_SETTIME, cptr, "%Tu :%s", TStime(), cli_name(&me));
750   }
751
752   return ret;
753 }
754
755 /*
756  * ms_server - server message handler
757  *
758  *    parv[0] = sender prefix
759  *    parv[1] = servername
760  *    parv[2] = hopcount
761  *    parv[3] = start timestamp
762  *    parv[4] = link timestamp
763  *    parv[5] = major protocol version: P09/P10
764  *    parv[parc-1] = serverinfo
765  *  If cptr is P10:
766  *    parv[6] = "YMM", where 'Y' is the server numeric and "MM" is the
767  *              numeric nick mask of this server.
768  *    parv[7] = 0 (not used yet, mandatory unsigned int after u2.10.06)
769  */
770 int ms_server(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
771 {
772   char*            ch;
773   int              i;
774   char             info[REALLEN + 1];
775   char*            host;
776   struct Client*   acptr;
777   struct Client*   bcptr;
778   struct Client*   LHcptr = 0;
779   struct ConfItem* aconf = 0;
780   struct ConfItem* lhconf = 0;
781   int              hop;
782   int              ret;
783   int              active_lh_line = 0;
784   unsigned short   prot;
785   time_t           start_timestamp;
786   time_t           timestamp = 0;
787   time_t           recv_time;
788   time_t           ghost = 0;
789
790   if (IsUserPort(cptr))
791     return exit_client_msg(cptr, cptr, &me,
792                            "Cannot connect a server to a user port");
793
794   recv_time = TStime();
795   info[0] = '\0';
796   if (parc < 7)
797   {
798     return need_more_params(sptr, "SERVER");
799     return exit_client(cptr, cptr, &me, "Need more parameters");
800   }
801   host = parv[1];
802
803   /*
804    * Detect protocol
805    */
806   if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
807     return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
808
809   if (!IsServer(cptr))          /* Don't allow silently connecting a server */
810     *parv[5] = 'J';
811
812   prot = atoi(parv[5] + 1);
813   if (prot > atoi(MAJOR_PROTOCOL))
814     prot = atoi(MAJOR_PROTOCOL);
815   /*
816    * Because the previous test is only in 2.10, the following is needed
817    * till all servers are 2.10:
818    */
819   if (IsServer(cptr) && prot > Protocol(cptr))
820     prot = Protocol(cptr);
821   hop = atoi(parv[2]);
822   start_timestamp = atoi(parv[3]);
823   timestamp = atoi(parv[4]);
824   Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age %Tu (%Tu)",
825          host, parv[4], start_timestamp, cli_serv(&me)->timestamp));
826   if ((timestamp < OLDEST_TS || (hop == 1 && start_timestamp < OLDEST_TS)))
827   {
828     return exit_client_msg(cptr, sptr, &me,
829         "Bogus timestamps (%s %s)", parv[3], parv[4]);
830   }
831   ircd_strncpy(info, parv[parc - 1], REALLEN);
832   info[REALLEN] = '\0';
833   if (prot < atoi(MINOR_PROTOCOL)) {
834     sendto_opmask_butone(0, SNO_OLDSNO, "Got incompatible protocol version "
835                          "(%s) from %s", parv[5], cli_name(cptr));
836     return exit_new_server(cptr, sptr, host, timestamp,
837                            "Incompatible protocol: %s", parv[5]);
838   }
839   /*
840    * Check for "FRENCH " infection ;-) (actually this should
841    * be replaced with routine to check the hostname syntax in
842    * general). [ This check is still needed, even after the parse
843    * is fixed, because someone can send "SERVER :foo bar " ].
844    * Also, changed to check other "difficult" characters, now
845    * that parse lets all through... --msa
846    */
847   if (strlen(host) > HOSTLEN)
848     host[HOSTLEN] = '\0';
849   for (ch = host; *ch; ch++)
850     if (*ch <= ' ' || *ch > '~')
851       break;
852   if (*ch || !strchr(host, '.')) {
853     sendto_opmask_butone(0, SNO_OLDSNO, "Bogus server name (%s) from %s",
854                          host, cli_name(cptr));
855     return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
856   }
857
858   if (IsServer(cptr))
859   {
860     /*
861      * A local server introduces a new server behind this link.
862      * Check if this is allowed according L:, H: and Q: lines.
863      */
864     if (info[0] == '\0')
865       return exit_client_msg(cptr, cptr, &me,
866           "No server info specified for %s", host);
867     /*
868      * See if the newly found server is behind a guaranteed
869      * leaf (L-line). If so, close the link.
870      */
871     if ((lhconf = find_conf_byhost(cli_confs(cptr), cli_name(cptr), CONF_LEAF)) &&
872         (!lhconf->port || (hop > lhconf->port)))
873     {
874       /*
875        * L: lines normally come in pairs, here we try to
876        * make sure that the oldest link is squitted, not
877        * both.
878        */
879       active_lh_line = 1;
880       if (timestamp <= cli_serv(cptr)->timestamp)
881         LHcptr = 0;          /* Kill incoming server */
882       else
883         LHcptr = cptr;          /* Squit ourselfs */
884     }
885     else if (!(lhconf = find_conf_byname(cli_confs(cptr), cli_name(cptr), CONF_HUB)) ||
886              (lhconf->port && (hop > lhconf->port)))
887     {
888       struct Client *ac3ptr;
889       active_lh_line = 2;
890       /* Look for net junction causing this: */
891       LHcptr = 0;            /* incoming server */
892       if (*parv[5] != 'J') {
893         for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up) {
894           if (IsJunction(ac3ptr)) {
895             LHcptr = ac3ptr;
896             break;
897           }
898         }
899       }
900     }
901   }
902
903   if (IsUnknown(cptr) || IsHandshake(cptr))
904   {
905     const char* encr;
906
907     /*
908      * A local link that is still in undefined state wants
909      * to be a SERVER. Check if this is allowed and change
910      * status accordingly...
911      */
912     /*
913      * If there is more then one server on the same machine
914      * that we try to connect to, it could be that the /CONNECT
915      * <mask> caused this connect to be put at the wrong place
916      * in the hashtable.        --Run
917      * Same thing for Unknown connections that first send NICK.
918      *                          --Xorath
919      * Better check if the two strings are (caseless) identical 
920      * and not mess with hash internals. 
921      *                          --Nemesi
922      */
923     if ((!(EmptyString(cli_name(cptr))))
924         && (IsUnknown(cptr) || IsHandshake(cptr))
925         && 0 != ircd_strcmp(cli_name(cptr), host))
926       hChangeClient(cptr, host);
927     ircd_strncpy(cli_name(cptr), host, HOSTLEN);
928     ircd_strncpy(cli_info(cptr), info[0] ? info : cli_name(&me), REALLEN);
929     cli_hopcount(cptr) = hop;
930
931     /* check connection rules */
932     if (0 != conf_eval_crule(host, CRULE_ALL)) {
933       ServerStats->is_ref++;
934       sendto_opmask_butone(0, SNO_OLDSNO, "Refused connection from %s.", cli_name(cptr));
935       return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
936     }
937     if (conf_check_server(cptr)) {
938       ++ServerStats->is_ref;
939       sendto_opmask_butone(0, SNO_OLDSNO, "Received unauthorized connection "
940                            "from %s.", cli_name(cptr));
941       return exit_client(cptr, cptr, &me, "No C conf lines");
942     }
943
944     host = cli_name(cptr);
945
946     update_load();
947
948     if (!(aconf = find_conf_byname(cli_confs(cptr), host, CONF_SERVER))) {
949       ++ServerStats->is_ref;
950       sendto_opmask_butone(0, SNO_OLDSNO, "Access denied. No conf line for "
951                            "server %s", cli_name(cptr));
952       return exit_client_msg(cptr, cptr, &me,
953                              "Access denied. No conf line for server %s", cli_name(cptr));
954     }
955     encr = cli_passwd(cptr);
956
957     if (*(aconf->passwd) && !!strcmp(aconf->passwd, encr)) {
958       ++ServerStats->is_ref;
959       sendto_opmask_butone(0, SNO_OLDSNO, "Access denied (passwd mismatch) %s",
960                            cli_name(cptr));
961       return exit_client_msg(cptr, cptr, &me,
962                              "No Access (passwd mismatch) %s", cli_name(cptr));
963     }
964     memset(cli_passwd(cptr), 0, sizeof(cli_passwd(cptr)));
965
966     if (!feature_bool(FEAT_HUB)) {
967       for (i = 0; i <= HighestFd; i++)
968         if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
969           active_lh_line = 3;
970           LHcptr = 0;
971           break;
972         }
973     }
974   }
975
976   /*
977    *  We want to find IsConnecting() and IsHandshake() too,
978    *  use FindClient().
979    *  The second finds collisions with numeric representation of existing
980    *  servers - these shouldn't happen anymore when all upgraded to 2.10.
981    *  -- Run
982    */
983   while ((acptr = FindClient(host)) || 
984          (parc > 7 && (acptr = FindNServer(parv[6]))))
985   {
986     /*
987      *  This link is trying feed me a server that I already have
988      *  access through another path
989      *
990      *  Do not allow Uworld to do this.
991      *  Do not allow servers that are juped.
992      *  Do not allow servers that have older link timestamps
993      *    then this try.
994      *  Do not allow servers that use the same numeric as an existing
995      *    server, but have a different name.
996      *
997      *  If my ircd.conf sucks, I can try to connect to myself:
998      */
999     if (acptr == &me)
1000       return exit_client_msg(cptr, cptr, &me,
1001           "nick collision with me, check server number in M:? (%s)", host);
1002     /*
1003      * Detect wrong numeric.
1004      */
1005     if (0 != ircd_strcmp(cli_name(acptr), host))
1006     {
1007       sendcmdto_serv_butone(&me, CMD_WALLOPS, cptr,
1008                             ":SERVER Numeric Collision: %s != %s", cli_name(acptr),
1009                             host);
1010       return exit_client_msg(cptr, cptr, &me,
1011           "NUMERIC collision between %s and %s."
1012           " Is your server numeric correct ?", host, cli_name(acptr));
1013     }
1014     /*
1015      *  Kill our try, if we had one.
1016      */
1017     if (IsConnecting(acptr))
1018     {
1019       if (!active_lh_line && exit_client(cptr, acptr, &me,
1020           "Just connected via another link") == CPTR_KILLED)
1021         return CPTR_KILLED;
1022       /*
1023        * We can have only ONE 'IsConnecting', 'IsHandshake' or
1024        * 'IsServer', because new 'IsConnecting's are refused to
1025        * the same server if we already had it.
1026        */
1027       break;
1028     }
1029     /*
1030      * Avoid other nick collisions...
1031      * This is a doubtfull test though, what else would it be
1032      * when it has a server.name ?
1033      */
1034     else if (!IsServer(acptr) && !IsHandshake(acptr))
1035       return exit_client_msg(cptr, cptr, &me,
1036           "Nickname %s already exists!", host);
1037     /*
1038      * Our new server might be a juped server,
1039      * or someone trying abuse a second Uworld:
1040      */
1041     else if (IsServer(acptr) && (0 == ircd_strncmp(cli_info(acptr), "JUPE", 4) ||
1042         find_conf_byhost(cli_confs(cptr), cli_name(acptr), CONF_UWORLD)))
1043     {
1044       if (!IsServer(sptr))
1045         return exit_client(cptr, sptr, &me, cli_info(acptr));
1046       sendcmdto_one(&me, CMD_WALLOPS, cptr, ":Received :%s SERVER %s "
1047                     "from %s !?!", parv[0], parv[1], cli_name(cptr));
1048       return exit_new_server(cptr, sptr, host, timestamp, "%s", cli_info(acptr));
1049     }
1050     /*
1051      * Of course we find the handshake this link was before :)
1052      */
1053     else if (IsHandshake(acptr) && acptr == cptr)
1054       break;
1055     /*
1056      * Here we have a server nick collision...
1057      * We don't want to kill the link that was last /connected,
1058      * but we neither want to kill a good (old) link.
1059      * Therefor we kill the second youngest link.
1060      */
1061     if (1)
1062     {
1063       struct Client* c2ptr = 0;
1064       struct Client* c3ptr = acptr;
1065       struct Client* ac2ptr;
1066       struct Client* ac3ptr;
1067
1068       /* Search youngest link: */
1069       for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up)
1070         if (cli_serv(ac3ptr)->timestamp > cli_serv(c3ptr)->timestamp)
1071           c3ptr = ac3ptr;
1072       if (IsServer(sptr))
1073       {
1074         for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up)
1075           if (cli_serv(ac3ptr)->timestamp > cli_serv(c3ptr)->timestamp)
1076             c3ptr = ac3ptr;
1077       }
1078       if (timestamp > cli_serv(c3ptr)->timestamp)
1079       {
1080         c3ptr = 0;
1081         c2ptr = acptr;          /* Make sure they differ */
1082       }
1083       /* Search second youngest link: */
1084       for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = cli_serv(ac2ptr)->up)
1085         if (ac2ptr != c3ptr &&
1086             cli_serv(ac2ptr)->timestamp >
1087             (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
1088           c2ptr = ac2ptr;
1089       if (IsServer(sptr))
1090       {
1091         for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = cli_serv(ac2ptr)->up)
1092           if (ac2ptr != c3ptr &&
1093               cli_serv(ac2ptr)->timestamp >
1094               (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
1095             c2ptr = ac2ptr;
1096       }
1097       if (c3ptr && timestamp > (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
1098         c2ptr = 0;
1099       /* If timestamps are equal, decide which link to break
1100        *  by name.
1101        */
1102       if ((c2ptr ? cli_serv(c2ptr)->timestamp : timestamp) ==
1103           (c3ptr ? cli_serv(c3ptr)->timestamp : timestamp))
1104       {
1105         char* n2;
1106         char* n2up;
1107         char* n3;
1108         char* n3up;
1109         if (c2ptr)
1110         {
1111           n2 = cli_name(c2ptr);
1112           n2up = MyConnect(c2ptr) ? cli_name(&me) : cli_name(cli_serv(c2ptr)->up);
1113         }
1114         else
1115         {
1116           n2 = host;
1117           n2up = IsServer(sptr) ? cli_name(sptr) : cli_name(&me);
1118         }
1119         if (c3ptr)
1120         {
1121           n3 = cli_name(c3ptr);
1122           n3up = MyConnect(c3ptr) ? cli_name(&me) : cli_name(cli_serv(c3ptr)->up);
1123         }
1124         else
1125         {
1126           n3 = host;
1127           n3up = IsServer(sptr) ? cli_name(sptr) : cli_name(&me);
1128         }
1129         if (strcmp(n2, n2up) > 0)
1130           n2 = n2up;
1131         if (strcmp(n3, n3up) > 0)
1132           n3 = n3up;
1133         if (strcmp(n3, n2) > 0)
1134         {
1135           ac2ptr = c2ptr;
1136           c2ptr = c3ptr;
1137           c3ptr = ac2ptr;
1138         }
1139       }
1140       /* Now squit the second youngest link: */
1141       if (!c2ptr)
1142         return exit_new_server(cptr, sptr, host, timestamp,
1143             "server %s already exists and is %ld seconds younger.",
1144             host, (long)cli_serv(acptr)->timestamp - (long)timestamp);
1145       else if (cli_from(c2ptr) == cptr || IsServer(sptr))
1146       {
1147         struct Client *killedptrfrom = cli_from(c2ptr);
1148         if (active_lh_line)
1149         {
1150           /*
1151            * If the L: or H: line also gets rid of this link,
1152            * we sent just one squit.
1153            */
1154           if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
1155             break;
1156           /*
1157            * If breaking the loop here solves the L: or H:
1158            * line problem, we don't squit that.
1159            */
1160           if (cli_from(c2ptr) == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
1161             active_lh_line = 0;
1162           else
1163           {
1164             /*
1165              * If we still have a L: or H: line problem,
1166              * we prefer to squit the new server, solving
1167              * loop and L:/H: line problem with only one squit.
1168              */
1169             LHcptr = 0;
1170             break;
1171           }
1172         }
1173         /*
1174          * If the new server was introduced by a server that caused a
1175          * Ghost less then 20 seconds ago, this is probably also
1176          * a Ghost... (20 seconds is more then enough because all
1177          * SERVER messages are at the beginning of a net.burst). --Run
1178          */
1179         if (CurrentTime - cli_serv(cptr)->ghost < 20)
1180         {
1181           killedptrfrom = cli_from(acptr);
1182           if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
1183             return CPTR_KILLED;
1184         }
1185         else if (exit_client_msg(cptr, c2ptr, &me,
1186             "Loop <-- %s (new link is %ld seconds younger)", host,
1187             (c3ptr ? (long)cli_serv(c3ptr)->timestamp : timestamp) -
1188             (long)cli_serv(c2ptr)->timestamp) == CPTR_KILLED)
1189           return CPTR_KILLED;
1190         /*
1191          * Did we kill the incoming server off already ?
1192          */
1193         if (killedptrfrom == cptr)
1194           return 0;
1195       }
1196       else
1197       {
1198         if (active_lh_line)
1199         {
1200           if (LHcptr && a_kills_b_too(LHcptr, acptr))
1201             break;
1202           if (cli_from(acptr) == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
1203             active_lh_line = 0;
1204           else
1205           {
1206             LHcptr = 0;
1207             break;
1208           }
1209         }
1210         /*
1211          * We can't believe it is a lagged server message
1212          * when it directly connects to us...
1213          * kill the older link at the ghost, rather then
1214          * at the second youngest link, assuming it isn't
1215          * a REAL loop.
1216          */
1217         ghost = CurrentTime;            /* Mark that it caused a ghost */
1218         if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
1219           return CPTR_KILLED;
1220         break;
1221       }
1222     }
1223   }
1224
1225   if (active_lh_line)
1226   {
1227     if (LHcptr == 0) {
1228       return exit_new_server(cptr, sptr, host, timestamp,
1229           (active_lh_line == 2) ?  "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1230           cli_name(cptr), host,
1231           lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
1232     }
1233     else
1234     {
1235       int killed = a_kills_b_too(LHcptr, sptr);
1236       if (active_lh_line < 3)
1237       {
1238         if (exit_client_msg(cptr, LHcptr, &me,
1239             (active_lh_line == 2) ?  "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1240             cli_name(cptr), host,
1241             lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
1242           return CPTR_KILLED;
1243       }
1244       else
1245       {
1246         ServerStats->is_ref++;
1247         if (exit_client(cptr, LHcptr, &me, "I'm a leaf") == CPTR_KILLED)
1248           return CPTR_KILLED;
1249       }
1250       /*
1251        * Did we kill the incoming server off already ?
1252        */
1253       if (killed)
1254         return 0;
1255     }
1256   }
1257
1258   if (IsServer(cptr))
1259   {
1260     /*
1261      * Server is informing about a new server behind
1262      * this link. Create REMOTE server structure,
1263      * add it to list and propagate word to my other
1264      * server links...
1265      */
1266
1267     acptr = make_client(cptr, STAT_SERVER);
1268     make_server(acptr);
1269     cli_serv(acptr)->prot = prot;
1270     cli_serv(acptr)->timestamp = timestamp;
1271     cli_hopcount(acptr) = hop;
1272     ircd_strncpy(cli_name(acptr), host, HOSTLEN);
1273     ircd_strncpy(cli_info(acptr), info, REALLEN);
1274     cli_serv(acptr)->up = sptr;
1275     cli_serv(acptr)->updown = add_dlink(&(cli_serv(sptr))->down, acptr);
1276     /* Use cptr, because we do protocol 9 -> 10 translation
1277        for numeric nicks ! */
1278     SetServerYXX(cptr, acptr, parv[6]);
1279
1280     Count_newremoteserver(UserStats);
1281     if (Protocol(acptr) < 10)
1282       cli_flags(acptr) |= FLAGS_TS8;
1283     add_client_to_list(acptr);
1284     hAddClient(acptr);
1285     if (*parv[5] == 'J')
1286     {
1287       SetBurst(acptr);
1288       sendto_opmask_butone(0, SNO_NETWORK, "Net junction: %s %s",
1289                            cli_name(sptr), cli_name(acptr));
1290       SetJunction(acptr);
1291     }
1292     /*
1293      * Old sendto_serv_but_one() call removed because we now need to send
1294      * different names to different servers (domain name matching).
1295      */
1296     for (i = 0; i <= HighestFd; i++)
1297     {
1298       if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
1299           bcptr == cptr || IsMe(bcptr))
1300         continue;
1301       if (0 == match(cli_name(&me), cli_name(acptr)))
1302         continue;
1303       sendcmdto_one(sptr, CMD_SERVER, bcptr, "%s %d 0 %s %s %s%s 0 :%s",
1304                     cli_name(acptr), hop + 1, parv[4], parv[5], NumServCap(acptr),
1305                     cli_info(acptr));
1306     }
1307     return 0;
1308   }
1309
1310   if (IsUnknown(cptr) || IsHandshake(cptr))
1311   {
1312     make_server(cptr);
1313     cli_serv(cptr)->timestamp = timestamp;
1314     cli_serv(cptr)->prot = prot;
1315     cli_serv(cptr)->ghost = ghost;
1316     SetServerYXX(cptr, cptr, parv[6]);
1317     if (start_timestamp > OLDEST_TS)
1318     {
1319       Debug((DEBUG_DEBUG, "My start time: %Tu; other's start time: %Tu",
1320              cli_serv(&me)->timestamp, start_timestamp));
1321       Debug((DEBUG_DEBUG, "Receive time: %Tu; received timestamp: %Tu; "
1322              "difference %ld", recv_time, timestamp, timestamp - recv_time));
1323       if (feature_bool(FEAT_RELIABLE_CLOCK)) {
1324         if (start_timestamp < cli_serv(&me)->timestamp)
1325           cli_serv(&me)->timestamp = start_timestamp;
1326         if (IsUnknown(cptr))
1327           cli_serv(cptr)->timestamp = TStime();
1328       } else {
1329         if (start_timestamp < cli_serv(&me)->timestamp) {
1330           sendto_opmask_butone(0, SNO_OLDSNO, "got earlier start time: "
1331                                "%Tu < %Tu", start_timestamp,
1332                                cli_serv(&me)->timestamp);
1333           cli_serv(&me)->timestamp = start_timestamp;
1334           TSoffset += timestamp - recv_time;
1335           sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
1336                                (int)(timestamp - recv_time));
1337         } else if ((start_timestamp > cli_serv(&me)->timestamp) &&
1338                    IsUnknown(cptr))
1339           cli_serv(cptr)->timestamp = TStime();
1340
1341         else if (timestamp != recv_time) {
1342           /*
1343            * Equal start times, we have a collision.  Let the connected-to
1344            * server decide. This assumes leafs issue more than half of the
1345            * connection attempts.
1346            */
1347           if (IsUnknown(cptr))
1348             cli_serv(cptr)->timestamp = TStime();
1349           else if (IsHandshake(cptr)) {
1350             sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
1351                                  (int)(timestamp - recv_time));
1352             TSoffset += timestamp - recv_time;
1353           }
1354         }
1355       }
1356     }
1357
1358     ret = server_estab(cptr, aconf);
1359   }
1360   else
1361     ret = 0;
1362
1363   if (feature_bool(FEAT_RELIABLE_CLOCK) &&
1364       abs(cli_serv(cptr)->timestamp - recv_time) > 30) {
1365     sendto_opmask_butone(0, SNO_OLDSNO, "Connected to a net with a "
1366                          "timestamp-clock difference of %Td seconds! Used "
1367                          "SETTIME to correct this.", timestamp - recv_time);
1368     sendcmdto_one(&me, CMD_SETTIME, cptr, "%Tu :%s", TStime(), cli_name(&me));
1369   }
1370
1371   return ret;
1372 }
1373
1374
1375 #if 0
1376 /*
1377  *  m_server
1378  *
1379  *    parv[0] = sender prefix
1380  *    parv[1] = servername
1381  *    parv[2] = hopcount
1382  *    parv[3] = start timestamp
1383  *    parv[4] = link timestamp
1384  *    parv[5] = major protocol version: P09/P10
1385  *    parv[parc-1] = serverinfo
1386  *  If cptr is P10:
1387  *    parv[6] = "YMM", where 'Y' is the server numeric and "MM" is the
1388  *              numeric nick mask of this server.
1389  *    parv[7] = 0 (not used yet, mandatory unsigned int after u2.10.06)
1390  */
1391 int m_server(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
1392 {
1393   char*            ch;
1394   int              i;
1395   char             info[REALLEN + 1];
1396   char*            host;
1397   struct Client*   acptr;
1398   struct Client*   bcptr;
1399   struct Client*   LHcptr = 0;
1400   struct ConfItem* aconf = 0;
1401   struct ConfItem* lhconf = 0;
1402   struct Jupe*     ajupe = 0;
1403   int              hop;
1404   int              ret;
1405   int              active_lh_line = 0;
1406   unsigned short   prot;
1407   time_t           start_timestamp;
1408   time_t           timestamp = 0;
1409   time_t           recv_time;
1410   time_t           ghost = 0;
1411
1412   if (IsUser(cptr))
1413   {
1414     sendto_one(cptr, err_str(ERR_ALREADYREGISTRED), me.name, parv[0]); /* XXX DEAD */
1415     return 0;
1416   }
1417
1418   if (IsUserPort(cptr))
1419     return exit_client_msg(cptr, cptr, &me,
1420         "You cannot connect a server to a user port; connect to %s port %u",
1421         me.name, server_port);
1422
1423   recv_time = TStime();
1424   info[0] = '\0';
1425   if (parc < 7)
1426   {
1427     return need_more_params(sptr, "SERVER");
1428     return exit_client(cptr, cptr, &me, "Need more parameters");
1429   }
1430   host = parv[1];
1431   /*
1432    * Detect protocol
1433    */
1434   if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
1435     return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
1436
1437   if (!IsServer(cptr))          /* Don't allow silently connecting a server */
1438     *parv[5] = 'J';
1439
1440   prot = atoi(parv[5] + 1);
1441   if (prot > atoi(MAJOR_PROTOCOL))
1442     prot = atoi(MAJOR_PROTOCOL);
1443   /*
1444    * Because the previous test is only in 2.10, the following is needed
1445    * till all servers are 2.10:
1446    */
1447   if (IsServer(cptr) && prot > Protocol(cptr))
1448     prot = Protocol(cptr);
1449   hop = atoi(parv[2]);
1450   start_timestamp = atoi(parv[3]);
1451   timestamp = atoi(parv[4]);
1452   Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age " TIME_T_FMT " ("
1453       TIME_T_FMT ")", host, parv[4], start_timestamp, me.serv->timestamp));
1454   if ((timestamp < OLDEST_TS || (hop == 1 && start_timestamp < OLDEST_TS)))
1455   {
1456     return exit_client_msg(cptr, sptr, &me,
1457         "Bogus timestamps (%s %s)", parv[3], parv[4]);
1458   }
1459   ircd_strncpy(info, parv[parc - 1], REALLEN);
1460   info[REALLEN] = '\0';
1461   if (prot < atoi(MINOR_PROTOCOL)) {
1462     sendto_ops("Got incompatible protocol version (%s) from %s", /* XXX DEAD */
1463                parv[5], cptr->name);
1464     return exit_new_server(cptr, sptr, host, timestamp,
1465         "Incompatible protocol: %s", parv[5]);
1466   }
1467   /*
1468    * Check for "FRENCH " infection ;-) (actually this should
1469    * be replaced with routine to check the hostname syntax in
1470    * general). [ This check is still needed, even after the parse
1471    * is fixed, because someone can send "SERVER :foo bar " ].
1472    * Also, changed to check other "difficult" characters, now
1473    * that parse lets all through... --msa
1474    */
1475   if (strlen(host) > HOSTLEN)
1476     host[HOSTLEN] = '\0';
1477   for (ch = host; *ch; ch++)
1478     if (*ch <= ' ' || *ch > '~')
1479       break;
1480   if (*ch || !strchr(host, '.'))
1481   {
1482     sendto_ops("Bogus server name (%s) from %s", host, cptr->name); /* XXX DEAD */
1483     return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
1484   }
1485
1486   if (IsServer(cptr))
1487   {
1488     /*
1489      * A local server introduces a new server behind this link.
1490      * Check if this is allowed according L:, H: and Q: lines.
1491      */
1492     if (info[0] == '\0')
1493       return exit_client_msg(cptr, cptr, &me,
1494           "No server info specified for %s", host);
1495     /*
1496      * See if the newly found server is behind a guaranteed
1497      * leaf (L-line). If so, close the link.
1498      */
1499     if ((lhconf = find_conf_byhost(cptr->confs, cptr->name, CONF_LEAF)) &&
1500         (!lhconf->port || (hop > lhconf->port)))
1501     {
1502       /*
1503        * L: lines normally come in pairs, here we try to
1504        * make sure that the oldest link is squitted, not
1505        * both.
1506        */
1507       active_lh_line = 1;
1508       if (timestamp <= cptr->serv->timestamp)
1509         LHcptr = 0;          /* Kill incoming server */
1510       else
1511         LHcptr = cptr;          /* Squit ourselfs */
1512     }
1513     else if (!(lhconf = find_conf_byname(cptr->confs, cptr->name, CONF_HUB)) ||
1514              (lhconf->port && (hop > lhconf->port)))
1515     {
1516       struct Client *ac3ptr;
1517       active_lh_line = 2;
1518       /* Look for net junction causing this: */
1519       LHcptr = 0;            /* incoming server */
1520       if (*parv[5] != 'J') {
1521         for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up) {
1522           if (IsJunction(ac3ptr)) {
1523             LHcptr = ac3ptr;
1524             break;
1525           }
1526         }
1527       }
1528     }
1529   }
1530
1531   if (IsUnknown(cptr) || IsHandshake(cptr))
1532   {
1533     const char* encr;
1534
1535     /*
1536      * A local link that is still in undefined state wants
1537      * to be a SERVER. Check if this is allowed and change
1538      * status accordingly...
1539      */
1540     /*
1541      * If there is more then one server on the same machine
1542      * that we try to connect to, it could be that the /CONNECT
1543      * <mask> caused this connect to be put at the wrong place
1544      * in the hashtable.        --Run
1545      * Same thing for Unknown connections that first send NICK.
1546      *                          --Xorath
1547      * Better check if the two strings are (caseless) identical 
1548      * and not mess with hash internals. 
1549      *                          --Nemesi
1550      */
1551     if ((!(EmptyString(cptr->name)))
1552         && (IsUnknown(cptr) || IsHandshake(cptr))
1553         && 0 != ircd_strcmp(cptr->name, host))
1554       hChangeClient(cptr, host);
1555     ircd_strncpy(cptr->name, host, HOSTLEN);
1556     ircd_strncpy(cptr->info, info[0] ? info : me.name, REALLEN);
1557     cptr->hopcount = hop;
1558
1559     /* check connection rules */
1560     if (0 != conf_eval_crule(host, CRULE_ALL)) {
1561       ServerStats->is_ref++;
1562       sendto_ops("Refused connection from %s.", cptr->name); /* XXX DEAD */
1563       return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
1564     }
1565     if (conf_check_server(cptr)) {
1566       ++ServerStats->is_ref;
1567       sendto_ops("Received unauthorized connection from %s.", cptr->name); /* XXX DEAD */
1568       return exit_client(cptr, cptr, &me, "No C/N conf lines");
1569     }
1570
1571     host = cptr->name;
1572
1573     update_load();
1574
1575     if (!(aconf = find_conf_byname(cptr->confs, host, CONF_SERVER))) {
1576       ++ServerStats->is_ref;
1577 #ifndef GODMODE
1578       sendto_ops("Access denied. No conf line for server %s", cptr->name); /* XXX DEAD */
1579       return exit_client_msg(cptr, cptr, &me,
1580           "Access denied. No conf line for server %s", cptr->name);
1581 #else /* GODMODE */
1582       sendto_ops("General C/N: line active: No line for server %s", cptr->name); /* XXX DEAD */
1583       aconf =
1584           find_conf_byname(cptr->confs, "general.undernet.org", CONF_SERVER);
1585       if (!aconf) {
1586         sendto_ops("Neither C/N lines for server %s nor " /* XXX DEAD */
1587             "\"general.undernet.org\"", cptr->name);
1588         return exit_client_msg(cptr, cptr, &me,
1589             "No C/N lines for server %s", cptr->name);
1590       }
1591 #endif /* GODMODE */
1592     }
1593 #ifdef CRYPT_LINK_PASSWORD
1594     /* passwd may be NULL. Head it off at the pass... */
1595     if (*cptr->passwd)
1596     {
1597       encr = ircd_crypt(cptr->passwd, aconf->passwd);
1598     }
1599     else
1600       encr = "";
1601 #else
1602     encr = cptr->passwd;
1603 #endif /* CRYPT_LINK_PASSWORD */
1604 #ifndef GODMODE
1605     if (*aconf->passwd && !!strcmp(aconf->passwd, encr)) {
1606       ++ServerStats->is_ref;
1607       sendto_ops("Access denied (passwd mismatch) %s", cptr->name); /* XXX DEAD */
1608       return exit_client_msg(cptr, cptr, &me,
1609           "No Access (passwd mismatch) %s", cptr->name);
1610     }
1611 #endif /* not GODMODE */
1612     memset(cptr->passwd, 0, sizeof(cptr->passwd));
1613
1614 #ifndef HUB
1615     for (i = 0; i <= HighestFd; i++)
1616       if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
1617         active_lh_line = 3;
1618         LHcptr = 0;
1619         break;
1620       }
1621 #endif
1622   }
1623
1624   /*
1625    *  We want to find IsConnecting() and IsHandshake() too,
1626    *  use FindClient().
1627    *  The second finds collisions with numeric representation of existing
1628    *  servers - these shouldn't happen anymore when all upgraded to 2.10.
1629    *  -- Run
1630    */
1631   while ((acptr = FindClient(host)) || 
1632          (parc > 7 && (acptr = FindNServer(parv[6]))))
1633   {
1634     /*
1635      *  This link is trying feed me a server that I already have
1636      *  access through another path
1637      *
1638      *  Do not allow Uworld to do this.
1639      *  Do not allow servers that are juped.
1640      *  Do not allow servers that have older link timestamps
1641      *    then this try.
1642      *  Do not allow servers that use the same numeric as an existing
1643      *    server, but have a different name.
1644      *
1645      *  If my ircd.conf sucks, I can try to connect to myself:
1646      */
1647     if (acptr == &me)
1648       return exit_client_msg(cptr, cptr, &me,
1649           "nick collision with me, check server number in M:? (%s)", host);
1650     /*
1651      * Detect wrong numeric.
1652      */
1653     if (0 != ircd_strcmp(acptr->name, host))
1654     {
1655       sendto_serv_butone(cptr, /* XXX DEAD */
1656           ":%s WALLOPS :SERVER Numeric Collision: %s != %s",
1657           me.name, acptr->name, host);
1658       return exit_client_msg(cptr, cptr, &me,
1659           "NUMERIC collision between %s and %s."
1660           " Is your server numeric correct ?", host, acptr->name);
1661     }
1662     /*
1663      *  Kill our try, if we had one.
1664      */
1665     if (IsConnecting(acptr))
1666     {
1667       if (!active_lh_line && exit_client(cptr, acptr, &me,
1668           "Just connected via another link") == CPTR_KILLED)
1669         return CPTR_KILLED;
1670       /*
1671        * We can have only ONE 'IsConnecting', 'IsHandshake' or
1672        * 'IsServer', because new 'IsConnecting's are refused to
1673        * the same server if we already had it.
1674        */
1675       break;
1676     }
1677     /*
1678      * Avoid other nick collisions...
1679      * This is a doubtfull test though, what else would it be
1680      * when it has a server.name ?
1681      */
1682     else if (!IsServer(acptr) && !IsHandshake(acptr))
1683       return exit_client_msg(cptr, cptr, &me,
1684           "Nickname %s already exists!", host);
1685     /*
1686      * Our new server might be a juped server,
1687      * or someone trying abuse a second Uworld:
1688      */
1689     else if (IsServer(acptr) && (0 == ircd_strncmp(acptr->info, "JUPE", 4) ||
1690         find_conf_byhost(cptr->confs, acptr->name, CONF_UWORLD)))
1691     {
1692       if (!IsServer(sptr))
1693         return exit_client(cptr, sptr, &me, acptr->info);
1694       sendto_one(cptr, ":%s WALLOPS :Received :%s SERVER %s from %s !?!", /* XXX DEAD */
1695           me.name, parv[0], parv[1], cptr->name);
1696       return exit_new_server(cptr, sptr, host, timestamp, "%s", acptr->info);
1697     }
1698     /*
1699      * Of course we find the handshake this link was before :)
1700      */
1701     else if (IsHandshake(acptr) && acptr == cptr)
1702       break;
1703     /*
1704      * Here we have a server nick collision...
1705      * We don't want to kill the link that was last /connected,
1706      * but we neither want to kill a good (old) link.
1707      * Therefor we kill the second youngest link.
1708      */
1709     if (1)
1710     {
1711       struct Client* c2ptr = 0;
1712       struct Client* c3ptr = acptr;
1713       struct Client* ac2ptr;
1714       struct Client* ac3ptr;
1715
1716       /* Search youngest link: */
1717       for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
1718         if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
1719           c3ptr = ac3ptr;
1720       if (IsServer(sptr))
1721       {
1722         for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
1723           if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
1724             c3ptr = ac3ptr;
1725       }
1726       if (timestamp > c3ptr->serv->timestamp)
1727       {
1728         c3ptr = 0;
1729         c2ptr = acptr;          /* Make sure they differ */
1730       }
1731       /* Search second youngest link: */
1732       for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
1733         if (ac2ptr != c3ptr &&
1734             ac2ptr->serv->timestamp >
1735             (c2ptr ? c2ptr->serv->timestamp : timestamp))
1736           c2ptr = ac2ptr;
1737       if (IsServer(sptr))
1738       {
1739         for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
1740           if (ac2ptr != c3ptr &&
1741               ac2ptr->serv->timestamp >
1742               (c2ptr ? c2ptr->serv->timestamp : timestamp))
1743             c2ptr = ac2ptr;
1744       }
1745       if (c3ptr && timestamp > (c2ptr ? c2ptr->serv->timestamp : timestamp))
1746         c2ptr = 0;
1747       /* If timestamps are equal, decide which link to break
1748        *  by name.
1749        */
1750       if ((c2ptr ? c2ptr->serv->timestamp : timestamp) ==
1751           (c3ptr ? c3ptr->serv->timestamp : timestamp))
1752       {
1753         char* n2;
1754         char* n2up;
1755         char* n3;
1756         char* n3up;
1757         if (c2ptr)
1758         {
1759           n2 = c2ptr->name;
1760           n2up = MyConnect(c2ptr) ? me.name : c2ptr->serv->up->name;
1761         }
1762         else
1763         {
1764           n2 = host;
1765           n2up = IsServer(sptr) ? sptr->name : me.name;
1766         }
1767         if (c3ptr)
1768         {
1769           n3 = c3ptr->name;
1770           n3up = MyConnect(c3ptr) ? me.name : c3ptr->serv->up->name;
1771         }
1772         else
1773         {
1774           n3 = host;
1775           n3up = IsServer(sptr) ? sptr->name : me.name;
1776         }
1777         if (strcmp(n2, n2up) > 0)
1778           n2 = n2up;
1779         if (strcmp(n3, n3up) > 0)
1780           n3 = n3up;
1781         if (strcmp(n3, n2) > 0)
1782         {
1783           ac2ptr = c2ptr;
1784           c2ptr = c3ptr;
1785           c3ptr = ac2ptr;
1786         }
1787       }
1788       /* Now squit the second youngest link: */
1789       if (!c2ptr)
1790         return exit_new_server(cptr, sptr, host, timestamp,
1791             "server %s already exists and is %ld seconds younger.",
1792             host, (long)acptr->serv->timestamp - (long)timestamp);
1793       else if (c2ptr->from == cptr || IsServer(sptr))
1794       {
1795         struct Client *killedptrfrom = c2ptr->from;
1796         if (active_lh_line)
1797         {
1798           /*
1799            * If the L: or H: line also gets rid of this link,
1800            * we sent just one squit.
1801            */
1802           if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
1803             break;
1804           /*
1805            * If breaking the loop here solves the L: or H:
1806            * line problem, we don't squit that.
1807            */
1808           if (c2ptr->from == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
1809             active_lh_line = 0;
1810           else
1811           {
1812             /*
1813              * If we still have a L: or H: line problem,
1814              * we prefer to squit the new server, solving
1815              * loop and L:/H: line problem with only one squit.
1816              */
1817             LHcptr = 0;
1818             break;
1819           }
1820         }
1821         /*
1822          * If the new server was introduced by a server that caused a
1823          * Ghost less then 20 seconds ago, this is probably also
1824          * a Ghost... (20 seconds is more then enough because all
1825          * SERVER messages are at the beginning of a net.burst). --Run
1826          */
1827         if (CurrentTime - cptr->serv->ghost < 20)
1828         {
1829           killedptrfrom = acptr->from;
1830           if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
1831             return CPTR_KILLED;
1832         }
1833         else if (exit_client_msg(cptr, c2ptr, &me,
1834             "Loop <-- %s (new link is %ld seconds younger)", host,
1835             (c3ptr ? (long)c3ptr->serv->timestamp : timestamp) -
1836             (long)c2ptr->serv->timestamp) == CPTR_KILLED)
1837           return CPTR_KILLED;
1838         /*
1839          * Did we kill the incoming server off already ?
1840          */
1841         if (killedptrfrom == cptr)
1842           return 0;
1843       }
1844       else
1845       {
1846         if (active_lh_line)
1847         {
1848           if (LHcptr && a_kills_b_too(LHcptr, acptr))
1849             break;
1850           if (acptr->from == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
1851             active_lh_line = 0;
1852           else
1853           {
1854             LHcptr = 0;
1855             break;
1856           }
1857         }
1858         /*
1859          * We can't believe it is a lagged server message
1860          * when it directly connects to us...
1861          * kill the older link at the ghost, rather then
1862          * at the second youngest link, assuming it isn't
1863          * a REAL loop.
1864          */
1865         ghost = CurrentTime;            /* Mark that it caused a ghost */
1866         if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
1867           return CPTR_KILLED;
1868         break;
1869       }
1870     }
1871   }
1872
1873   if (active_lh_line)
1874   {
1875     if (LHcptr == 0) {
1876       return exit_new_server(cptr, sptr, host, timestamp,
1877           (active_lh_line == 2) ?  "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1878           cptr->name, host,
1879           lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
1880     }
1881     else
1882     {
1883       int killed = a_kills_b_too(LHcptr, sptr);
1884       if (active_lh_line < 3)
1885       {
1886         if (exit_client_msg(cptr, LHcptr, &me,
1887             (active_lh_line == 2) ?  "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1888             cptr->name, host,
1889             lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
1890           return CPTR_KILLED;
1891       }
1892       else
1893       {
1894         ServerStats->is_ref++;
1895         if (exit_client(cptr, LHcptr, &me, "I'm a leaf") == CPTR_KILLED)
1896           return CPTR_KILLED;
1897       }
1898       /*
1899        * Did we kill the incoming server off already ?
1900        */
1901       if (killed)
1902         return 0;
1903     }
1904   }
1905
1906   if (IsServer(cptr))
1907   {
1908     /*
1909      * Server is informing about a new server behind
1910      * this link. Create REMOTE server structure,
1911      * add it to list and propagate word to my other
1912      * server links...
1913      */
1914
1915     acptr = make_client(cptr, STAT_SERVER);
1916     make_server(acptr);
1917     acptr->serv->prot = prot;
1918     acptr->serv->timestamp = timestamp;
1919     acptr->hopcount = hop;
1920     ircd_strncpy(acptr->name, host, HOSTLEN);
1921     ircd_strncpy(acptr->info, info, REALLEN);
1922     acptr->serv->up = sptr;
1923     acptr->serv->updown = add_dlink(&sptr->serv->down, acptr);
1924     /* Use cptr, because we do protocol 9 -> 10 translation
1925        for numeric nicks ! */
1926     SetServerYXX(cptr, acptr, parv[6]);
1927
1928     Count_newremoteserver(UserStats);
1929     if (Protocol(acptr) < 10)
1930       acptr->flags |= FLAGS_TS8;
1931     add_client_to_list(acptr);
1932     hAddClient(acptr);
1933     if (*parv[5] == 'J')
1934     {
1935       SetBurst(acptr);
1936       sendto_op_mask(SNO_NETWORK, "Net junction: %s %s", /* XXX DEAD */
1937           sptr->name, acptr->name);
1938       SetJunction(acptr);
1939     }
1940     /*
1941      * Old sendto_serv_but_one() call removed because we now need to send
1942      * different names to different servers (domain name matching).
1943      */
1944     for (i = 0; i <= HighestFd; i++)
1945     {
1946       if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
1947           bcptr == cptr || IsMe(bcptr))
1948         continue;
1949       if (0 == match(me.name, acptr->name))
1950         continue;
1951         sendto_one(bcptr, "%s " TOK_SERVER " %s %d 0 %s %s %s%s 0 :%s", /* XXX DEAD */
1952             NumServ(sptr), acptr->name, hop + 1, parv[4], parv[5],
1953             NumServCap(acptr), acptr->info);
1954     }
1955     return 0;
1956   }
1957
1958   if (IsUnknown(cptr) || IsHandshake(cptr))
1959   {
1960     make_server(cptr);
1961     cptr->serv->timestamp = timestamp;
1962     cptr->serv->prot = prot;
1963     cptr->serv->ghost = ghost;
1964     SetServerYXX(cptr, cptr, parv[6]);
1965     if (start_timestamp > OLDEST_TS)
1966     {
1967 #ifndef RELIABLE_CLOCK
1968 #ifdef TESTNET
1969       sendto_ops("Debug: my start time: " TIME_T_FMT " ; others start time: " /* XXX DEAD */
1970           TIME_T_FMT, me.serv->timestamp, start_timestamp);
1971       sendto_ops("Debug: receive time: " TIME_T_FMT " ; received timestamp: " /* XXX DEAD */
1972           TIME_T_FMT " ; difference %ld",
1973           recv_time, timestamp, timestamp - recv_time);
1974 #endif
1975       if (start_timestamp < me.serv->timestamp)
1976       {
1977         sendto_ops("got earlier start time: " TIME_T_FMT " < " TIME_T_FMT, /* XXX DEAD */
1978             start_timestamp, me.serv->timestamp);
1979         me.serv->timestamp = start_timestamp;
1980         TSoffset += timestamp - recv_time;
1981         sendto_ops("clock adjusted by adding %d", (int)(timestamp - recv_time)); /* XXX DEAD */
1982       }
1983       else if ((start_timestamp > me.serv->timestamp) && IsUnknown(cptr))
1984         cptr->serv->timestamp = TStime();
1985
1986       else if (timestamp != recv_time)
1987       {
1988         /*
1989          * Equal start times, we have a collision.  Let the connected-to server
1990          * decide. This assumes leafs issue more than half of the connection
1991          * attempts.
1992          */
1993         if (IsUnknown(cptr))
1994           cptr->serv->timestamp = TStime();
1995         else if (IsHandshake(cptr))
1996         {
1997           sendto_ops("clock adjusted by adding %d", /* XXX DEAD */
1998               (int)(timestamp - recv_time));
1999           TSoffset += timestamp - recv_time;
2000         }
2001       }
2002 #else /* RELIABLE CLOCK IS TRUE, we _always_ use our own clock */
2003       if (start_timestamp < me.serv->timestamp)
2004         me.serv->timestamp = start_timestamp;
2005       if (IsUnknown(cptr))
2006         cptr->serv->timestamp = TStime();
2007 #endif
2008     }
2009
2010     ret = server_estab(cptr, aconf); /* XXX DEAD */
2011   }
2012   else
2013     ret = 0;
2014 #ifdef RELIABLE_CLOCK
2015   if (abs(cptr->serv->timestamp - recv_time) > 30)
2016   {
2017     sendto_ops("Connected to a net with a timestamp-clock" /* XXX DEAD */
2018         " difference of " STIME_T_FMT " seconds! Used SETTIME to correct"
2019         " this.", timestamp - recv_time);
2020     sendto_one(cptr, ":%s SETTIME " TIME_T_FMT " :%s", /* XXX DEAD */
2021         me.name, TStime(), me.name);
2022   }
2023 #endif
2024
2025   return ret;
2026 }
2027 #endif /* 0 */
2028