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, ajupe);
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  *    parv[8] = %<lastmod> - optional parameter only present if there's an
770  *              outstanding JUPE; specifies the JUPE's lastmod field
771  */
772 int ms_server(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
773 {
774   char*            ch;
775   int              i;
776   char             info[REALLEN + 1];
777   char*            host;
778   struct Client*   acptr;
779   struct Client*   bcptr;
780   struct Client*   LHcptr = 0;
781   struct ConfItem* aconf = 0;
782   struct ConfItem* lhconf = 0;
783   struct Jupe*     ajupe = 0;
784   int              hop;
785   int              ret;
786   int              active_lh_line = 0;
787   unsigned short   prot;
788   time_t           start_timestamp;
789   time_t           timestamp = 0;
790   time_t           recv_time;
791   time_t           ghost = 0;
792   time_t           lastmod = 0;
793
794   if (IsUserPort(cptr))
795     return exit_client_msg(cptr, cptr, &me,
796                            "Cannot connect a server to a user port");
797
798   recv_time = TStime();
799   info[0] = '\0';
800   if (parc < 7)
801   {
802     return need_more_params(sptr, "SERVER");
803     return exit_client(cptr, cptr, &me, "Need more parameters");
804   }
805   host = parv[1];
806
807   /*
808    * Detect protocol
809    */
810   if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
811     return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
812
813   if (!IsServer(cptr))          /* Don't allow silently connecting a server */
814     *parv[5] = 'J';
815
816   prot = atoi(parv[5] + 1);
817   if (prot > atoi(MAJOR_PROTOCOL))
818     prot = atoi(MAJOR_PROTOCOL);
819   /*
820    * Because the previous test is only in 2.10, the following is needed
821    * till all servers are 2.10:
822    */
823   if (IsServer(cptr) && prot > Protocol(cptr))
824     prot = Protocol(cptr);
825   hop = atoi(parv[2]);
826   start_timestamp = atoi(parv[3]);
827   timestamp = atoi(parv[4]);
828   Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age %Tu (%Tu)",
829          host, parv[4], start_timestamp, cli_serv(&me)->timestamp));
830   if ((timestamp < OLDEST_TS || (hop == 1 && start_timestamp < OLDEST_TS)))
831   {
832     return exit_client_msg(cptr, sptr, &me,
833         "Bogus timestamps (%s %s)", parv[3], parv[4]);
834   }
835   ircd_strncpy(info, parv[parc - 1], REALLEN);
836   info[REALLEN] = '\0';
837   if (prot < atoi(MINOR_PROTOCOL)) {
838     sendto_opmask_butone(0, SNO_OLDSNO, "Got incompatible protocol version "
839                          "(%s) from %s", parv[5], cli_name(cptr));
840     return exit_new_server(cptr, sptr, host, timestamp,
841                            "Incompatible protocol: %s", parv[5]);
842   }
843   if (parc > 9 && *parv[8] == '%')
844     lastmod = atoi(parv[8] + 1);
845   /* If there's a jupe that matches, and it's a global jupe, and the
846    * introducer didn't indicate it knew of the jupe or has an older
847    * version of the jupe, and the connection isn't in a BURST, resynch
848    * the jupe.
849    */
850   if ((ajupe = jupe_find(host)) && !JupeIsLocal(ajupe) &&
851       JupeLastMod(ajupe) > lastmod && !IsBurstOrBurstAck(cptr))
852     jupe_resend(cptr, ajupe);
853   /*
854    * Check for "FRENCH " infection ;-) (actually this should
855    * be replaced with routine to check the hostname syntax in
856    * general). [ This check is still needed, even after the parse
857    * is fixed, because someone can send "SERVER :foo bar " ].
858    * Also, changed to check other "difficult" characters, now
859    * that parse lets all through... --msa
860    */
861   if (strlen(host) > HOSTLEN)
862     host[HOSTLEN] = '\0';
863   for (ch = host; *ch; ch++)
864     if (*ch <= ' ' || *ch > '~')
865       break;
866   if (*ch || !strchr(host, '.')) {
867     sendto_opmask_butone(0, SNO_OLDSNO, "Bogus server name (%s) from %s",
868                          host, cli_name(cptr));
869     return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
870   }
871
872   if (IsServer(cptr))
873   {
874     /*
875      * A local server introduces a new server behind this link.
876      * Check if this is allowed according L:, H: and Q: lines.
877      */
878     if (info[0] == '\0')
879       return exit_client_msg(cptr, cptr, &me,
880           "No server info specified for %s", host);
881     /*
882      * See if the newly found server is behind a guaranteed
883      * leaf (L-line). If so, close the link.
884      */
885     if ((lhconf = find_conf_byhost(cli_confs(cptr), cli_name(cptr), CONF_LEAF)) &&
886         (!lhconf->port || (hop > lhconf->port)))
887     {
888       /*
889        * L: lines normally come in pairs, here we try to
890        * make sure that the oldest link is squitted, not
891        * both.
892        */
893       active_lh_line = 1;
894       if (timestamp <= cli_serv(cptr)->timestamp)
895         LHcptr = 0;          /* Kill incoming server */
896       else
897         LHcptr = cptr;          /* Squit ourselfs */
898     }
899     else if (!(lhconf = find_conf_byname(cli_confs(cptr), cli_name(cptr), CONF_HUB)) ||
900              (lhconf->port && (hop > lhconf->port)))
901     {
902       struct Client *ac3ptr;
903       active_lh_line = 2;
904       /* Look for net junction causing this: */
905       LHcptr = 0;            /* incoming server */
906       if (*parv[5] != 'J') {
907         for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up) {
908           if (IsJunction(ac3ptr)) {
909             LHcptr = ac3ptr;
910             break;
911           }
912         }
913       }
914     }
915   }
916
917   if (IsUnknown(cptr) || IsHandshake(cptr))
918   {
919     const char* encr;
920
921     /*
922      * A local link that is still in undefined state wants
923      * to be a SERVER. Check if this is allowed and change
924      * status accordingly...
925      */
926     /*
927      * If there is more then one server on the same machine
928      * that we try to connect to, it could be that the /CONNECT
929      * <mask> caused this connect to be put at the wrong place
930      * in the hashtable.        --Run
931      * Same thing for Unknown connections that first send NICK.
932      *                          --Xorath
933      * Better check if the two strings are (caseless) identical 
934      * and not mess with hash internals. 
935      *                          --Nemesi
936      */
937     if ((!(EmptyString(cli_name(cptr))))
938         && (IsUnknown(cptr) || IsHandshake(cptr))
939         && 0 != ircd_strcmp(cli_name(cptr), host))
940       hChangeClient(cptr, host);
941     ircd_strncpy(cli_name(cptr), host, HOSTLEN);
942     ircd_strncpy(cli_info(cptr), info[0] ? info : cli_name(&me), REALLEN);
943     cli_hopcount(cptr) = hop;
944
945     /* check connection rules */
946     if (0 != conf_eval_crule(host, CRULE_ALL)) {
947       ServerStats->is_ref++;
948       sendto_opmask_butone(0, SNO_OLDSNO, "Refused connection from %s.", cli_name(cptr));
949       return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
950     }
951     if (conf_check_server(cptr)) {
952       ++ServerStats->is_ref;
953       sendto_opmask_butone(0, SNO_OLDSNO, "Received unauthorized connection "
954                            "from %s.", cli_name(cptr));
955       return exit_client(cptr, cptr, &me, "No C conf lines");
956     }
957
958     host = cli_name(cptr);
959
960     update_load();
961
962     if (!(aconf = find_conf_byname(cli_confs(cptr), host, CONF_SERVER))) {
963       ++ServerStats->is_ref;
964       sendto_opmask_butone(0, SNO_OLDSNO, "Access denied. No conf line for "
965                            "server %s", cli_name(cptr));
966       return exit_client_msg(cptr, cptr, &me,
967                              "Access denied. No conf line for server %s", cli_name(cptr));
968     }
969     encr = cli_passwd(cptr);
970
971     if (*(aconf->passwd) && !!strcmp(aconf->passwd, encr)) {
972       ++ServerStats->is_ref;
973       sendto_opmask_butone(0, SNO_OLDSNO, "Access denied (passwd mismatch) %s",
974                            cli_name(cptr));
975       return exit_client_msg(cptr, cptr, &me,
976                              "No Access (passwd mismatch) %s", cli_name(cptr));
977     }
978     memset(cli_passwd(cptr), 0, sizeof(cli_passwd(cptr)));
979
980     if (!feature_bool(FEAT_HUB)) {
981       for (i = 0; i <= HighestFd; i++)
982         if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
983           active_lh_line = 3;
984           LHcptr = 0;
985           break;
986         }
987     }
988   }
989
990   /*
991    *  We want to find IsConnecting() and IsHandshake() too,
992    *  use FindClient().
993    *  The second finds collisions with numeric representation of existing
994    *  servers - these shouldn't happen anymore when all upgraded to 2.10.
995    *  -- Run
996    */
997   while ((acptr = FindClient(host)) || 
998          (parc > 7 && (acptr = FindNServer(parv[6]))))
999   {
1000     /*
1001      *  This link is trying feed me a server that I already have
1002      *  access through another path
1003      *
1004      *  Do not allow Uworld to do this.
1005      *  Do not allow servers that are juped.
1006      *  Do not allow servers that have older link timestamps
1007      *    then this try.
1008      *  Do not allow servers that use the same numeric as an existing
1009      *    server, but have a different name.
1010      *
1011      *  If my ircd.conf sucks, I can try to connect to myself:
1012      */
1013     if (acptr == &me)
1014       return exit_client_msg(cptr, cptr, &me,
1015           "nick collision with me, check server number in M:? (%s)", host);
1016     /*
1017      * Detect wrong numeric.
1018      */
1019     if (0 != ircd_strcmp(cli_name(acptr), host))
1020     {
1021       sendcmdto_serv_butone(&me, CMD_WALLOPS, cptr,
1022                             ":SERVER Numeric Collision: %s != %s", cli_name(acptr),
1023                             host);
1024       return exit_client_msg(cptr, cptr, &me,
1025           "NUMERIC collision between %s and %s."
1026           " Is your server numeric correct ?", host, cli_name(acptr));
1027     }
1028     /*
1029      *  Kill our try, if we had one.
1030      */
1031     if (IsConnecting(acptr))
1032     {
1033       if (!active_lh_line && exit_client(cptr, acptr, &me,
1034           "Just connected via another link") == CPTR_KILLED)
1035         return CPTR_KILLED;
1036       /*
1037        * We can have only ONE 'IsConnecting', 'IsHandshake' or
1038        * 'IsServer', because new 'IsConnecting's are refused to
1039        * the same server if we already had it.
1040        */
1041       break;
1042     }
1043     /*
1044      * Avoid other nick collisions...
1045      * This is a doubtfull test though, what else would it be
1046      * when it has a server.name ?
1047      */
1048     else if (!IsServer(acptr) && !IsHandshake(acptr))
1049       return exit_client_msg(cptr, cptr, &me,
1050           "Nickname %s already exists!", host);
1051     /*
1052      * Our new server might be a juped server,
1053      * or someone trying abuse a second Uworld:
1054      */
1055     else if (IsServer(acptr) && (0 == ircd_strncmp(cli_info(acptr), "JUPE", 4) ||
1056         find_conf_byhost(cli_confs(cptr), cli_name(acptr), CONF_UWORLD)))
1057     {
1058       if (!IsServer(sptr))
1059         return exit_client(cptr, sptr, &me, cli_info(acptr));
1060       sendcmdto_one(&me, CMD_WALLOPS, cptr, ":Received :%s SERVER %s "
1061                     "from %s !?!", parv[0], parv[1], cli_name(cptr));
1062       return exit_new_server(cptr, sptr, host, timestamp, "%s", cli_info(acptr));
1063     }
1064     /*
1065      * Of course we find the handshake this link was before :)
1066      */
1067     else if (IsHandshake(acptr) && acptr == cptr)
1068       break;
1069     /*
1070      * Here we have a server nick collision...
1071      * We don't want to kill the link that was last /connected,
1072      * but we neither want to kill a good (old) link.
1073      * Therefor we kill the second youngest link.
1074      */
1075     if (1)
1076     {
1077       struct Client* c2ptr = 0;
1078       struct Client* c3ptr = acptr;
1079       struct Client* ac2ptr;
1080       struct Client* ac3ptr;
1081
1082       /* Search youngest link: */
1083       for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up)
1084         if (cli_serv(ac3ptr)->timestamp > cli_serv(c3ptr)->timestamp)
1085           c3ptr = ac3ptr;
1086       if (IsServer(sptr))
1087       {
1088         for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up)
1089           if (cli_serv(ac3ptr)->timestamp > cli_serv(c3ptr)->timestamp)
1090             c3ptr = ac3ptr;
1091       }
1092       if (timestamp > cli_serv(c3ptr)->timestamp)
1093       {
1094         c3ptr = 0;
1095         c2ptr = acptr;          /* Make sure they differ */
1096       }
1097       /* Search second youngest link: */
1098       for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = cli_serv(ac2ptr)->up)
1099         if (ac2ptr != c3ptr &&
1100             cli_serv(ac2ptr)->timestamp >
1101             (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
1102           c2ptr = ac2ptr;
1103       if (IsServer(sptr))
1104       {
1105         for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = cli_serv(ac2ptr)->up)
1106           if (ac2ptr != c3ptr &&
1107               cli_serv(ac2ptr)->timestamp >
1108               (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
1109             c2ptr = ac2ptr;
1110       }
1111       if (c3ptr && timestamp > (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
1112         c2ptr = 0;
1113       /* If timestamps are equal, decide which link to break
1114        *  by name.
1115        */
1116       if ((c2ptr ? cli_serv(c2ptr)->timestamp : timestamp) ==
1117           (c3ptr ? cli_serv(c3ptr)->timestamp : timestamp))
1118       {
1119         char* n2;
1120         char* n2up;
1121         char* n3;
1122         char* n3up;
1123         if (c2ptr)
1124         {
1125           n2 = cli_name(c2ptr);
1126           n2up = MyConnect(c2ptr) ? cli_name(&me) : cli_name(cli_serv(c2ptr)->up);
1127         }
1128         else
1129         {
1130           n2 = host;
1131           n2up = IsServer(sptr) ? cli_name(sptr) : cli_name(&me);
1132         }
1133         if (c3ptr)
1134         {
1135           n3 = cli_name(c3ptr);
1136           n3up = MyConnect(c3ptr) ? cli_name(&me) : cli_name(cli_serv(c3ptr)->up);
1137         }
1138         else
1139         {
1140           n3 = host;
1141           n3up = IsServer(sptr) ? cli_name(sptr) : cli_name(&me);
1142         }
1143         if (strcmp(n2, n2up) > 0)
1144           n2 = n2up;
1145         if (strcmp(n3, n3up) > 0)
1146           n3 = n3up;
1147         if (strcmp(n3, n2) > 0)
1148         {
1149           ac2ptr = c2ptr;
1150           c2ptr = c3ptr;
1151           c3ptr = ac2ptr;
1152         }
1153       }
1154       /* Now squit the second youngest link: */
1155       if (!c2ptr)
1156         return exit_new_server(cptr, sptr, host, timestamp,
1157             "server %s already exists and is %ld seconds younger.",
1158             host, (long)cli_serv(acptr)->timestamp - (long)timestamp);
1159       else if (cli_from(c2ptr) == cptr || IsServer(sptr))
1160       {
1161         struct Client *killedptrfrom = cli_from(c2ptr);
1162         if (active_lh_line)
1163         {
1164           /*
1165            * If the L: or H: line also gets rid of this link,
1166            * we sent just one squit.
1167            */
1168           if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
1169             break;
1170           /*
1171            * If breaking the loop here solves the L: or H:
1172            * line problem, we don't squit that.
1173            */
1174           if (cli_from(c2ptr) == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
1175             active_lh_line = 0;
1176           else
1177           {
1178             /*
1179              * If we still have a L: or H: line problem,
1180              * we prefer to squit the new server, solving
1181              * loop and L:/H: line problem with only one squit.
1182              */
1183             LHcptr = 0;
1184             break;
1185           }
1186         }
1187         /*
1188          * If the new server was introduced by a server that caused a
1189          * Ghost less then 20 seconds ago, this is probably also
1190          * a Ghost... (20 seconds is more then enough because all
1191          * SERVER messages are at the beginning of a net.burst). --Run
1192          */
1193         if (CurrentTime - cli_serv(cptr)->ghost < 20)
1194         {
1195           killedptrfrom = cli_from(acptr);
1196           if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
1197             return CPTR_KILLED;
1198         }
1199         else if (exit_client_msg(cptr, c2ptr, &me,
1200             "Loop <-- %s (new link is %ld seconds younger)", host,
1201             (c3ptr ? (long)cli_serv(c3ptr)->timestamp : timestamp) -
1202             (long)cli_serv(c2ptr)->timestamp) == CPTR_KILLED)
1203           return CPTR_KILLED;
1204         /*
1205          * Did we kill the incoming server off already ?
1206          */
1207         if (killedptrfrom == cptr)
1208           return 0;
1209       }
1210       else
1211       {
1212         if (active_lh_line)
1213         {
1214           if (LHcptr && a_kills_b_too(LHcptr, acptr))
1215             break;
1216           if (cli_from(acptr) == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
1217             active_lh_line = 0;
1218           else
1219           {
1220             LHcptr = 0;
1221             break;
1222           }
1223         }
1224         /*
1225          * We can't believe it is a lagged server message
1226          * when it directly connects to us...
1227          * kill the older link at the ghost, rather then
1228          * at the second youngest link, assuming it isn't
1229          * a REAL loop.
1230          */
1231         ghost = CurrentTime;            /* Mark that it caused a ghost */
1232         if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
1233           return CPTR_KILLED;
1234         break;
1235       }
1236     }
1237   }
1238
1239   if (active_lh_line)
1240   {
1241     if (LHcptr == 0) {
1242       return exit_new_server(cptr, sptr, host, timestamp,
1243           (active_lh_line == 2) ?  "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1244           cli_name(cptr), host,
1245           lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
1246     }
1247     else
1248     {
1249       int killed = a_kills_b_too(LHcptr, sptr);
1250       if (active_lh_line < 3)
1251       {
1252         if (exit_client_msg(cptr, LHcptr, &me,
1253             (active_lh_line == 2) ?  "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1254             cli_name(cptr), host,
1255             lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
1256           return CPTR_KILLED;
1257       }
1258       else
1259       {
1260         ServerStats->is_ref++;
1261         if (exit_client(cptr, LHcptr, &me, "I'm a leaf") == CPTR_KILLED)
1262           return CPTR_KILLED;
1263       }
1264       /*
1265        * Did we kill the incoming server off already ?
1266        */
1267       if (killed)
1268         return 0;
1269     }
1270   }
1271
1272   if (IsServer(cptr))
1273   {
1274     /*
1275      * Server is informing about a new server behind
1276      * this link. Create REMOTE server structure,
1277      * add it to list and propagate word to my other
1278      * server links...
1279      */
1280
1281     acptr = make_client(cptr, STAT_SERVER);
1282     make_server(acptr);
1283     cli_serv(acptr)->prot = prot;
1284     cli_serv(acptr)->timestamp = timestamp;
1285     cli_hopcount(acptr) = hop;
1286     ircd_strncpy(cli_name(acptr), host, HOSTLEN);
1287     ircd_strncpy(cli_info(acptr), info, REALLEN);
1288     cli_serv(acptr)->up = sptr;
1289     cli_serv(acptr)->updown = add_dlink(&(cli_serv(sptr))->down, acptr);
1290     /* Use cptr, because we do protocol 9 -> 10 translation
1291        for numeric nicks ! */
1292     SetServerYXX(cptr, acptr, parv[6]);
1293
1294     Count_newremoteserver(UserStats);
1295     if (Protocol(acptr) < 10)
1296       cli_flags(acptr) |= FLAGS_TS8;
1297     add_client_to_list(acptr);
1298     hAddClient(acptr);
1299     if (*parv[5] == 'J')
1300     {
1301       SetBurst(acptr);
1302       sendto_opmask_butone(0, SNO_NETWORK, "Net junction: %s %s",
1303                            cli_name(sptr), cli_name(acptr));
1304       SetJunction(acptr);
1305     }
1306     /*
1307      * Old sendto_serv_but_one() call removed because we now need to send
1308      * different names to different servers (domain name matching).
1309      */
1310     for (i = 0; i <= HighestFd; i++)
1311     {
1312       if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
1313           bcptr == cptr || IsMe(bcptr))
1314         continue;
1315       if (0 == match(cli_name(&me), cli_name(acptr)))
1316         continue;
1317       sendcmdto_one(sptr, CMD_SERVER, bcptr, "%s %d 0 %s %s %s%s 0 :%s",
1318                     cli_name(acptr), hop + 1, parv[4], parv[5], NumServCap(acptr),
1319                     cli_info(acptr));
1320     }
1321     return 0;
1322   }
1323
1324   if (IsUnknown(cptr) || IsHandshake(cptr))
1325   {
1326     make_server(cptr);
1327     cli_serv(cptr)->timestamp = timestamp;
1328     cli_serv(cptr)->prot = prot;
1329     cli_serv(cptr)->ghost = ghost;
1330     SetServerYXX(cptr, cptr, parv[6]);
1331     if (start_timestamp > OLDEST_TS)
1332     {
1333       Debug((DEBUG_DEBUG, "My start time: %Tu; other's start time: %Tu",
1334              cli_serv(&me)->timestamp, start_timestamp));
1335       Debug((DEBUG_DEBUG, "Receive time: %Tu; received timestamp: %Tu; "
1336              "difference %ld", recv_time, timestamp, timestamp - recv_time));
1337       if (feature_bool(FEAT_RELIABLE_CLOCK)) {
1338         if (start_timestamp < cli_serv(&me)->timestamp)
1339           cli_serv(&me)->timestamp = start_timestamp;
1340         if (IsUnknown(cptr))
1341           cli_serv(cptr)->timestamp = TStime();
1342       } else {
1343         if (start_timestamp < cli_serv(&me)->timestamp) {
1344           sendto_opmask_butone(0, SNO_OLDSNO, "got earlier start time: "
1345                                "%Tu < %Tu", start_timestamp,
1346                                cli_serv(&me)->timestamp);
1347           cli_serv(&me)->timestamp = start_timestamp;
1348           TSoffset += timestamp - recv_time;
1349           sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
1350                                (int)(timestamp - recv_time));
1351         } else if ((start_timestamp > cli_serv(&me)->timestamp) &&
1352                    IsUnknown(cptr))
1353           cli_serv(cptr)->timestamp = TStime();
1354
1355         else if (timestamp != recv_time) {
1356           /*
1357            * Equal start times, we have a collision.  Let the connected-to
1358            * server decide. This assumes leafs issue more than half of the
1359            * connection attempts.
1360            */
1361           if (IsUnknown(cptr))
1362             cli_serv(cptr)->timestamp = TStime();
1363           else if (IsHandshake(cptr)) {
1364             sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d",
1365                                  (int)(timestamp - recv_time));
1366             TSoffset += timestamp - recv_time;
1367           }
1368         }
1369       }
1370     }
1371
1372     ret = server_estab(cptr, aconf, ajupe);
1373   }
1374   else
1375     ret = 0;
1376
1377   if (feature_bool(FEAT_RELIABLE_CLOCK) &&
1378       abs(cli_serv(cptr)->timestamp - recv_time) > 30) {
1379     sendto_opmask_butone(0, SNO_OLDSNO, "Connected to a net with a "
1380                          "timestamp-clock difference of %Td seconds! Used "
1381                          "SETTIME to correct this.", timestamp - recv_time);
1382     sendcmdto_one(&me, CMD_SETTIME, cptr, "%Tu :%s", TStime(), cli_name(&me));
1383   }
1384
1385   return ret;
1386 }
1387
1388
1389 #if 0
1390 /*
1391  *  m_server
1392  *
1393  *    parv[0] = sender prefix
1394  *    parv[1] = servername
1395  *    parv[2] = hopcount
1396  *    parv[3] = start timestamp
1397  *    parv[4] = link timestamp
1398  *    parv[5] = major protocol version: P09/P10
1399  *    parv[parc-1] = serverinfo
1400  *  If cptr is P10:
1401  *    parv[6] = "YMM", where 'Y' is the server numeric and "MM" is the
1402  *              numeric nick mask of this server.
1403  *    parv[7] = 0 (not used yet, mandatory unsigned int after u2.10.06)
1404  */
1405 int m_server(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
1406 {
1407   char*            ch;
1408   int              i;
1409   char             info[REALLEN + 1];
1410   char*            host;
1411   struct Client*   acptr;
1412   struct Client*   bcptr;
1413   struct Client*   LHcptr = 0;
1414   struct ConfItem* aconf = 0;
1415   struct ConfItem* lhconf = 0;
1416   struct Jupe*     ajupe = 0;
1417   int              hop;
1418   int              ret;
1419   int              active_lh_line = 0;
1420   unsigned short   prot;
1421   time_t           start_timestamp;
1422   time_t           timestamp = 0;
1423   time_t           recv_time;
1424   time_t           ghost = 0;
1425
1426   if (IsUser(cptr))
1427   {
1428     sendto_one(cptr, err_str(ERR_ALREADYREGISTRED), me.name, parv[0]); /* XXX DEAD */
1429     return 0;
1430   }
1431
1432   if (IsUserPort(cptr))
1433     return exit_client_msg(cptr, cptr, &me,
1434         "You cannot connect a server to a user port; connect to %s port %u",
1435         me.name, server_port);
1436
1437   recv_time = TStime();
1438   info[0] = '\0';
1439   if (parc < 7)
1440   {
1441     return need_more_params(sptr, "SERVER");
1442     return exit_client(cptr, cptr, &me, "Need more parameters");
1443   }
1444   host = parv[1];
1445   /*
1446    * Detect protocol
1447    */
1448   if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
1449     return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
1450
1451   if (!IsServer(cptr))          /* Don't allow silently connecting a server */
1452     *parv[5] = 'J';
1453
1454   prot = atoi(parv[5] + 1);
1455   if (prot > atoi(MAJOR_PROTOCOL))
1456     prot = atoi(MAJOR_PROTOCOL);
1457   /*
1458    * Because the previous test is only in 2.10, the following is needed
1459    * till all servers are 2.10:
1460    */
1461   if (IsServer(cptr) && prot > Protocol(cptr))
1462     prot = Protocol(cptr);
1463   hop = atoi(parv[2]);
1464   start_timestamp = atoi(parv[3]);
1465   timestamp = atoi(parv[4]);
1466   Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age " TIME_T_FMT " ("
1467       TIME_T_FMT ")", host, parv[4], start_timestamp, me.serv->timestamp));
1468   if ((timestamp < OLDEST_TS || (hop == 1 && start_timestamp < OLDEST_TS)))
1469   {
1470     return exit_client_msg(cptr, sptr, &me,
1471         "Bogus timestamps (%s %s)", parv[3], parv[4]);
1472   }
1473   ircd_strncpy(info, parv[parc - 1], REALLEN);
1474   info[REALLEN] = '\0';
1475   if (prot < atoi(MINOR_PROTOCOL)) {
1476     sendto_ops("Got incompatible protocol version (%s) from %s", /* XXX DEAD */
1477                parv[5], cptr->name);
1478     return exit_new_server(cptr, sptr, host, timestamp,
1479         "Incompatible protocol: %s", parv[5]);
1480   }
1481   /*
1482    * Check for "FRENCH " infection ;-) (actually this should
1483    * be replaced with routine to check the hostname syntax in
1484    * general). [ This check is still needed, even after the parse
1485    * is fixed, because someone can send "SERVER :foo bar " ].
1486    * Also, changed to check other "difficult" characters, now
1487    * that parse lets all through... --msa
1488    */
1489   if (strlen(host) > HOSTLEN)
1490     host[HOSTLEN] = '\0';
1491   for (ch = host; *ch; ch++)
1492     if (*ch <= ' ' || *ch > '~')
1493       break;
1494   if (*ch || !strchr(host, '.'))
1495   {
1496     sendto_ops("Bogus server name (%s) from %s", host, cptr->name); /* XXX DEAD */
1497     return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
1498   }
1499
1500   if (IsServer(cptr))
1501   {
1502     /*
1503      * A local server introduces a new server behind this link.
1504      * Check if this is allowed according L:, H: and Q: lines.
1505      */
1506     if (info[0] == '\0')
1507       return exit_client_msg(cptr, cptr, &me,
1508           "No server info specified for %s", host);
1509     /*
1510      * See if the newly found server is behind a guaranteed
1511      * leaf (L-line). If so, close the link.
1512      */
1513     if ((lhconf = find_conf_byhost(cptr->confs, cptr->name, CONF_LEAF)) &&
1514         (!lhconf->port || (hop > lhconf->port)))
1515     {
1516       /*
1517        * L: lines normally come in pairs, here we try to
1518        * make sure that the oldest link is squitted, not
1519        * both.
1520        */
1521       active_lh_line = 1;
1522       if (timestamp <= cptr->serv->timestamp)
1523         LHcptr = 0;          /* Kill incoming server */
1524       else
1525         LHcptr = cptr;          /* Squit ourselfs */
1526     }
1527     else if (!(lhconf = find_conf_byname(cptr->confs, cptr->name, CONF_HUB)) ||
1528              (lhconf->port && (hop > lhconf->port)))
1529     {
1530       struct Client *ac3ptr;
1531       active_lh_line = 2;
1532       /* Look for net junction causing this: */
1533       LHcptr = 0;            /* incoming server */
1534       if (*parv[5] != 'J') {
1535         for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up) {
1536           if (IsJunction(ac3ptr)) {
1537             LHcptr = ac3ptr;
1538             break;
1539           }
1540         }
1541       }
1542     }
1543   }
1544
1545   if (IsUnknown(cptr) || IsHandshake(cptr))
1546   {
1547     const char* encr;
1548
1549     /*
1550      * A local link that is still in undefined state wants
1551      * to be a SERVER. Check if this is allowed and change
1552      * status accordingly...
1553      */
1554     /*
1555      * If there is more then one server on the same machine
1556      * that we try to connect to, it could be that the /CONNECT
1557      * <mask> caused this connect to be put at the wrong place
1558      * in the hashtable.        --Run
1559      * Same thing for Unknown connections that first send NICK.
1560      *                          --Xorath
1561      * Better check if the two strings are (caseless) identical 
1562      * and not mess with hash internals. 
1563      *                          --Nemesi
1564      */
1565     if ((!(EmptyString(cptr->name)))
1566         && (IsUnknown(cptr) || IsHandshake(cptr))
1567         && 0 != ircd_strcmp(cptr->name, host))
1568       hChangeClient(cptr, host);
1569     ircd_strncpy(cptr->name, host, HOSTLEN);
1570     ircd_strncpy(cptr->info, info[0] ? info : me.name, REALLEN);
1571     cptr->hopcount = hop;
1572
1573     /* check connection rules */
1574     if (0 != conf_eval_crule(host, CRULE_ALL)) {
1575       ServerStats->is_ref++;
1576       sendto_ops("Refused connection from %s.", cptr->name); /* XXX DEAD */
1577       return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
1578     }
1579     if (conf_check_server(cptr)) {
1580       ++ServerStats->is_ref;
1581       sendto_ops("Received unauthorized connection from %s.", cptr->name); /* XXX DEAD */
1582       return exit_client(cptr, cptr, &me, "No C/N conf lines");
1583     }
1584
1585     host = cptr->name;
1586
1587     update_load();
1588
1589     if (!(aconf = find_conf_byname(cptr->confs, host, CONF_SERVER))) {
1590       ++ServerStats->is_ref;
1591 #ifndef GODMODE
1592       sendto_ops("Access denied. No conf line for server %s", cptr->name); /* XXX DEAD */
1593       return exit_client_msg(cptr, cptr, &me,
1594           "Access denied. No conf line for server %s", cptr->name);
1595 #else /* GODMODE */
1596       sendto_ops("General C/N: line active: No line for server %s", cptr->name); /* XXX DEAD */
1597       aconf =
1598           find_conf_byname(cptr->confs, "general.undernet.org", CONF_SERVER);
1599       if (!aconf) {
1600         sendto_ops("Neither C/N lines for server %s nor " /* XXX DEAD */
1601             "\"general.undernet.org\"", cptr->name);
1602         return exit_client_msg(cptr, cptr, &me,
1603             "No C/N lines for server %s", cptr->name);
1604       }
1605 #endif /* GODMODE */
1606     }
1607 #ifdef CRYPT_LINK_PASSWORD
1608     /* passwd may be NULL. Head it off at the pass... */
1609     if (*cptr->passwd)
1610     {
1611       encr = ircd_crypt(cptr->passwd, aconf->passwd);
1612     }
1613     else
1614       encr = "";
1615 #else
1616     encr = cptr->passwd;
1617 #endif /* CRYPT_LINK_PASSWORD */
1618 #ifndef GODMODE
1619     if (*aconf->passwd && !!strcmp(aconf->passwd, encr)) {
1620       ++ServerStats->is_ref;
1621       sendto_ops("Access denied (passwd mismatch) %s", cptr->name); /* XXX DEAD */
1622       return exit_client_msg(cptr, cptr, &me,
1623           "No Access (passwd mismatch) %s", cptr->name);
1624     }
1625 #endif /* not GODMODE */
1626     memset(cptr->passwd, 0, sizeof(cptr->passwd));
1627
1628 #ifndef HUB
1629     for (i = 0; i <= HighestFd; i++)
1630       if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
1631         active_lh_line = 3;
1632         LHcptr = 0;
1633         break;
1634       }
1635 #endif
1636   }
1637
1638   /*
1639    *  We want to find IsConnecting() and IsHandshake() too,
1640    *  use FindClient().
1641    *  The second finds collisions with numeric representation of existing
1642    *  servers - these shouldn't happen anymore when all upgraded to 2.10.
1643    *  -- Run
1644    */
1645   while ((acptr = FindClient(host)) || 
1646          (parc > 7 && (acptr = FindNServer(parv[6]))))
1647   {
1648     /*
1649      *  This link is trying feed me a server that I already have
1650      *  access through another path
1651      *
1652      *  Do not allow Uworld to do this.
1653      *  Do not allow servers that are juped.
1654      *  Do not allow servers that have older link timestamps
1655      *    then this try.
1656      *  Do not allow servers that use the same numeric as an existing
1657      *    server, but have a different name.
1658      *
1659      *  If my ircd.conf sucks, I can try to connect to myself:
1660      */
1661     if (acptr == &me)
1662       return exit_client_msg(cptr, cptr, &me,
1663           "nick collision with me, check server number in M:? (%s)", host);
1664     /*
1665      * Detect wrong numeric.
1666      */
1667     if (0 != ircd_strcmp(acptr->name, host))
1668     {
1669       sendto_serv_butone(cptr, /* XXX DEAD */
1670           ":%s WALLOPS :SERVER Numeric Collision: %s != %s",
1671           me.name, acptr->name, host);
1672       return exit_client_msg(cptr, cptr, &me,
1673           "NUMERIC collision between %s and %s."
1674           " Is your server numeric correct ?", host, acptr->name);
1675     }
1676     /*
1677      *  Kill our try, if we had one.
1678      */
1679     if (IsConnecting(acptr))
1680     {
1681       if (!active_lh_line && exit_client(cptr, acptr, &me,
1682           "Just connected via another link") == CPTR_KILLED)
1683         return CPTR_KILLED;
1684       /*
1685        * We can have only ONE 'IsConnecting', 'IsHandshake' or
1686        * 'IsServer', because new 'IsConnecting's are refused to
1687        * the same server if we already had it.
1688        */
1689       break;
1690     }
1691     /*
1692      * Avoid other nick collisions...
1693      * This is a doubtfull test though, what else would it be
1694      * when it has a server.name ?
1695      */
1696     else if (!IsServer(acptr) && !IsHandshake(acptr))
1697       return exit_client_msg(cptr, cptr, &me,
1698           "Nickname %s already exists!", host);
1699     /*
1700      * Our new server might be a juped server,
1701      * or someone trying abuse a second Uworld:
1702      */
1703     else if (IsServer(acptr) && (0 == ircd_strncmp(acptr->info, "JUPE", 4) ||
1704         find_conf_byhost(cptr->confs, acptr->name, CONF_UWORLD)))
1705     {
1706       if (!IsServer(sptr))
1707         return exit_client(cptr, sptr, &me, acptr->info);
1708       sendto_one(cptr, ":%s WALLOPS :Received :%s SERVER %s from %s !?!", /* XXX DEAD */
1709           me.name, parv[0], parv[1], cptr->name);
1710       return exit_new_server(cptr, sptr, host, timestamp, "%s", acptr->info);
1711     }
1712     /*
1713      * Of course we find the handshake this link was before :)
1714      */
1715     else if (IsHandshake(acptr) && acptr == cptr)
1716       break;
1717     /*
1718      * Here we have a server nick collision...
1719      * We don't want to kill the link that was last /connected,
1720      * but we neither want to kill a good (old) link.
1721      * Therefor we kill the second youngest link.
1722      */
1723     if (1)
1724     {
1725       struct Client* c2ptr = 0;
1726       struct Client* c3ptr = acptr;
1727       struct Client* ac2ptr;
1728       struct Client* ac3ptr;
1729
1730       /* Search youngest link: */
1731       for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
1732         if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
1733           c3ptr = ac3ptr;
1734       if (IsServer(sptr))
1735       {
1736         for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
1737           if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
1738             c3ptr = ac3ptr;
1739       }
1740       if (timestamp > c3ptr->serv->timestamp)
1741       {
1742         c3ptr = 0;
1743         c2ptr = acptr;          /* Make sure they differ */
1744       }
1745       /* Search second youngest link: */
1746       for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
1747         if (ac2ptr != c3ptr &&
1748             ac2ptr->serv->timestamp >
1749             (c2ptr ? c2ptr->serv->timestamp : timestamp))
1750           c2ptr = ac2ptr;
1751       if (IsServer(sptr))
1752       {
1753         for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
1754           if (ac2ptr != c3ptr &&
1755               ac2ptr->serv->timestamp >
1756               (c2ptr ? c2ptr->serv->timestamp : timestamp))
1757             c2ptr = ac2ptr;
1758       }
1759       if (c3ptr && timestamp > (c2ptr ? c2ptr->serv->timestamp : timestamp))
1760         c2ptr = 0;
1761       /* If timestamps are equal, decide which link to break
1762        *  by name.
1763        */
1764       if ((c2ptr ? c2ptr->serv->timestamp : timestamp) ==
1765           (c3ptr ? c3ptr->serv->timestamp : timestamp))
1766       {
1767         char* n2;
1768         char* n2up;
1769         char* n3;
1770         char* n3up;
1771         if (c2ptr)
1772         {
1773           n2 = c2ptr->name;
1774           n2up = MyConnect(c2ptr) ? me.name : c2ptr->serv->up->name;
1775         }
1776         else
1777         {
1778           n2 = host;
1779           n2up = IsServer(sptr) ? sptr->name : me.name;
1780         }
1781         if (c3ptr)
1782         {
1783           n3 = c3ptr->name;
1784           n3up = MyConnect(c3ptr) ? me.name : c3ptr->serv->up->name;
1785         }
1786         else
1787         {
1788           n3 = host;
1789           n3up = IsServer(sptr) ? sptr->name : me.name;
1790         }
1791         if (strcmp(n2, n2up) > 0)
1792           n2 = n2up;
1793         if (strcmp(n3, n3up) > 0)
1794           n3 = n3up;
1795         if (strcmp(n3, n2) > 0)
1796         {
1797           ac2ptr = c2ptr;
1798           c2ptr = c3ptr;
1799           c3ptr = ac2ptr;
1800         }
1801       }
1802       /* Now squit the second youngest link: */
1803       if (!c2ptr)
1804         return exit_new_server(cptr, sptr, host, timestamp,
1805             "server %s already exists and is %ld seconds younger.",
1806             host, (long)acptr->serv->timestamp - (long)timestamp);
1807       else if (c2ptr->from == cptr || IsServer(sptr))
1808       {
1809         struct Client *killedptrfrom = c2ptr->from;
1810         if (active_lh_line)
1811         {
1812           /*
1813            * If the L: or H: line also gets rid of this link,
1814            * we sent just one squit.
1815            */
1816           if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
1817             break;
1818           /*
1819            * If breaking the loop here solves the L: or H:
1820            * line problem, we don't squit that.
1821            */
1822           if (c2ptr->from == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
1823             active_lh_line = 0;
1824           else
1825           {
1826             /*
1827              * If we still have a L: or H: line problem,
1828              * we prefer to squit the new server, solving
1829              * loop and L:/H: line problem with only one squit.
1830              */
1831             LHcptr = 0;
1832             break;
1833           }
1834         }
1835         /*
1836          * If the new server was introduced by a server that caused a
1837          * Ghost less then 20 seconds ago, this is probably also
1838          * a Ghost... (20 seconds is more then enough because all
1839          * SERVER messages are at the beginning of a net.burst). --Run
1840          */
1841         if (CurrentTime - cptr->serv->ghost < 20)
1842         {
1843           killedptrfrom = acptr->from;
1844           if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
1845             return CPTR_KILLED;
1846         }
1847         else if (exit_client_msg(cptr, c2ptr, &me,
1848             "Loop <-- %s (new link is %ld seconds younger)", host,
1849             (c3ptr ? (long)c3ptr->serv->timestamp : timestamp) -
1850             (long)c2ptr->serv->timestamp) == CPTR_KILLED)
1851           return CPTR_KILLED;
1852         /*
1853          * Did we kill the incoming server off already ?
1854          */
1855         if (killedptrfrom == cptr)
1856           return 0;
1857       }
1858       else
1859       {
1860         if (active_lh_line)
1861         {
1862           if (LHcptr && a_kills_b_too(LHcptr, acptr))
1863             break;
1864           if (acptr->from == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
1865             active_lh_line = 0;
1866           else
1867           {
1868             LHcptr = 0;
1869             break;
1870           }
1871         }
1872         /*
1873          * We can't believe it is a lagged server message
1874          * when it directly connects to us...
1875          * kill the older link at the ghost, rather then
1876          * at the second youngest link, assuming it isn't
1877          * a REAL loop.
1878          */
1879         ghost = CurrentTime;            /* Mark that it caused a ghost */
1880         if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
1881           return CPTR_KILLED;
1882         break;
1883       }
1884     }
1885   }
1886
1887   if (active_lh_line)
1888   {
1889     if (LHcptr == 0) {
1890       return exit_new_server(cptr, sptr, host, timestamp,
1891           (active_lh_line == 2) ?  "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1892           cptr->name, host,
1893           lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
1894     }
1895     else
1896     {
1897       int killed = a_kills_b_too(LHcptr, sptr);
1898       if (active_lh_line < 3)
1899       {
1900         if (exit_client_msg(cptr, LHcptr, &me,
1901             (active_lh_line == 2) ?  "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
1902             cptr->name, host,
1903             lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
1904           return CPTR_KILLED;
1905       }
1906       else
1907       {
1908         ServerStats->is_ref++;
1909         if (exit_client(cptr, LHcptr, &me, "I'm a leaf") == CPTR_KILLED)
1910           return CPTR_KILLED;
1911       }
1912       /*
1913        * Did we kill the incoming server off already ?
1914        */
1915       if (killed)
1916         return 0;
1917     }
1918   }
1919
1920   if (IsServer(cptr))
1921   {
1922     /*
1923      * Server is informing about a new server behind
1924      * this link. Create REMOTE server structure,
1925      * add it to list and propagate word to my other
1926      * server links...
1927      */
1928
1929     acptr = make_client(cptr, STAT_SERVER);
1930     make_server(acptr);
1931     acptr->serv->prot = prot;
1932     acptr->serv->timestamp = timestamp;
1933     acptr->hopcount = hop;
1934     ircd_strncpy(acptr->name, host, HOSTLEN);
1935     ircd_strncpy(acptr->info, info, REALLEN);
1936     acptr->serv->up = sptr;
1937     acptr->serv->updown = add_dlink(&sptr->serv->down, acptr);
1938     /* Use cptr, because we do protocol 9 -> 10 translation
1939        for numeric nicks ! */
1940     SetServerYXX(cptr, acptr, parv[6]);
1941
1942     Count_newremoteserver(UserStats);
1943     if (Protocol(acptr) < 10)
1944       acptr->flags |= FLAGS_TS8;
1945     add_client_to_list(acptr);
1946     hAddClient(acptr);
1947     if (*parv[5] == 'J')
1948     {
1949       SetBurst(acptr);
1950       sendto_op_mask(SNO_NETWORK, "Net junction: %s %s", /* XXX DEAD */
1951           sptr->name, acptr->name);
1952       SetJunction(acptr);
1953     }
1954     /*
1955      * Old sendto_serv_but_one() call removed because we now need to send
1956      * different names to different servers (domain name matching).
1957      */
1958     for (i = 0; i <= HighestFd; i++)
1959     {
1960       if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
1961           bcptr == cptr || IsMe(bcptr))
1962         continue;
1963       if (0 == match(me.name, acptr->name))
1964         continue;
1965         sendto_one(bcptr, "%s " TOK_SERVER " %s %d 0 %s %s %s%s 0 :%s", /* XXX DEAD */
1966             NumServ(sptr), acptr->name, hop + 1, parv[4], parv[5],
1967             NumServCap(acptr), acptr->info);
1968     }
1969     return 0;
1970   }
1971
1972   if (IsUnknown(cptr) || IsHandshake(cptr))
1973   {
1974     make_server(cptr);
1975     cptr->serv->timestamp = timestamp;
1976     cptr->serv->prot = prot;
1977     cptr->serv->ghost = ghost;
1978     SetServerYXX(cptr, cptr, parv[6]);
1979     if (start_timestamp > OLDEST_TS)
1980     {
1981 #ifndef RELIABLE_CLOCK
1982 #ifdef TESTNET
1983       sendto_ops("Debug: my start time: " TIME_T_FMT " ; others start time: " /* XXX DEAD */
1984           TIME_T_FMT, me.serv->timestamp, start_timestamp);
1985       sendto_ops("Debug: receive time: " TIME_T_FMT " ; received timestamp: " /* XXX DEAD */
1986           TIME_T_FMT " ; difference %ld",
1987           recv_time, timestamp, timestamp - recv_time);
1988 #endif
1989       if (start_timestamp < me.serv->timestamp)
1990       {
1991         sendto_ops("got earlier start time: " TIME_T_FMT " < " TIME_T_FMT, /* XXX DEAD */
1992             start_timestamp, me.serv->timestamp);
1993         me.serv->timestamp = start_timestamp;
1994         TSoffset += timestamp - recv_time;
1995         sendto_ops("clock adjusted by adding %d", (int)(timestamp - recv_time)); /* XXX DEAD */
1996       }
1997       else if ((start_timestamp > me.serv->timestamp) && IsUnknown(cptr))
1998         cptr->serv->timestamp = TStime();
1999
2000       else if (timestamp != recv_time)
2001       {
2002         /*
2003          * Equal start times, we have a collision.  Let the connected-to server
2004          * decide. This assumes leafs issue more than half of the connection
2005          * attempts.
2006          */
2007         if (IsUnknown(cptr))
2008           cptr->serv->timestamp = TStime();
2009         else if (IsHandshake(cptr))
2010         {
2011           sendto_ops("clock adjusted by adding %d", /* XXX DEAD */
2012               (int)(timestamp - recv_time));
2013           TSoffset += timestamp - recv_time;
2014         }
2015       }
2016 #else /* RELIABLE CLOCK IS TRUE, we _always_ use our own clock */
2017       if (start_timestamp < me.serv->timestamp)
2018         me.serv->timestamp = start_timestamp;
2019       if (IsUnknown(cptr))
2020         cptr->serv->timestamp = TStime();
2021 #endif
2022     }
2023
2024     ret = server_estab(cptr, aconf); /* XXX DEAD */
2025   }
2026   else
2027     ret = 0;
2028 #ifdef RELIABLE_CLOCK
2029   if (abs(cptr->serv->timestamp - recv_time) > 30)
2030   {
2031     sendto_ops("Connected to a net with a timestamp-clock" /* XXX DEAD */
2032         " difference of " STIME_T_FMT " seconds! Used SETTIME to correct"
2033         " this.", timestamp - recv_time);
2034     sendto_one(cptr, ":%s SETTIME " TIME_T_FMT " :%s", /* XXX DEAD */
2035         me.name, TStime(), me.name);
2036   }
2037 #endif
2038
2039   return ret;
2040 }
2041 #endif /* 0 */
2042