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