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