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