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