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