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