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 #include "client.h"
85 #include "hash.h"
86 #include "ircd.h"
87 #include "ircd_log.h"
88 #include "ircd_features.h"
89 #include "ircd_reply.h"
90 #include "ircd_string.h"
91 #include "jupe.h"
92 #include "list.h"
93 #include "match.h"
94 #include "msg.h"
95 #include "numeric.h"
96 #include "numnicks.h"
97 #include "querycmds.h"
98 #include "s_bsd.h"
99 #include "s_conf.h"
100 #include "s_debug.h"
101 #include "s_misc.h"
102 #include "s_serv.h"
103 #include "send.h"
104 #include "userload.h"
105
106 #include <assert.h>
107 #include <stdlib.h>
108 #include <string.h>
109
110 /*
111  * mr_server - registration message handler
112  *
113  *    parv[0] = sender prefix
114  *    parv[1] = servername
115  *    parv[2] = hopcount
116  *    parv[3] = start timestamp
117  *    parv[4] = link timestamp
118  *    parv[5] = major protocol version: P09/P10
119  *    parv[parc-1] = serverinfo
120  *  If cptr is P10:
121  *    parv[6] = "YMM", where 'Y' is the server numeric and "MM" is the
122  *              numeric nick mask of this server.
123  *    parv[7] = +hs (h == hub, s == service)
124  */
125 int mr_server(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
126 {
127   char*            ch;
128   int              i;
129   char             info[REALLEN + 1];
130   char*            host;
131   struct Client*   acptr;
132   struct Client*   bcptr;
133   struct Client*   LHcptr = 0;
134   struct ConfItem* aconf = 0;
135   struct ConfItem* lhconf = 0;
136   struct Jupe*     ajupe = 0;
137   int              hop;
138   int              ret;
139   int              active_lh_line = 0;
140   unsigned short   prot;
141   time_t           start_timestamp;
142   time_t           timestamp = 0;
143   time_t           recv_time;
144   time_t           ghost = 0;
145
146   if (IsUserPort(cptr))
147     return exit_client_msg(cptr, cptr, &me, 
148                            "Cannot connect a server to a user port");
149
150   recv_time = TStime();
151   info[0] = '\0';
152
153   if (parc < 7)
154   {
155     need_more_params(sptr, "SERVER");
156     return exit_client(cptr, cptr, &me, "Need more parameters");
157   }
158   host = parv[1];
159
160   if ((ajupe = jupe_find(host)) && JupeIsActive(ajupe))
161     return exit_client_msg(cptr, sptr, &me, "Juped: %s", JupeReason(ajupe));
162
163   log_write(LS_NETWORK, L_NOTICE, LOG_NOSNOTICE, "SERVER: %s %s[%s]", parv[1],
164             cli_sockhost(cptr), cli_sock_ip(cptr));
165
166   /*
167    * Detect protocol
168    */
169   if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
170     return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
171
172   if (!IsServer(cptr))          /* Don't allow silently connecting a server */
173     *parv[5] = 'J';
174
175   if (*parv[7] == '+') {
176     for (ch = parv[7] + 1; *ch; ch++)
177       switch (*ch) {
178       case 'h':
179         SetHub(cptr);
180         break;
181       case 's':
182         SetService(cptr);
183         break;
184       }
185   }
186
187   prot = atoi(parv[5] + 1);
188   if (prot > atoi(MAJOR_PROTOCOL))
189     prot = atoi(MAJOR_PROTOCOL);
190   /*
191    * Because the previous test is only in 2.10, the following is needed
192    * till all servers are 2.10:
193    */
194   if (IsServer(cptr) && prot > Protocol(cptr))
195     prot = Protocol(cptr);
196   hop = atoi(parv[2]);
197   start_timestamp = atoi(parv[3]);
198   timestamp = atoi(parv[4]);
199   Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age %Tu (%Tu)",
200          host, parv[4], start_timestamp, cli_serv(&me)->timestamp));
201
202   if ((timestamp < OLDEST_TS || (hop == 1 && start_timestamp < OLDEST_TS)))
203   {
204     return exit_client_msg(cptr, sptr, &me,
205         "Bogus timestamps (%s %s)", parv[3], parv[4]);
206   }
207   ircd_strncpy(info, parv[parc - 1], REALLEN);
208   info[REALLEN] = '\0';
209   if (prot < atoi(MINOR_PROTOCOL)) {
210     sendto_opmask_butone(0, SNO_OLDSNO, "Got incompatible protocol version "
211                          "(%s) from %s", parv[5], cli_name(cptr));
212     return exit_new_server(cptr, sptr, host, timestamp,
213                            "Incompatible protocol: %s", parv[5]);
214   }
215   /*
216    * Check for "FRENCH " infection ;-) (actually this should
217    * be replaced with routine to check the hostname syntax in
218    * general). [ This check is still needed, even after the parse
219    * is fixed, because someone can send "SERVER :foo bar " ].
220    * Also, changed to check other "difficult" characters, now
221    * that parse lets all through... --msa
222    */
223   if (strlen(host) > HOSTLEN)
224     host[HOSTLEN] = '\0';
225
226   for (ch = host; *ch; ch++) {
227     if (*ch <= ' ' || *ch > '~')
228       break;
229   }
230   if (*ch || !strchr(host, '.')) {
231     sendto_opmask_butone(0, SNO_OLDSNO, "Bogus server name (%s) from %s",
232                          host, cli_name(cptr));
233     return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
234   }
235
236   if (IsServer(cptr))
237   {
238     /*
239      * A local server introduces a new server behind this link.
240      * Check if this is allowed according L:, H: and Q: lines.
241      */
242     if (info[0] == '\0')
243       return exit_client_msg(cptr, cptr, &me,
244                              "No server info specified for %s", host);
245     /*
246      * See if the newly found server is behind a guaranteed
247      * leaf (L-line). If so, close the link.
248      */
249     if ((lhconf = find_conf_byhost(cli_confs(cptr), cli_name(cptr), CONF_LEAF)) &&
250         (!lhconf->port || (hop > lhconf->port)))
251     {
252       /*
253        * L: lines normally come in pairs, here we try to
254        * make sure that the oldest link is squitted, not
255        * both.
256        */
257       active_lh_line = 1;
258       if (timestamp <= cli_serv(cptr)->timestamp)
259         LHcptr = 0;          /* Kill incoming server */
260       else
261         LHcptr = cptr;          /* Squit ourselfs */
262     }
263     else if (!(lhconf = find_conf_byname(cli_confs(cptr), cli_name(cptr), CONF_HUB)) ||
264              (lhconf->port && (hop > lhconf->port)))
265     {
266       struct Client *ac3ptr;
267       active_lh_line = 2;
268       /* Look for net junction causing this: */
269       LHcptr = 0;            /* incoming server */
270       if (*parv[5] != 'J') {
271         for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up) {
272           if (IsJunction(ac3ptr)) {
273             LHcptr = ac3ptr;
274             break;
275           }
276         }
277       }
278     }
279   }
280
281   if (IsUnknown(cptr) || IsHandshake(cptr))
282   {
283     const char* encr;
284
285     /*
286      * A local link that is still in undefined state wants
287      * to be a SERVER. Check if this is allowed and change
288      * status accordingly...
289      */
290     /*
291      * If there is more then one server on the same machine
292      * that we try to connect to, it could be that the /CONNECT
293      * <mask> caused this connect to be put at the wrong place
294      * in the hashtable.        --Run
295      * Same thing for Unknown connections that first send NICK.
296      *                          --Xorath
297      * Better check if the two strings are (caseless) identical 
298      * and not mess with hash internals. 
299      *                          --Nemesi
300      */
301     if (!EmptyString(cli_name(cptr)) && 
302         (IsUnknown(cptr) || IsHandshake(cptr)) &&
303         0 != ircd_strcmp(cli_name(cptr), host))
304       hChangeClient(cptr, host);
305     ircd_strncpy(cli_name(cptr), host, HOSTLEN);
306     ircd_strncpy(cli_info(cptr), info[0] ? info : cli_name(&me), REALLEN);
307     cli_hopcount(cptr) = hop;
308
309     /* check connection rules */
310     if (0 != conf_eval_crule(host, CRULE_ALL)) {
311       ServerStats->is_ref++;
312       sendto_opmask_butone(0, SNO_OLDSNO, "Refused connection from %s.", cli_name(cptr));
313       return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
314     }
315
316     if (conf_check_server(cptr)) {
317       ++ServerStats->is_ref;
318       sendto_opmask_butone(0, SNO_OLDSNO, "Received unauthorized connection "
319                            "from %s.", cli_name(cptr));
320       return exit_client(cptr, cptr, &me, "No C:line");
321     }
322
323     host = cli_name(cptr);
324
325     update_load();
326
327     if (!(aconf = find_conf_byname(cli_confs(cptr), host, CONF_SERVER))) {
328       ++ServerStats->is_ref;
329       sendto_opmask_butone(0, SNO_OLDSNO, "Access denied. No conf line for "
330                            "server %s", cli_name(cptr));
331       return exit_client_msg(cptr, cptr, &me,
332           "Access denied. No conf line for server %s", cli_name(cptr));
333     }
334     encr = cli_passwd(cptr);
335
336     if (*aconf->passwd && !!strcmp(aconf->passwd, encr)) {
337       ++ServerStats->is_ref;
338       sendto_opmask_butone(0, SNO_OLDSNO, "Access denied (passwd mismatch) %s",
339                            cli_name(cptr));
340       return exit_client_msg(cptr, cptr, &me,
341           "No Access (passwd mismatch) %s", cli_name(cptr));
342     }
343
344     memset(cli_passwd(cptr), 0, sizeof(cli_passwd(cptr)));
345
346     if (!feature_bool(FEAT_HUB)) {
347       for (i = 0; i <= HighestFd; i++)
348         if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
349           active_lh_line = 3;
350           LHcptr = 0;
351           break;
352         }
353     }
354   }
355
356   /*
357    *  We want to find IsConnecting() and IsHandshake() too,
358    *  use FindClient().
359    *  The second finds collisions with numeric representation of existing
360    *  servers - these shouldn't happen anymore when all upgraded to 2.10.
361    *  -- Run
362    */
363   while ((acptr = FindClient(host)) || 
364          (parc > 7 && (acptr = FindNServer(parv[6]))))
365   {
366     /*
367      *  This link is trying feed me a server that I already have
368      *  access through another path
369      *
370      *  Do not allow Uworld to do this.
371      *  Do not allow servers that are juped.
372      *  Do not allow servers that have older link timestamps
373      *    then this try.
374      *  Do not allow servers that use the same numeric as an existing
375      *    server, but have a different name.
376      *
377      *  If my ircd.conf sucks, I can try to connect to myself:
378      */
379     if (acptr == &me)
380       return exit_client_msg(cptr, cptr, &me, "nick collision with me (%s), check server number in M:?", host);
381     /*
382      * Detect wrong numeric.
383      */
384     if (0 != ircd_strcmp(cli_name(acptr), host)) {
385       sendcmdto_serv_butone(&me, CMD_WALLOPS, cptr,
386                             ":SERVER Numeric Collision: %s != %s",
387                             cli_name(acptr), host);
388       return exit_client_msg(cptr, cptr, &me,
389           "NUMERIC collision between %s and %s."
390           " Is your server numeric correct ?", host, cli_name(acptr));
391     }
392     /*
393      *  Kill our try, if we had one.
394      */
395     if (IsConnecting(acptr))
396     {
397       if (!active_lh_line && exit_client(cptr, acptr, &me,
398           "Just connected via another link") == CPTR_KILLED)
399         return CPTR_KILLED;
400       /*
401        * We can have only ONE 'IsConnecting', 'IsHandshake' or
402        * 'IsServer', because new 'IsConnecting's are refused to
403        * the same server if we already had it.
404        */
405       break;
406     }
407     /*
408      * Avoid other nick collisions...
409      * This is a doubtfull test though, what else would it be
410      * when it has a server.name ?
411      */
412     else if (!IsServer(acptr) && !IsHandshake(acptr))
413       return exit_client_msg(cptr, cptr, &me,
414                              "Nickname %s already exists!", host);
415     /*
416      * Our new server might be a juped server,
417      * or someone trying abuse a second Uworld:
418      */
419     else if (IsServer(acptr) && (0 == ircd_strncmp(cli_info(acptr), "JUPE", 4) ||
420         find_conf_byhost(cli_confs(cptr), cli_name(acptr), CONF_UWORLD)))
421     {
422       if (!IsServer(sptr))
423         return exit_client(cptr, sptr, &me, cli_info(acptr));
424       sendcmdto_serv_butone(&me, CMD_WALLOPS, cptr,
425                             ":Received :%s SERVER %s from %s !?!", parv[0],
426                             parv[1], cli_name(cptr));
427       return exit_new_server(cptr, sptr, host, timestamp, "%s", cli_info(acptr));
428     }
429     /*
430      * Of course we find the handshake this link was before :)
431      */
432     else if (IsHandshake(acptr) && acptr == cptr)
433       break;
434     /*
435      * Here we have a server nick collision...
436      * We don't want to kill the link that was last /connected,
437      * but we neither want to kill a good (old) link.
438      * Therefor we kill the second youngest link.
439      */
440     if (1)
441     {
442       struct Client* c2ptr = 0;
443       struct Client* c3ptr = acptr;
444       struct Client* ac2ptr;
445       struct Client* ac3ptr;
446
447       /* Search youngest link: */
448       for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up)
449         if (cli_serv(ac3ptr)->timestamp > cli_serv(c3ptr)->timestamp)
450           c3ptr = ac3ptr;
451       if (IsServer(sptr))
452       {
453         for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up)
454           if (cli_serv(ac3ptr)->timestamp > cli_serv(c3ptr)->timestamp)
455             c3ptr = ac3ptr;
456       }
457       if (timestamp > cli_serv(c3ptr)->timestamp)
458       {
459         c3ptr = 0;
460         c2ptr = acptr;          /* Make sure they differ */
461       }
462       /* Search second youngest link: */
463       for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = cli_serv(ac2ptr)->up)
464         if (ac2ptr != c3ptr &&
465             cli_serv(ac2ptr)->timestamp >
466             (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
467           c2ptr = ac2ptr;
468       if (IsServer(sptr))
469       {
470         for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = cli_serv(ac2ptr)->up)
471           if (ac2ptr != c3ptr &&
472               cli_serv(ac2ptr)->timestamp >
473               (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
474             c2ptr = ac2ptr;
475       }
476       if (c3ptr && timestamp > (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
477         c2ptr = 0;
478       /* If timestamps are equal, decide which link to break
479        *  by name.
480        */
481       if ((c2ptr ? cli_serv(c2ptr)->timestamp : timestamp) ==
482           (c3ptr ? cli_serv(c3ptr)->timestamp : timestamp))
483       {
484         char* n2;
485         char* n2up;
486         char* n3;
487         char* n3up;
488         if (c2ptr)
489         {
490           n2 = cli_name(c2ptr);
491           n2up = MyConnect(c2ptr) ? cli_name(&me) : cli_name(cli_serv(c2ptr)->up);
492         }
493         else
494         {
495           n2 = host;
496           n2up = IsServer(sptr) ? cli_name(sptr) : cli_name(&me);
497         }
498         if (c3ptr)
499         {
500           n3 = cli_name(c3ptr);
501           n3up = MyConnect(c3ptr) ? cli_name(&me) : cli_name(cli_serv(c3ptr)->up);
502         }
503         else
504         {
505           n3 = host;
506           n3up = IsServer(sptr) ? cli_name(sptr) : cli_name(&me);
507         }
508         if (strcmp(n2, n2up) > 0)
509           n2 = n2up;
510         if (strcmp(n3, n3up) > 0)
511           n3 = n3up;
512         if (strcmp(n3, n2) > 0)
513         {
514           ac2ptr = c2ptr;
515           c2ptr = c3ptr;
516           c3ptr = ac2ptr;
517         }
518       }
519       /* Now squit the second youngest link: */
520       if (!c2ptr)
521         return exit_new_server(cptr, sptr, host, timestamp,
522                                "server %s already exists and is %ld seconds younger.",
523                                host, (long)cli_serv(acptr)->timestamp - (long)timestamp);
524       else if (cli_from(c2ptr) == cptr || IsServer(sptr))
525       {
526         struct Client *killedptrfrom = cli_from(c2ptr);
527         if (active_lh_line)
528         {
529           /*
530            * If the L: or H: line also gets rid of this link,
531            * we sent just one squit.
532            */
533           if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
534             break;
535           /*
536            * If breaking the loop here solves the L: or H:
537            * line problem, we don't squit that.
538            */
539           if (cli_from(c2ptr) == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
540             active_lh_line = 0;
541           else
542           {
543             /*
544              * If we still have a L: or H: line problem,
545              * we prefer to squit the new server, solving
546              * loop and L:/H: line problem with only one squit.
547              */
548             LHcptr = 0;
549             break;
550           }
551         }
552         /*
553          * If the new server was introduced by a server that caused a
554          * Ghost less then 20 seconds ago, this is probably also
555          * a Ghost... (20 seconds is more then enough because all
556          * SERVER messages are at the beginning of a net.burst). --Run
557          */
558         if (CurrentTime - cli_serv(cptr)->ghost < 20)
559         {
560           killedptrfrom = cli_from(acptr);
561           if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
562             return CPTR_KILLED;
563         }
564         else if (exit_client_msg(cptr, c2ptr, &me,
565             "Loop <-- %s (new link is %ld seconds younger)", host,
566             (c3ptr ? (long)cli_serv(c3ptr)->timestamp : timestamp) -
567             (long)cli_serv(c2ptr)->timestamp) == CPTR_KILLED)
568           return CPTR_KILLED;
569         /*
570          * Did we kill the incoming server off already ?
571          */
572         if (killedptrfrom == cptr)
573           return 0;
574       }
575       else
576       {
577         if (active_lh_line)
578         {
579           if (LHcptr && a_kills_b_too(LHcptr, acptr))
580             break;
581           if (cli_from(acptr) == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
582             active_lh_line = 0;
583           else
584           {
585             LHcptr = 0;
586             break;
587           }
588         }
589         /*
590          * We can't believe it is a lagged server message
591          * when it directly connects to us...
592          * kill the older link at the ghost, rather then
593          * at the second youngest link, assuming it isn't
594          * a REAL loop.
595          */
596         ghost = CurrentTime;            /* Mark that it caused a ghost */
597         if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
598           return CPTR_KILLED;
599         break;
600       }
601     }
602   }
603
604   if (active_lh_line)
605   {
606     if (LHcptr == 0) {
607       return exit_new_server(cptr, sptr, host, timestamp,
608           (active_lh_line == 2) ?  "Non-Hub link %s <- %s(%s), check H:" : 
609                                    "Leaf-only link %s <- %s(%s), check L:",
610           cli_name(cptr), host, 
611           lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
612     }
613     else
614     {
615       int killed = a_kills_b_too(LHcptr, sptr);
616       if (active_lh_line < 3)
617       {
618         if (exit_client_msg(cptr, LHcptr, &me,
619             (active_lh_line == 2) ?  "Non-Hub link %s <- %s(%s), check H:" : 
620                                      "Leaf-only link %s <- %s(%s), check L:",
621             cli_name(cptr), host,
622             lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
623           return CPTR_KILLED;
624       }
625       else
626       {
627         ServerStats->is_ref++;
628         if (exit_client(cptr, LHcptr, &me, "I'm a leaf, define HUB") == CPTR_KILLED)
629           return CPTR_KILLED;
630       }
631       /*
632        * Did we kill the incoming server off already ?
633        */
634       if (killed)
635         return 0;
636     }
637   }
638
639   if (IsServer(cptr))
640   {
641     /*
642      * Server is informing about a new server behind
643      * this link. Create REMOTE server structure,
644      * add it to list and propagate word to my other
645      * server links...
646      */
647
648     acptr = make_client(cptr, STAT_SERVER);
649     make_server(acptr);
650     cli_serv(acptr)->prot = prot;
651     cli_serv(acptr)->timestamp = timestamp;
652     cli_hopcount(acptr) = hop;
653     ircd_strncpy(cli_name(acptr), host, HOSTLEN);
654     ircd_strncpy(cli_info(acptr), info, REALLEN);
655     cli_serv(acptr)->up = sptr;
656     cli_serv(acptr)->updown = add_dlink(&(cli_serv(sptr))->down, acptr);
657     /* Use cptr, because we do protocol 9 -> 10 translation
658        for numeric nicks ! */
659     SetServerYXX(cptr, acptr, parv[6]);
660
661     Count_newremoteserver(UserStats);
662     if (Protocol(acptr) < 10)
663       cli_flags(acptr) |= FLAGS_TS8;
664     add_client_to_list(acptr);
665     hAddClient(acptr);
666     if (*parv[5] == 'J')
667     {
668       SetBurst(acptr);
669       sendto_opmask_butone(0, SNO_NETWORK, "Net junction: %s %s",
670           cli_name(sptr), cli_name(acptr));
671       SetJunction(acptr);
672     }
673     /*
674      * Old sendto_serv_but_one() call removed because we now need to send
675      * different names to different servers (domain name matching).
676      *
677      * Personally, I think this is bogus; it's a feature we don't use here.
678      * -Kev
679      */
680     for (i = 0; i <= HighestFd; i++)
681     {
682       if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
683           bcptr == cptr || IsMe(bcptr))
684         continue;
685       if (0 == match(cli_name(&me), cli_name(acptr)))
686         continue;
687       sendcmdto_one(sptr, CMD_SERVER, bcptr, "%s %d 0 %s %s %s%s +%s%s :%s",
688                     cli_name(acptr), hop + 1, parv[4], parv[5],
689                     NumServCap(acptr), IsHub(acptr) ? "h" : "",
690                     IsService(acptr) ? "s" : "", cli_info(acptr));
691     }
692     return 0;
693   }
694
695   if (IsUnknown(cptr) || IsHandshake(cptr))
696   {
697     make_server(cptr);
698     cli_serv(cptr)->timestamp = timestamp;
699     cli_serv(cptr)->prot = prot;
700     cli_serv(cptr)->ghost = ghost;
701     SetServerYXX(cptr, cptr, parv[6]);
702     if (start_timestamp > OLDEST_TS)
703     {
704       Debug((DEBUG_DEBUG, "My start time: %Tu; other's start time: %Tu",
705              cli_serv(&me)->timestamp, start_timestamp));
706       Debug((DEBUG_DEBUG, "Receive time: %Tu; received timestamp: %Tu; "
707              "difference %ld", recv_time, timestamp, timestamp - recv_time));
708       if (feature_bool(FEAT_RELIABLE_CLOCK)) {
709         if (start_timestamp < cli_serv(&me)->timestamp)
710           cli_serv(&me)->timestamp = start_timestamp;
711         if (IsUnknown(cptr))
712           cli_serv(cptr)->timestamp = TStime();
713       } else {
714         if (start_timestamp < cli_serv(&me)->timestamp) {
715           sendto_opmask_butone(0, SNO_OLDSNO, "got earlier start time: "
716                                "%Tu < %Tu", start_timestamp,
717                                cli_serv(&me)->timestamp);
718           cli_serv(&me)->timestamp = start_timestamp;
719           TSoffset += timestamp - recv_time;
720           sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
721                                (int)(timestamp - recv_time));
722         } else if ((start_timestamp > cli_serv(&me)->timestamp) &&
723                  IsUnknown(cptr))
724           cli_serv(cptr)->timestamp = TStime();
725
726         else if (timestamp != recv_time) {
727           /*
728            * Equal start times, we have a collision.  Let the connected-to
729            * server decide. This assumes leafs issue more than half of the
730            * connection attempts.
731            */
732           if (IsUnknown(cptr))
733             cli_serv(cptr)->timestamp = TStime();
734           else if (IsHandshake(cptr)) {
735             sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
736                                  (int)(timestamp - recv_time));
737             TSoffset += timestamp - recv_time;
738           }
739         }
740       }
741     }
742
743     ret = server_estab(cptr, aconf);
744   }
745   else
746     ret = 0;
747
748   if (feature_bool(FEAT_RELIABLE_CLOCK) &&
749       abs(cli_serv(cptr)->timestamp - recv_time) > 30) {
750     sendto_opmask_butone(0, SNO_OLDSNO, "Connected to a net with a "
751                          "timestamp-clock difference of %Td seconds! "
752                          "Used SETTIME to correct this.",
753                          timestamp - recv_time);
754     sendcmdto_prio_one(&me, CMD_SETTIME, cptr, "%Tu :%s", TStime(),
755                        cli_name(&me));
756   }
757
758   return ret;
759 }
760
761 /*
762  * ms_server - server message handler
763  *
764  *    parv[0] = sender prefix
765  *    parv[1] = servername
766  *    parv[2] = hopcount
767  *    parv[3] = start timestamp
768  *    parv[4] = link timestamp
769  *    parv[5] = major protocol version: P09/P10
770  *    parv[parc-1] = serverinfo
771  *  If cptr is P10:
772  *    parv[6] = "YMM", where 'Y' is the server numeric and "MM" is the
773  *              numeric nick mask of this server.
774  *    parv[7] = +hs (h == hub, s == service)
775  */
776 int ms_server(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
777 {
778   char*            ch;
779   int              i;
780   char             info[REALLEN + 1];
781   char*            host;
782   struct Client*   acptr;
783   struct Client*   bcptr;
784   struct Client*   LHcptr = 0;
785   struct ConfItem* aconf = 0;
786   struct ConfItem* lhconf = 0;
787   int              hop;
788   int              ret;
789   int              active_lh_line = 0;
790   unsigned short   prot;
791   time_t           start_timestamp;
792   time_t           timestamp = 0;
793   time_t           recv_time;
794   time_t           ghost = 0;
795
796   if (IsUserPort(cptr))
797     return exit_client_msg(cptr, cptr, &me,
798                            "Cannot connect a server to a user port");
799
800   recv_time = TStime();
801   info[0] = '\0';
802   if (parc < 7)
803   {
804     return need_more_params(sptr, "SERVER");
805     return exit_client(cptr, cptr, &me, "Need more parameters");
806   }
807   host = parv[1];
808
809   /*
810    * Detect protocol
811    */
812   if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
813     return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
814
815   if (!IsServer(cptr))          /* Don't allow silently connecting a server */
816     *parv[5] = 'J';
817
818   if (*parv[7] == '+') {
819     for (ch = parv[7] + 1; *ch; ch++)
820       switch (*ch) {
821       case 'h':
822         SetHub(cptr);
823         break;
824       case 's':
825         SetService(cptr);
826         break;
827       }
828   }
829
830   prot = atoi(parv[5] + 1);
831   if (prot > atoi(MAJOR_PROTOCOL))
832     prot = atoi(MAJOR_PROTOCOL);
833   /*
834    * Because the previous test is only in 2.10, the following is needed
835    * till all servers are 2.10:
836    */
837   if (IsServer(cptr) && prot > Protocol(cptr))
838     prot = Protocol(cptr);
839   hop = atoi(parv[2]);
840   start_timestamp = atoi(parv[3]);
841   timestamp = atoi(parv[4]);
842   Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age %Tu (%Tu)",
843          host, parv[4], start_timestamp, cli_serv(&me)->timestamp));
844   if ((timestamp < OLDEST_TS || (hop == 1 && start_timestamp < OLDEST_TS)))
845   {
846     return exit_client_msg(cptr, sptr, &me,
847         "Bogus timestamps (%s %s)", parv[3], parv[4]);
848   }
849   ircd_strncpy(info, parv[parc - 1], REALLEN);
850   info[REALLEN] = '\0';
851   if (prot < atoi(MINOR_PROTOCOL)) {
852     sendto_opmask_butone(0, SNO_OLDSNO, "Got incompatible protocol version "
853                          "(%s) from %s", parv[5], cli_name(cptr));
854     return exit_new_server(cptr, sptr, host, timestamp,
855                            "Incompatible protocol: %s", parv[5]);
856   }
857   /*
858    * Check for "FRENCH " infection ;-) (actually this should
859    * be replaced with routine to check the hostname syntax in
860    * general). [ This check is still needed, even after the parse
861    * is fixed, because someone can send "SERVER :foo bar " ].
862    * Also, changed to check other "difficult" characters, now
863    * that parse lets all through... --msa
864    */
865   if (strlen(host) > HOSTLEN)
866     host[HOSTLEN] = '\0';
867   for (ch = host; *ch; ch++)
868     if (*ch <= ' ' || *ch > '~')
869       break;
870   if (*ch || !strchr(host, '.')) {
871     sendto_opmask_butone(0, SNO_OLDSNO, "Bogus server name (%s) from %s",
872                          host, cli_name(cptr));
873     return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
874   }
875
876   if (IsServer(cptr))
877   {
878     /*
879      * A local server introduces a new server behind this link.
880      * Check if this is allowed according L:, H: and Q: lines.
881      */
882     if (info[0] == '\0')
883       return exit_client_msg(cptr, cptr, &me,
884           "No server info specified for %s", host);
885     /*
886      * See if the newly found server is behind a guaranteed
887      * leaf (L-line). If so, close the link.
888      */
889     if ((lhconf = find_conf_byhost(cli_confs(cptr), cli_name(cptr), CONF_LEAF)) &&
890         (!lhconf->port || (hop > lhconf->port)))
891     {
892       /*
893        * L: lines normally come in pairs, here we try to
894        * make sure that the oldest link is squitted, not
895        * both.
896        */
897       active_lh_line = 1;
898       if (timestamp <= cli_serv(cptr)->timestamp)
899         LHcptr = 0;          /* Kill incoming server */
900       else
901         LHcptr = cptr;          /* Squit ourselfs */
902     }
903     else if (!(lhconf = find_conf_byname(cli_confs(cptr), cli_name(cptr), CONF_HUB)) ||
904              (lhconf->port && (hop > lhconf->port)))
905     {
906       struct Client *ac3ptr;
907       active_lh_line = 2;
908       /* Look for net junction causing this: */
909       LHcptr = 0;            /* incoming server */
910       if (*parv[5] != 'J') {
911         for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up) {
912           if (IsJunction(ac3ptr)) {
913             LHcptr = ac3ptr;
914             break;
915           }
916         }
917       }
918     }
919   }
920
921   if (IsUnknown(cptr) || IsHandshake(cptr))
922   {
923     const char* encr;
924
925     /*
926      * A local link that is still in undefined state wants
927      * to be a SERVER. Check if this is allowed and change
928      * status accordingly...
929      */
930     /*
931      * If there is more then one server on the same machine
932      * that we try to connect to, it could be that the /CONNECT
933      * <mask> caused this connect to be put at the wrong place
934      * in the hashtable.        --Run
935      * Same thing for Unknown connections that first send NICK.
936      *                          --Xorath
937      * Better check if the two strings are (caseless) identical 
938      * and not mess with hash internals. 
939      *                          --Nemesi
940      */
941     if ((!(EmptyString(cli_name(cptr))))
942         && (IsUnknown(cptr) || IsHandshake(cptr))
943         && 0 != ircd_strcmp(cli_name(cptr), host))
944       hChangeClient(cptr, host);
945     ircd_strncpy(cli_name(cptr), host, HOSTLEN);
946     ircd_strncpy(cli_info(cptr), info[0] ? info : cli_name(&me), REALLEN);
947     cli_hopcount(cptr) = hop;
948
949     /* check connection rules */
950     if (0 != conf_eval_crule(host, CRULE_ALL)) {
951       ServerStats->is_ref++;
952       sendto_opmask_butone(0, SNO_OLDSNO, "Refused connection from %s.", cli_name(cptr));
953       return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
954     }
955     if (conf_check_server(cptr)) {
956       ++ServerStats->is_ref;
957       sendto_opmask_butone(0, SNO_OLDSNO, "Received unauthorized connection "
958                            "from %s.", cli_name(cptr));
959       return exit_client(cptr, cptr, &me, "No C conf lines");
960     }
961
962     host = cli_name(cptr);
963
964     update_load();
965
966     if (!(aconf = find_conf_byname(cli_confs(cptr), host, CONF_SERVER))) {
967       ++ServerStats->is_ref;
968       sendto_opmask_butone(0, SNO_OLDSNO, "Access denied. No conf line for "
969                            "server %s", cli_name(cptr));
970       return exit_client_msg(cptr, cptr, &me,
971                              "Access denied. No conf line for server %s", cli_name(cptr));
972     }
973     encr = cli_passwd(cptr);
974
975     if (*(aconf->passwd) && !!strcmp(aconf->passwd, encr)) {
976       ++ServerStats->is_ref;
977       sendto_opmask_butone(0, SNO_OLDSNO, "Access denied (passwd mismatch) %s",
978                            cli_name(cptr));
979       return exit_client_msg(cptr, cptr, &me,
980                              "No Access (passwd mismatch) %s", cli_name(cptr));
981     }
982     memset(cli_passwd(cptr), 0, sizeof(cli_passwd(cptr)));
983
984     if (!feature_bool(FEAT_HUB)) {
985       for (i = 0; i <= HighestFd; i++)
986         if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
987           active_lh_line = 3;
988           LHcptr = 0;
989           break;
990         }
991     }
992   }
993
994   /*
995    *  We want to find IsConnecting() and IsHandshake() too,
996    *  use FindClient().
997    *  The second finds collisions with numeric representation of existing
998    *  servers - these shouldn't happen anymore when all upgraded to 2.10.
999    *  -- Run
1000    */
1001   while ((acptr = FindClient(host)) || 
1002          (parc > 7 && (acptr = FindNServer(parv[6]))))
1003   {
1004     /*
1005      *  This link is trying feed me a server that I already have
1006      *  access through another path
1007      *
1008      *  Do not allow Uworld to do this.
1009      *  Do not allow servers that are juped.
1010      *  Do not allow servers that have older link timestamps
1011      *    then this try.
1012      *  Do not allow servers that use the same numeric as an existing
1013      *    server, but have a different name.
1014      *
1015      *  If my ircd.conf sucks, I can try to connect to myself:
1016      */
1017     if (acptr == &me)
1018       return exit_client_msg(cptr, cptr, &me,
1019           "nick collision with me, check server number in M:? (%s)", host);
1020     /*
1021      * Detect wrong numeric.
1022      */
1023     if (0 != ircd_strcmp(cli_name(acptr), host))
1024     {
1025       sendcmdto_serv_butone(&me, CMD_WALLOPS, cptr,
1026                             ":SERVER Numeric Collision: %s != %s", cli_name(acptr),
1027                             host);
1028       return exit_client_msg(cptr, cptr, &me,
1029           "NUMERIC collision between %s and %s."
1030           " Is your server numeric correct ?", host, cli_name(acptr));
1031     }
1032     /*
1033      *  Kill our try, if we had one.
1034      */
1035     if (IsConnecting(acptr))
1036     {
1037       if (!active_lh_line && exit_client(cptr, acptr, &me,
1038           "Just connected via another link") == CPTR_KILLED)
1039         return CPTR_KILLED;
1040       /*
1041        * We can have only ONE 'IsConnecting', 'IsHandshake' or
1042        * 'IsServer', because new 'IsConnecting's are refused to
1043        * the same server if we already had it.
1044        */
1045       break;
1046     }
1047     /*
1048      * Avoid other nick collisions...
1049      * This is a doubtfull test though, what else would it be
1050      * when it has a server.name ?
1051      */
1052     else if (!IsServer(acptr) && !IsHandshake(acptr))
1053       return exit_client_msg(cptr, cptr, &me,
1054           "Nickname %s already exists!", host);
1055     /*
1056      * Our new server might be a juped server,
1057      * or someone trying abuse a second Uworld:
1058      */
1059     else if (IsServer(acptr) && (0 == ircd_strncmp(cli_info(acptr), "JUPE", 4) ||
1060         find_conf_byhost(cli_confs(cptr), cli_name(acptr), CONF_UWORLD)))
1061     {
1062       if (!IsServer(sptr))
1063         return exit_client(cptr, sptr, &me, cli_info(acptr));
1064       sendcmdto_one(&me, CMD_WALLOPS, cptr, ":Received :%s SERVER %s "
1065                     "from %s !?!", parv[0], parv[1], cli_name(cptr));
1066       return exit_new_server(cptr, sptr, host, timestamp, "%s", cli_info(acptr));
1067     }
1068     /*
1069      * Of course we find the handshake this link was before :)
1070      */
1071     else if (IsHandshake(acptr) && acptr == cptr)
1072       break;
1073     /*
1074      * Here we have a server nick collision...
1075      * We don't want to kill the link that was last /connected,
1076      * but we neither want to kill a good (old) link.
1077      * Therefor we kill the second youngest link.
1078      */
1079     if (1)
1080     {
1081       struct Client* c2ptr = 0;
1082       struct Client* c3ptr = acptr;
1083       struct Client* ac2ptr;
1084       struct Client* ac3ptr;
1085
1086       /* Search youngest link: */
1087       for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up)
1088         if (cli_serv(ac3ptr)->timestamp > cli_serv(c3ptr)->timestamp)
1089           c3ptr = ac3ptr;
1090       if (IsServer(sptr))
1091       {
1092         for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up)
1093           if (cli_serv(ac3ptr)->timestamp > cli_serv(c3ptr)->timestamp)
1094             c3ptr = ac3ptr;
1095       }
1096       if (timestamp > cli_serv(c3ptr)->timestamp)
1097       {
1098         c3ptr = 0;
1099         c2ptr = acptr;          /* Make sure they differ */
1100       }
1101       /* Search second youngest link: */
1102       for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = cli_serv(ac2ptr)->up)
1103         if (ac2ptr != c3ptr &&
1104             cli_serv(ac2ptr)->timestamp >
1105             (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
1106           c2ptr = ac2ptr;
1107       if (IsServer(sptr))
1108       {
1109         for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = cli_serv(ac2ptr)->up)
1110           if (ac2ptr != c3ptr &&
1111               cli_serv(ac2ptr)->timestamp >
1112               (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
1113             c2ptr = ac2ptr;
1114       }
1115       if (c3ptr && timestamp > (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
1116         c2ptr = 0;
1117       /* If timestamps are equal, decide which link to break
1118        *  by name.
1119        */
1120       if ((c2ptr ? cli_serv(c2ptr)->timestamp : timestamp) ==
1121           (c3ptr ? cli_serv(c3ptr)->timestamp : timestamp))
1122       {
1123         char* n2;
1124         char* n2up;
1125         char* n3;
1126         char* n3up;
1127         if (c2ptr)
1128         {
1129           n2 = cli_name(c2ptr);
1130           n2up = MyConnect(c2ptr) ? cli_name(&me) : cli_name(cli_serv(c2ptr)->up);
1131         }
1132         else
1133         {
1134           n2 = host;
1135           n2up = IsServer(sptr) ? cli_name(sptr) : cli_name(&me);
1136         }
1137         if (c3ptr)
1138         {
1139           n3 = cli_name(c3ptr);
1140           n3up = MyConnect(c3ptr) ? cli_name(&me) : cli_name(cli_serv(c3ptr)->up);
1141         }
1142         else
1143         {
1144           n3 = host;
1145           n3up = IsServer(sptr) ? cli_name(sptr) : cli_name(&me);
1146         }
1147         if (strcmp(n2, n2up) > 0)
1148           n2 = n2up;
1149         if (strcmp(n3, n3up) > 0)
1150           n3 = n3up;
1151         if (strcmp(n3, n2) > 0)
1152         {
1153           ac2ptr = c2ptr;
1154           c2ptr = c3ptr;
1155           c3ptr = ac2ptr;
1156         }
1157       }
1158       /* Now squit the second youngest link: */
1159       if (!c2ptr)
1160         return exit_new_server(cptr, sptr, host, timestamp,
1161             "server %s already exists and is %ld seconds younger.",
1162             host, (long)cli_serv(acptr)->timestamp - (long)timestamp);
1163       else if (cli_from(c2ptr) == cptr || IsServer(sptr))
1164       {
1165         struct Client *killedptrfrom = cli_from(c2ptr);
1166         if (active_lh_line)
1167         {
1168           /*
1169            * If the L: or H: line also gets rid of this link,
1170            * we sent just one squit.
1171            */
1172           if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
1173             break;
1174           /*
1175            * If breaking the loop here solves the L: or H:
1176            * line problem, we don't squit that.
1177            */
1178           if (cli_from(c2ptr) == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
1179             active_lh_line = 0;
1180           else
1181           {
1182             /*
1183              * If we still have a L: or H: line problem,
1184              * we prefer to squit the new server, solving
1185              * loop and L:/H: line problem with only one squit.
1186              */
1187             LHcptr = 0;
1188             break;
1189           }
1190         }
1191         /*
1192          * If the new server was introduced by a server that caused a
1193          * Ghost less then 20 seconds ago, this is probably also
1194          * a Ghost... (20 seconds is more then enough because all
1195          * SERVER messages are at the beginning of a net.burst). --Run
1196          */
1197         if (CurrentTime - cli_serv(cptr)->ghost < 20)
1198         {
1199           killedptrfrom = cli_from(acptr);
1200           if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
1201             return CPTR_KILLED;
1202         }
1203         else if (exit_client_msg(cptr, c2ptr, &me,
1204             "Loop <-- %s (new link is %ld seconds younger)", host,
1205             (c3ptr ? (long)cli_serv(c3ptr)->timestamp : timestamp) -
1206             (long)cli_serv(c2ptr)->timestamp) == CPTR_KILLED)
1207           return CPTR_KILLED;
1208         /*
1209          * Did we kill the incoming server off already ?
1210          */
1211         if (killedptrfrom == cptr)
1212           return 0;
1213       }
1214       else
1215       {
1216         if (active_lh_line)
1217         {
1218           if (LHcptr && a_kills_b_too(LHcptr, acptr))
1219             break;
1220           if (cli_from(acptr) == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
1221             active_lh_line = 0;
1222           else
1223           {
1224             LHcptr = 0;
1225             break;
1226           }
1227         }
1228         /*
1229          * We can't believe it is a lagged server message
1230          * when it directly connects to us...
1231          * kill the older link at the ghost, rather then
1232          * at the second youngest link, assuming it isn't
1233          * a REAL loop.
1234          */
1235         ghost = CurrentTime;            /* Mark that it caused a ghost */
1236         if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
1237           return CPTR_KILLED;
1238         break;
1239       }
1240     }
1241   }
1242
1243   if (active_lh_line)
1244   {
1245     if (LHcptr == 0) {
1246       return exit_new_server(cptr, sptr, host, timestamp,
1247           (active_lh_line == 2) ?  "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1248           cli_name(cptr), host,
1249           lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
1250     }
1251     else
1252     {
1253       int killed = a_kills_b_too(LHcptr, sptr);
1254       if (active_lh_line < 3)
1255       {
1256         if (exit_client_msg(cptr, LHcptr, &me,
1257             (active_lh_line == 2) ?  "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1258             cli_name(cptr), host,
1259             lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
1260           return CPTR_KILLED;
1261       }
1262       else
1263       {
1264         ServerStats->is_ref++;
1265         if (exit_client(cptr, LHcptr, &me, "I'm a leaf") == CPTR_KILLED)
1266           return CPTR_KILLED;
1267       }
1268       /*
1269        * Did we kill the incoming server off already ?
1270        */
1271       if (killed)
1272         return 0;
1273     }
1274   }
1275
1276   if (IsServer(cptr))
1277   {
1278     /*
1279      * Server is informing about a new server behind
1280      * this link. Create REMOTE server structure,
1281      * add it to list and propagate word to my other
1282      * server links...
1283      */
1284
1285     acptr = make_client(cptr, STAT_SERVER);
1286     make_server(acptr);
1287     cli_serv(acptr)->prot = prot;
1288     cli_serv(acptr)->timestamp = timestamp;
1289     cli_hopcount(acptr) = hop;
1290     ircd_strncpy(cli_name(acptr), host, HOSTLEN);
1291     ircd_strncpy(cli_info(acptr), info, REALLEN);
1292     cli_serv(acptr)->up = sptr;
1293     cli_serv(acptr)->updown = add_dlink(&(cli_serv(sptr))->down, acptr);
1294     /* Use cptr, because we do protocol 9 -> 10 translation
1295        for numeric nicks ! */
1296     SetServerYXX(cptr, acptr, parv[6]);
1297
1298     Count_newremoteserver(UserStats);
1299     if (Protocol(acptr) < 10)
1300       cli_flags(acptr) |= FLAGS_TS8;
1301     add_client_to_list(acptr);
1302     hAddClient(acptr);
1303     if (*parv[5] == 'J')
1304     {
1305       SetBurst(acptr);
1306       sendto_opmask_butone(0, SNO_NETWORK, "Net junction: %s %s",
1307                            cli_name(sptr), cli_name(acptr));
1308       SetJunction(acptr);
1309     }
1310     /*
1311      * Old sendto_serv_but_one() call removed because we now need to send
1312      * different names to different servers (domain name matching).
1313      */
1314     for (i = 0; i <= HighestFd; i++)
1315     {
1316       if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
1317           bcptr == cptr || IsMe(bcptr))
1318         continue;
1319       if (0 == match(cli_name(&me), cli_name(acptr)))
1320         continue;
1321       sendcmdto_one(sptr, CMD_SERVER, bcptr, "%s %d 0 %s %s %s%s +%s%s :%s",
1322                     cli_name(acptr), hop + 1, parv[4], parv[5],
1323                     NumServCap(acptr), IsHub(acptr) ? "h" : "",
1324                     IsService(acptr) ? "s" : "", cli_info(acptr));
1325     }
1326     return 0;
1327   }
1328
1329   if (IsUnknown(cptr) || IsHandshake(cptr))
1330   {
1331     make_server(cptr);
1332     cli_serv(cptr)->timestamp = timestamp;
1333     cli_serv(cptr)->prot = prot;
1334     cli_serv(cptr)->ghost = ghost;
1335     SetServerYXX(cptr, cptr, parv[6]);
1336     if (start_timestamp > OLDEST_TS)
1337     {
1338       Debug((DEBUG_DEBUG, "My start time: %Tu; other's start time: %Tu",
1339              cli_serv(&me)->timestamp, start_timestamp));
1340       Debug((DEBUG_DEBUG, "Receive time: %Tu; received timestamp: %Tu; "
1341              "difference %ld", recv_time, timestamp, timestamp - recv_time));
1342       if (feature_bool(FEAT_RELIABLE_CLOCK)) {
1343         if (start_timestamp < cli_serv(&me)->timestamp)
1344           cli_serv(&me)->timestamp = start_timestamp;
1345         if (IsUnknown(cptr))
1346           cli_serv(cptr)->timestamp = TStime();
1347       } else {
1348         if (start_timestamp < cli_serv(&me)->timestamp) {
1349           sendto_opmask_butone(0, SNO_OLDSNO, "got earlier start time: "
1350                                "%Tu < %Tu", start_timestamp,
1351                                cli_serv(&me)->timestamp);
1352           cli_serv(&me)->timestamp = start_timestamp;
1353           TSoffset += timestamp - recv_time;
1354           sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
1355                                (int)(timestamp - recv_time));
1356         } else if ((start_timestamp > cli_serv(&me)->timestamp) &&
1357                    IsUnknown(cptr))
1358           cli_serv(cptr)->timestamp = TStime();
1359
1360         else if (timestamp != recv_time) {
1361           /*
1362            * Equal start times, we have a collision.  Let the connected-to
1363            * server decide. This assumes leafs issue more than half of the
1364            * connection attempts.
1365            */
1366           if (IsUnknown(cptr))
1367             cli_serv(cptr)->timestamp = TStime();
1368           else if (IsHandshake(cptr)) {
1369             sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
1370                                  (int)(timestamp - recv_time));
1371             TSoffset += timestamp - recv_time;
1372           }
1373         }
1374       }
1375     }
1376
1377     ret = server_estab(cptr, aconf);
1378   }
1379   else
1380     ret = 0;
1381
1382   if (feature_bool(FEAT_RELIABLE_CLOCK) &&
1383       abs(cli_serv(cptr)->timestamp - recv_time) > 30) {
1384     sendto_opmask_butone(0, SNO_OLDSNO, "Connected to a net with a "
1385                          "timestamp-clock difference of %Td seconds! Used "
1386                          "SETTIME to correct this.", timestamp - recv_time);
1387     sendcmdto_prio_one(&me, CMD_SETTIME, cptr, "%Tu :%s", TStime(),
1388                        cli_name(&me));
1389   }
1390
1391   return ret;
1392 }