Example #1
0
/*
 * Goes thru the list of locally connected servers (except cptr),
 * check if my neighbours can see the server "server" (or if it is hidden
 * by a hostmask)
 * Returns the number of marked servers
 */
int	mark_blind_servers (aClient *cptr, aClient *server)
{
	Reg	int		i, j = 0;
	Reg	aClient		*acptr;
	Reg	aConfItem	*aconf;
	
	for (i = fdas.highest; i >= 0; i--)
	{
		if (!(acptr = local[fdas.fd[i]]) || !IsServer(acptr))
			continue;
		if (acptr == cptr->from || IsMe(acptr))
		{
			acptr->flags &= ~FLAGS_HIDDEN;
			continue;
		}
		if (((aconf = acptr->serv->nline) &&
			!match(my_name_for_link(ME, aconf->port), server->name)))
		{
			acptr->flags |= FLAGS_HIDDEN;
			j++;
		}
		else
		{
			acptr->flags &= ~FLAGS_HIDDEN;
		}
	}
	return j;
}
Example #2
0
/*
** Remove *everything* that depends on source_p, from all lists, and sending
** all necessary QUITs and SQUITs.  source_p itself is still on the lists,
** and its SQUITs have been sent except for the upstream one  -orabidoo
*/
static void remove_dependents(struct Client* client_p, 
                               struct Client* source_p,
                               struct Client* from,
                               const char* comment,
                               const char* comment1)
{
  struct Client *to;
  struct ConfItem *aconf;
  static char myname[HOSTLEN+1];
  dlink_node *ptr;

  for(ptr = serv_list.head; ptr; ptr=ptr->next)
    {
      to = ptr->data;

      if (IsMe(to) ||to == source_p->from || (to == client_p && IsCapable(to,CAP_QS)))
        continue;

      /* MyConnect(source_p) is rotten at this point: if source_p
       * was mine, ->from is NULL. 
       */
      /* The WALLOPS isn't needed here as pointed out by
       * comstud, since m_squit already does the notification.
       */

      if ((aconf = to->serv->sconf))
        strlcpy(myname, my_name_for_link(me.name, aconf), HOSTLEN);
      else
        strlcpy(myname, me.name, HOSTLEN);
      recurse_send_quits(client_p, source_p, to, comment1, myname);
    }

  recurse_remove_clients(source_p, comment1);
}
Example #3
0
static int
do_server_estab(aClient *cptr)
{
    aClient *acptr;
    aConnect *aconn;
    aChannel *chptr;
    int i;
    /* "refresh" inpath with host  */
    char *inpath = get_client_name(cptr, HIDEME);

    SetServer(cptr);

    Count.unknown--;
    Count.server++;
    Count.myserver++;

    if(IsZipCapable(cptr) && DoZipThis(cptr))
    {
        sendto_one(cptr, "SVINFO ZIP");
        SetZipOut(cptr);
        cptr->serv->zip_out = zip_create_output_session();
    }

#ifdef MAXBUFFERS
    /* let's try to bump up server sock_opts... -Taner */
    reset_sock_opts(cptr->fd, 1);
#endif

    /* adds to server list */
    add_to_list(&server_list, cptr);

    set_effective_class(cptr);

    /* Check one more time for good measure... is it there? */
    if ((acptr = find_name(cptr->name, NULL)))
    {
        char        nbuf[HOSTLEN * 2 + USERLEN + 5];
        aClient *bcptr;

        /*
         * While negotiating stuff, another copy of this server appeared.
         *
         * Rather than KILL the link which introduced it, KILL the
         * youngest of the two links. -avalon
         */

        bcptr = (cptr->firsttime > acptr->from->firsttime) ? cptr :
            acptr->from;
        sendto_one(bcptr, "ERROR :Server %s already exists", cptr->name);
        if (bcptr == cptr)
        {
            sendto_gnotice("from %s: Link %s cancelled, server %s already "
                           "exists (final phase)", me.name,
                           get_client_name(bcptr, HIDEME), cptr->name);
            sendto_serv_butone(bcptr, ":%s GNOTICE :Link %s cancelled, "
                                "server %s already exists (final phase)",
                                me.name, get_client_name(bcptr, HIDEME),
                                cptr->name);
            return exit_client(bcptr, bcptr, &me,
                               "Server Exists (final phase)");
        }
        /* inform all those who care (set +n) -epi */

        strcpy(nbuf, get_client_name(bcptr, HIDEME));
        sendto_gnotice("from %s: Link %s cancelled, server %s reintroduced "
                       "by %s (final phase)", me.name, nbuf, cptr->name,
                       get_client_name(cptr, HIDEME));
        sendto_serv_butone(bcptr, ":%s GNOTICE :Link %s cancelled, server %s "
                           "reintroduced by %s (final phase)", me.name, nbuf,
                           cptr->name, get_client_name(cptr, HIDEME));
        exit_client(bcptr, bcptr, &me, "Server Exists (final phase)");
    }

    /* error, error, error! if a server is U:'d, and it connects to us,
     * we need to figure that out! So, do it here. - lucas
     */

    if (find_aUserver(cptr->name))
    {
        Count.myulined++;
        cptr->flags |= FLAGS_ULINE;

        /* If the server has special u:line flags, let's set them.. */
        cptr->serv->uflags = cptr->serv->aconn->uflags;
    }

    fakelinkserver_update(cptr->name, cptr->info);

    sendto_gnotice("from %s: Link with %s established, states:%s%s%s%s",
                   me.name, inpath, ZipOut(cptr) ? " Output-compressed" : "",
                   RC4EncLink(cptr) ? " encrypted" : "",
                   IsULine(cptr) ? " ULined" : "",
                   DoesTS(cptr) ? " TS" : " Non-TS");

    /*
     * Notify everyone of the fact that this has just linked: the entire
     * network should get two of these, one explaining the link between
     * me->serv and the other between serv->me
     */

    sendto_serv_butone(NULL, ":%s GNOTICE :Link with %s established: %s",
                       me.name, inpath,
                       DoesTS(cptr) ? "TS link" : "Non-TS link!");

    add_to_client_hash_table(cptr->name, cptr);

    /* add it to scache */

    find_or_add(cptr->name);

    /*
     * Old sendto_serv_but_one() call removed because we now need to
     * send different names to different servers (domain name
     * matching) Send new server to other servers.
     */
    for (i = 0; i <= highest_fd; i++)
    {
        if (!(acptr = local[i]) || !IsServer(acptr) || acptr == cptr ||
            IsMe(acptr))
            continue;
        if ((aconn = acptr->serv->aconn) &&
            !match(my_name_for_link(me.name, aconn), cptr->name))
            continue;
        sendto_one(acptr, ":%s SERVER %s 2 :%s", me.name, cptr->name,
                   cptr->info);
    }

    /*
     * Pass on my client information to the new server
     *
     * First, pass only servers (idea is that if the link gets
     * cancelled beacause the server was already there, there are no
     * NICK's to be cancelled...). Of course, if cancellation occurs,
     * all this info is sent anyway, and I guess the link dies when a
     * read is attempted...? --msa
     *
     * Note: Link cancellation to occur at this point means that at
     * least two servers from my fragment are building up connection
     * this other fragment at the same time, it's a race condition,
     * not the normal way of operation...
     *
     * ALSO NOTE: using the get_client_name for server names-- see
     * previous *WARNING*!!! (Also, original inpath is
     * destroyed...)
     */

    aconn = cptr->serv->aconn;
    for (acptr = &me; acptr; acptr = acptr->prev)
    {
        if (acptr->from == cptr)
            continue;
        if (IsServer(acptr))
        {
            if (match(my_name_for_link(me.name, aconn), acptr->name) == 0)
                continue;
            sendto_one(cptr, ":%s SERVER %s %d :%s",
                       acptr->serv->up, acptr->name,
                       acptr->hopcount + 1, acptr->info);
        }
    }

    /* send out our SQLINES and SGLINES too */
    send_simbans(cptr, SBAN_CHAN|SBAN_NETWORK);
    send_simbans(cptr, SBAN_NICK|SBAN_NETWORK);
    send_simbans(cptr, SBAN_GCOS|SBAN_NETWORK);

    /* Send out fake server list and other 'fake' stuff */
    fakeserver_sendserver(cptr);

    /* Send UHM (user host-masking) type */
    if(confopts & FLAGS_HUB)
        sendto_one(cptr, "SVSUHM %d", uhm_type);

    /* send clone list */
    clones_send(cptr);

    /* Bursts are about to start.. send a BURST */
    if (IsBurst(cptr))
        sendto_one(cptr, "BURST");

    /*
     * * Send it in the shortened format with the TS, if it's a TS
     * server; walk the list of channels, sending all the nicks that
     * haven't been sent yet for each channel, then send the channel
     * itself -- it's less obvious than sending all nicks first, but
     * on the receiving side memory will be allocated more nicely
     * saving a few seconds in the handling of a split -orabidoo
     */
    {
        chanMember       *cm;
        static char nickissent = 1;

        nickissent = 3 - nickissent;
        /*
         * flag used for each nick to check if we've sent it yet - must
         * be different each time and !=0, so we alternate between 1 and
         * 2 -orabidoo
         */
        for (chptr = channel; chptr; chptr = chptr->nextch)
        {
            for (cm = chptr->members; cm; cm = cm->next)
            {
                acptr = cm->cptr;
                if (acptr->nicksent != nickissent)
                {
                    acptr->nicksent = nickissent;
                    if (acptr->from != cptr)
                        sendnick_TS(cptr, acptr);
                }
            }
            send_channel_modes(cptr, chptr);
        }
        /* also send out those that are not on any channel */
        for (acptr = &me; acptr; acptr = acptr->prev)
            if (acptr->nicksent != nickissent)
            {
                acptr->nicksent = nickissent;
                if (acptr->from != cptr)
                    sendnick_TS(cptr, acptr);
            }
    }

    if(confopts & FLAGS_HUB)
        fakelusers_sendlock(cptr);

    if(ZipOut(cptr))
    {
        unsigned long inb, outb;
        double rat;

        zip_out_get_stats(cptr->serv->zip_out, &inb, &outb, &rat);

        if(inb)
        {
            sendto_gnotice("from %s: Connect burst to %s: %lu bytes normal, "
                           "%lu compressed (%3.2f%%)", me.name,
                           get_client_name(cptr, HIDEME), inb, outb, rat);
            sendto_serv_butone(cptr, ":%s GNOTICE :Connect burst to %s: %lu "
                               "bytes normal, %lu compressed (%3.2f%%)",
                               me.name, get_client_name(cptr, HIDEME), inb,
                               outb, rat);
        }
    }

    /* stuff a PING at the end of this burst so we can figure out when
       the other side has finished processing it. */
    cptr->flags |= FLAGS_BURST|FLAGS_PINGSENT;
    if (IsBurst(cptr)) cptr->flags |= FLAGS_SOBSENT;
    sendto_one(cptr, "PING :%s", me.name);

    return 0;
}
Example #4
0
/*
 *  m_server
 *       parv[0] = sender prefix
 *       parv[1] = servername
 *       parv[2] = serverinfo/hopcount
 *       parv[3] = serverinfo
 */
int m_server(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
    int     i;
    char        info[REALLEN + 1], *host;
    aClient    *acptr, *bcptr;
    aConnect   *aconn;
    int         hop;
    char        nbuf[HOSTLEN * 2 + USERLEN + 5]; /* same size as in s_misc.c */

    info[0] = '\0';

    if (parc < 2 || *parv[1] == '\0')
    {
        sendto_one(cptr, "ERROR :No servername");
        return 0;
    }

    hop = 0;
    host = parv[1];
    if (parc > 3 && atoi(parv[2]))
    {
        hop = atoi(parv[2]);
        strncpyzt(info, parv[3], REALLEN + 1);
    }
    else if (parc > 2)
    {
        strncpyzt(info, parv[2], REALLEN + 1);
        if ((parc > 3) && ((i = strlen(info)) < (REALLEN - 2)))
        {
            strcat(info, " ");
            strncat(info, parv[3], REALLEN - i - 2);
            info[REALLEN] = '\0';
        }
    }
    /*
     * July 5, 1997
     * Rewritten to throw away server cruft from users,
     * combined the hostname validity test with cleanup of host name,
     * so a cleaned up hostname can be returned as an error if
     * necessary. - Dianora
     */

    /* yes, the if(strlen) below is really needed!! */
    if (strlen(host) > HOSTLEN)
        host[HOSTLEN] = '\0';

    if (IsPerson(cptr))
    {
        /* A local link that has been identified as a USER tries
         * something fishy... ;-)
         */
        sendto_one(cptr, err_str(ERR_UNKNOWNCOMMAND),
                   me.name, parv[0], "SERVER");

        return 0;
    }
    else
        /* hostile servername check */
    {
        /*
         * Lets check for bogus names and clean them up we don't bother
         * cleaning up ones from users, becasuse we will never see them
         * any more - Dianora
         */

        int bogus_server = 0;
        int found_dot = 0;
        char clean_host[(2 * HOSTLEN) + 1];
        char *s;
        char *d;
        int n;

        s = host;
        d = clean_host;
        n = (2 * HOSTLEN) - 2;

        while (*s && n > 0)
        {
            if ((unsigned char) *s < (unsigned char) ' ')
                /* Is it a control character? */
            {
                bogus_server = 1;
                *d++ = '^';
                *d++ = (char) ((unsigned char) *s + 0x40);
                /* turn it into a printable */
                n -= 2;
            }
            else if ((unsigned char) *s > (unsigned char) '~')
            {
                bogus_server = 1;
                *d++ = '.';
                n--;
            }
            else
            {
                if (*s == '.')
                    found_dot = 1;
                *d++ = *s;
                n--;
            }
            s++;
        }
        *d = '\0';

        if ((!found_dot) || bogus_server)
        {
            sendto_one(sptr, "ERROR :Bogus server name (%s)",
                       clean_host);
            return exit_client(cptr, cptr, cptr, "Bogus server name");
        }
    }

    /* new connection */
    if (IsUnknown(cptr) || IsHandshake(cptr))
    {
        strncpyzt(cptr->name, host, sizeof(cptr->name));
        strncpyzt(cptr->info, info[0] ? info : me.name, REALLEN + 1);
        cptr->hopcount = hop;

        switch (check_server_init(cptr))
        {
            case 0:
                return m_server_estab(cptr);
            case 1:
                sendto_ops("Access check for %s in progress",
                           get_client_name(cptr, HIDEME));
                return 1;
            default:
                ircstp->is_ref++;
                sendto_ops_lev(ADMIN_LEV, "Link %s dropped, no Connect block",
                           get_client_name(cptr, TRUE));
                return exit_client(cptr, cptr, cptr, "No Connect block");
        }
    }
    
    /* already linked server */
    if (!IsServer(cptr))
        return 0;

    if ((acptr = find_name(host, NULL)))
    {
        /*
         * * This link is trying feed me a server that I already have
         * access through another path -- multiple paths not accepted
         * currently, kill this link immediately!!
         *
         * Rather than KILL the link which introduced it, KILL the
         * youngest of the two links. -avalon
         */

        bcptr = (cptr->firsttime > acptr->from->firsttime) ? cptr :
            acptr->from;
        sendto_one(bcptr, "ERROR :Server %s already exists", host);
        if (bcptr == cptr)
        {
            /* Don't complain for servers that are juped */
            /* (don't complain if the server that already exists is U: lined,
                unless I actually have a .conf U: line for it */
            if(!IsULine(acptr) || find_aUserver(acptr->name))
            {
                sendto_gnotice("from %s: Link %s cancelled, server %s already "
                               "exists", me.name, get_client_name(bcptr, HIDEME),
                               host);
                sendto_serv_butone(bcptr, ":%s GNOTICE :Link %s cancelled, "
                                   "server %s already exists", me.name,
                                   get_client_name(bcptr, HIDEME), host);
            }
            return exit_client(bcptr, bcptr, &me, "Server Exists");
        }
        /* inform all those who care (set +n) -epi */
        strcpy(nbuf, get_client_name(bcptr, HIDEME));
        sendto_gnotice("from %s: Link %s cancelled, server %s reintroduced "
                       "by %s", me.name, nbuf, host,
                       get_client_name(cptr, HIDEME));
        sendto_serv_butone(bcptr, ":%s GNOTICE :Link %s cancelled, server %s "
                           "reintroduced by %s", me.name, nbuf, host,
                           get_client_name(cptr, HIDEME));
        exit_client(bcptr, bcptr, &me, "Server Exists");
    }
    /*
     * The following if statement would be nice to remove since user
     * nicks never have '.' in them and servers must always have '.' in
     * them. There should never be a server/nick name collision, but it
     * is possible a capricious server admin could deliberately do
     * something strange.
     *
     * -Dianora
     */

    if ((acptr = find_client(host, NULL)) && acptr != cptr)
    {
        /*
         * * Server trying to use the same name as a person. Would
         * cause a fair bit of confusion. Enough to make it hellish for
         * a while and servers to send stuff to the wrong place.
         */
        sendto_one(cptr, "ERROR :Nickname %s already exists!", host);
        strcpy(nbuf, get_client_name(cptr, HIDEME));
        sendto_gnotice("from %s: Link %s cancelled, servername/nick collision",
                       me.name, nbuf);
        sendto_serv_butone(cptr, ":%s GNOTICE :Link %s cancelled, "
                           "servername/nick collision", me.name, nbuf);
        return exit_client(cptr, cptr, cptr, "Nick as Server");
    }

    if (IsServer(cptr))
    {
        /*
         * * Server is informing about a new server behind this link.
         * Create REMOTE server structure, add it to list and propagate
         * word to my other server links...
         */
        if (parc == 1 || info[0] == '\0')
        {
            sendto_one(cptr, "ERROR :No server info specified for %s", host);
            return 0;
        }
        /*
         * * See if the newly found server is behind a guaranteed leaf
         * (L-line). If so, close the link.
         *
         * Depreciated.  Kinda redundant with Hlines. -epi
         */
        if (!(cptr->serv->aconn->flags & CONN_HUB))
        {
            aconn = cptr->serv->aconn;
            sendto_gnotice("from %s: Non-Hub link %s introduced %s",
                           me.name, get_client_name(cptr, HIDEME), host);
            sendto_serv_butone(cptr,":%s GNOTICE :Non-Hub link %s introduced "
                               "%s", me.name, get_client_name(cptr, HIDEME),
                               host);
            sendto_one(cptr, "ERROR :You're not a hub (introducing %s)",
                       host);
            return exit_client(cptr, cptr, cptr, "Too many servers");
        }

        acptr = make_client(cptr, sptr);
        make_server(acptr);
        acptr->hopcount = hop;
        strncpyzt(acptr->name, host, sizeof(acptr->name));
        strncpyzt(acptr->info, info, REALLEN + 1);
        acptr->serv->up = find_or_add(parv[0]);

        fakelinkserver_update(acptr->name, acptr->info);
        SetServer(acptr);

        /*
         * if this server is behind a U-lined server, make it U-lined as
         * well. - lucas
         */

        if (IsULine(sptr) || find_aUserver(acptr->name))
        {
            acptr->flags |= FLAGS_ULINE;
            sendto_realops_lev(DEBUG_LEV, "%s introducing super server %s",
                               cptr->name, acptr->name);
        }

        Count.server++;

        add_client_to_list(acptr);
        add_to_client_hash_table(acptr->name, acptr);
        /*
         * Old sendto_serv_but_one() call removed because we now need
         * to send different names to different servers (domain name matching)
         */
        for (i = 0; i <= highest_fd; i++)
        {
            if (!(bcptr = local[i]) || !IsServer(bcptr) || bcptr == cptr ||
                IsMe(bcptr))
                continue;
            if (!(aconn = bcptr->serv->aconn))
            {
                sendto_gnotice("from %s: Lost Connect block for %s on %s."
                               " Closing", me.name,
                               get_client_name(cptr, HIDEME), host);
                sendto_serv_butone(cptr, ":%s GNOTICE :Lost Connect block for"
                                   " %s on %s. Closing", me.name,
                                   get_client_name(cptr, HIDEME), host);
                return exit_client(cptr, cptr, cptr, "Lost Connect block");
            }
            if (match(my_name_for_link(me.name, aconn), acptr->name) == 0)
                continue;
            sendto_one(bcptr, ":%s SERVER %s %d :%s",
                       parv[0], acptr->name, hop + 1, acptr->info);
        }
        return 0;
    }

    return 0;
}
Example #5
0
static int
m_server_estab(aClient *cptr)
{
    aConnect *aconn;
    aClient *acptr;

    char       *inpath, *host, *s, *encr;

    inpath = get_client_name(cptr, HIDEME);  /* "refresh" inpath with host  */
    host = cptr->name;

    if (!(aconn = cptr->serv->aconn))
    {
        ircstp->is_ref++;
        sendto_one(cptr, "ERROR :Lost Connect block");
        sendto_ops_lev(ADMIN_LEV, "Lost Connect block for server %s",
                           get_client_name(cptr, TRUE));
        return exit_client(cptr, cptr, cptr, "Lost Connect block");
    }

    encr = cptr->passwd;
    if (*aconn->apasswd && !StrEq(aconn->apasswd, encr))
    {
        ircstp->is_ref++;
        sendto_one(cptr, "ERROR :Wrong link password");
        sendto_ops("Link %s dropped, wrong password", inpath);
        return exit_client(cptr, cptr, cptr, "Bad Password");
    }
    memset(cptr->passwd, '\0', sizeof(cptr->passwd));

    if ((acptr = find_client(host, NULL)))
    {
        /* Don't complain about juped servers */
        if(!IsULine(acptr) || find_aUserver(acptr->name))
        {
            sendto_gnotice("from %s: Link %s dropped, server already exists",
                           me.name, inpath);
            sendto_serv_butone(cptr, ":%s GNOTICE :Link %s dropped, server already"
                               " exists", me.name, inpath);
        }
        return exit_client(cptr, cptr, cptr, "Server Exists");
    }

    if(!(confopts & FLAGS_HUB))
    {
        int i;
        for (i = 0; i <= highest_fd; i++)
            if (local[i] && IsServer(local[i]))
            {
                ircstp->is_ref++;
                sendto_one(cptr, "ERROR :I'm a leaf not a hub");
                return exit_client(cptr, cptr, cptr, "I'm a leaf");
            }
    }

    /* aconf->port is a CAPAB field, kind-of. kludge. mm, mm. */
    /* no longer! this should still get better though */
    if((aconn->flags & CONN_ZIP))
        SetZipCapable(cptr);
    if((aconn->flags & CONN_DKEY))
        SetWantDKEY(cptr);
    if (IsUnknown(cptr))
    {
        if (aconn->cpasswd[0])
            sendto_one(cptr, "PASS %s :TS", aconn->cpasswd);

        /* Pass my info to the new server */

#ifdef HAVE_ENCRYPTION_ON
        if(!WantDKEY(cptr))
            sendto_one(cptr, "CAPAB SSJOIN NOQUIT BURST UNCONNECT ZIP "
                       "NICKIP NICKIPSTR TSMODE");
        else
            sendto_one(cptr, "CAPAB SSJOIN NOQUIT BURST UNCONNECT DKEY "
                       "ZIP NICKIP NICKIPSTR TSMODE");
#else
        sendto_one(cptr, "CAPAB SSJOIN NOQUIT BURST UNCONNECT ZIP NICKIP NICKIPSTR TSMODE");
#endif

        sendto_one(cptr, "SERVER %s 1 :%s",
                   my_name_for_link(me.name, aconn),
                   (me.info[0]) ? (me.info) : "IRCers United");
    }
    else 
    {
        s = (char *) strchr(aconn->host, '@');
        *s = '\0';      /* should never be NULL -- wanna bet? -Dianora */

        Debug((DEBUG_INFO, "Check Usernames [%s]vs[%s]", aconn->host,
               cptr->username));
        if (match(aconn->host, cptr->username))
        {
            *s = '@';
            ircstp->is_ref++;
            sendto_ops("Username mismatch [%s]v[%s] : %s",
                       aconn->host, cptr->username,
                       get_client_name(cptr, HIDEME));
            sendto_one(cptr, "ERROR :No Username Match");
            return exit_client(cptr, cptr, cptr, "Bad User");
        }
        *s = '@';
    }

    /* send routing notice, this should never happen anymore */
    if (!DoesTS(cptr))
    {
        sendto_gnotice("from %s: Warning: %s linked, non-TS server",
                       me.name, get_client_name(cptr, HIDEME));
        sendto_serv_butone(cptr,
                           ":%s GNOTICE :Warning: %s linked, non-TS server",
                           me.name, get_client_name(cptr, HIDEME));
    }

    sendto_one(cptr, "SVINFO %d %d 0 :%ld", TS_CURRENT, TS_MIN,
               (ts_val) timeofday);

    /* sendto one(cptr, "CAPAB ...."); moved to after PASS but before SERVER
     * now in two places.. up above and in s_bsd.c. - lucas
     * This is to make sure we pass on our capabilities before we establish
     * a server connection
     */

    /*
     * *WARNING*
     *   In the following code in place of plain
     * server's name we send what is returned by
     * get_client_name which may add the "sockhost" after the name.
     * It's *very* *important* that there is a SPACE between
     * the name and sockhost (if present). The receiving server
     * will start the information field from this first blank and
     * thus puts the sockhost into info. ...a bit tricky, but
     * you have been warned, besides code is more neat this way...
     * --msa
     */

    cptr->serv->up = me.name;
    cptr->serv->aconn = aconn;

    throttle_remove(cipntoa(cptr));

#ifdef HAVE_ENCRYPTION_ON
    if(!CanDoDKEY(cptr) || !WantDKEY(cptr))
        return do_server_estab(cptr);
    else
    {
        SetNegoServer(cptr); /* VERY IMPORTANT THAT THIS IS HERE */
        sendto_one(cptr, "DKEY START");
    }
#else
    return do_server_estab(cptr);
#endif

    return 0;
}
Example #6
0
/*
 * m_squit - SQUIT message handler
 *      parv[0] = sender prefix
 *      parv[1] = server name
 *      parv[2] = comment
 */
int m_squit(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
{
  struct ConfItem* aconf;
  char*            server;
  struct Client*   acptr;
  char  *comment = (parc > 2 && parv[2]) ? parv[2] : cptr->name;

  if (!(IsServer(sptr) || HasUmode(sptr,UMODE_REMOTE)))
    {
      if (SeesOperMessages(sptr))
	sendto_one(sptr,":%s NOTICE %s :You have no R umode", me.name, parv[0]);
      else
	sendto_one(sptr, form_str(ERR_NOPRIVILEGES), me.name, parv[0]);
      return 0;
    }

  if (parc > 1)
    {
      server = parv[1];
      /*
      ** To accomodate host masking, a squit for a masked server
      ** name is expanded if the incoming mask is the same as
      ** the server name for that link to the name of link.
      */
      while ((*server == '*') && IsServer(cptr))
        {
          aconf = cptr->serv->nline;
          if (!aconf)
            break;
          if (!irccmp(server, my_name_for_link(me.name, aconf)))
            server = cptr->name;
          break; /* WARNING is normal here */
          /* NOTREACHED */
        }
      /*
      ** The following allows wild cards in SQUIT. Only useful
      ** when the command is issued by an oper.
      */
      for (acptr = GlobalClientList; (acptr = next_client(acptr, server));
           acptr = acptr->next)
        if (IsServer(acptr) || IsMe(acptr))
          break;
      if (acptr && IsMe(acptr))
        {
          acptr = cptr;
          server = cptr->name;
        }
    }
  else
    {
      /*
      ** This is actually protocol error. But, well, closing
      ** the link is very proper answer to that...
      **
      ** Closing the client's connection probably wouldn't do much
      ** good.. any oper out there should know that the proper way
      ** to disconnect is /QUIT :)
      **
      ** its still valid if its not a local client, its then
      ** a protocol error for sure -Dianora
      */
      if(MyClient(sptr))
        {
          sendto_one(sptr, form_str(ERR_NEEDMOREPARAMS),
               me.name, parv[0], "SQUIT");
          return 0;
        }
      else
        {
          server = cptr->host;
          acptr = cptr;
        }
    }

  /*
  ** SQUIT semantics is tricky, be careful...
  **
  ** The old (irc2.2PL1 and earlier) code just cleans away the
  ** server client from the links (because it is never true
  ** "cptr == acptr".
  **
  ** This logic here works the same way until "SQUIT host" hits
  ** the server having the target "host" as local link. Then it
  ** will do a real cleanup spewing SQUIT's and QUIT's to all
  ** directions, also to the link from which the orinal SQUIT
  ** came, generating one unnecessary "SQUIT host" back to that
  ** link.
  **
  ** One may think that this could be implemented like
  ** "hunt_server" (e.g. just pass on "SQUIT" without doing
  ** nothing until the server having the link as local is
  ** reached). Unfortunately this wouldn't work in the real life,
  ** because either target may be unreachable or may not comply
  ** with the request. In either case it would leave target in
  ** links--no command to clear it away. So, it's better just
  ** clean out while going forward, just to be sure.
  **
  ** ...of course, even better cleanout would be to QUIT/SQUIT
  ** dependant users/servers already on the way out, but
  ** currently there is not enough information about remote
  ** clients to do this...   --msa
  */
  if (!acptr)
    {
      sendto_one(sptr, form_str(ERR_NOSUCHSERVER),
                 me.name, parv[0], server);
      return 0;
    }

  if (MyClient(sptr) && !HasUmode(sptr,UMODE_REMOTE) && !MyConnect(acptr))
    {
      sendto_one(sptr,":%s NOTICE %s :You have no R umode",me.name,parv[0]);
      return 0;
    }

  /*
  **  Notify all opers, if my local link is remotely squitted
  */
  if (MyConnect(acptr) && IsServer(cptr))
    {
      sendto_ops_flag(UMODE_AUSPEX,
		      "%s received SQUIT %s from %s (%s)",
		      me.name, server, get_client_name(sptr,FALSE), comment);
      logprintf(L_TRACE, "SQUIT From %s : %s (%s)", parv[0], server, comment);
    }
  else if (MyConnect(acptr))
    sendto_ops_flag(UMODE_SERVNOTICE, "Received SQUIT %s from %s (%s)",
			   acptr->name, get_client_name(sptr,FALSE), comment);
  
  return exit_client(cptr, acptr, sptr, comment);
}
Example #7
0
/*
 * ms_server - SERVER message handler
 *      parv[0] = sender prefix
 *      parv[1] = servername
 *      parv[2] = serverinfo/hopcount
 *      parv[3] = serverinfo
 */
static void ms_server(struct Client *client_p, struct Client *source_p,
                      int parc, char *parv[])
{
  char             info[REALLEN + 1];
                   /* same size as in s_misc.c */
  char*            name;
  struct Client*   target_p;
  struct Client*   bclient_p;
  struct ConfItem* aconf;
  int              hop;
  int              hlined = 0;
  int              llined = 0;
  dlink_node	   *ptr;

  /* Just to be sure -A1kmm. */
  if (!IsServer(source_p))
   return;

  if (parc < 4)
    {
      sendto_one(client_p,"ERROR :No servername");
      return;
    }

  name = parv[1];
  hop = atoi(parv[2]);
  strlcpy(info, parv[3], REALLEN);

  if ((target_p = server_exists(name)))
    {
      /*
       * This link is trying feed me a server that I already have
       * access through another path -- multiple paths not accepted
       * currently, kill this link immediately!!
       *
       * Rather than KILL the link which introduced it, KILL the
       * youngest of the two links. -avalon
       *
       * I think that we should exit the link itself, not the introducer,
       * and we should always exit the most recently received(i.e. the
       * one we are receiving this SERVER for. -A1kmm
       *
       * You *cant* do this, if you link somewhere, it bursts you a server
       * that already exists, then sends you a client burst, you squit the
       * server, but you keep getting the burst of clients on a server that
       * doesnt exist, although ircd can handle it, its not a realistic
       * solution.. --fl_ 
       */
      /* It is behind a host-masked server. Completely ignore the
       * server message(don't propagate or we will delink from whoever
       * we propagate to). -A1kmm */
      if (irccmp(target_p->name, name) && target_p->from==client_p)
        return;

      sendto_one(client_p, "ERROR :Server %s already exists", name);
	
      sendto_realops_flags(FLAGS_ALL, L_ADMIN,
	                   "Link %s cancelled, server %s already exists",
		 	   get_client_name(client_p, SHOW_IP), name);
      sendto_realops_flags(FLAGS_ALL, L_OPER,
	                   "Link %s cancelled, server %s already exists",
		 	   client_p->name, name);
      
        exit_client(client_p, client_p, &me, "Server Exists");
	return;
    }
  
  /* 
   * User nicks never have '.' in them and server names
   * must always have '.' in them.
   */
  if (strchr(name,'.') == NULL)
    {
      /*
       * Server trying to use the same name as a person. Would
       * cause a fair bit of confusion. Enough to make it hellish
       * for a while and servers to send stuff to the wrong place.
       */
      sendto_one(client_p,"ERROR :Nickname %s already exists!", name);
      sendto_realops_flags(FLAGS_ALL, L_ADMIN,
			   "Link %s cancelled: Server/nick collision on %s",
		/* inpath */ get_client_name(client_p, HIDE_IP), name);
      sendto_realops_flags(FLAGS_ALL, L_OPER,
          "Link %s cancelled: Server/nick collision on %s",
	  get_client_name(client_p, MASK_IP), name);
      exit_client(client_p, client_p, client_p, "Nick as Server");
      return;
    }

  /*
   * Server is informing about a new server behind
   * this link. Create REMOTE server structure,
   * add it to list and propagate word to my other
   * server links...
   */
  if (parc == 1 || info[0] == '\0')
    {
      sendto_one(client_p, "ERROR :No server info specified for %s", name);
      return;
    }

  /*
   * See if the newly found server is behind a guaranteed
   * leaf. If so, close the link.
   *
   */

  for (aconf = ConfigItemList; aconf; aconf=aconf->next)
    {
     if ((aconf->status & (CONF_LEAF|CONF_HUB)) == 0)
       continue;

     if (match(aconf->name, client_p->name))
       {
        if (aconf->status == CONF_HUB)
	  {
	    if(match(aconf->host, name))
	      hlined++;
	  }
        else if (aconf->status == CONF_LEAF)
	  {
	    if(match(aconf->host, name))
	      llined++;
	  }
       }
    }

  /* Ok, this way this works is
   *
   * A server can have a CONF_HUB allowing it to introduce servers
   * behind it.
   *
   * connect {
   *            name = "irc.bighub.net";
   *            hub_mask="*";
   *            ...
   * 
   * That would allow "irc.bighub.net" to introduce anything it wanted..
   *
   * However
   *
   * connect {
   *            name = "irc.somehub.fi";
   *		hub_mask="*";
   *		leaf_mask="*.edu";
   *...
   * Would allow this server in finland to hub anything but
   * .edu's
   */

  /* Ok, check client_p can hub the new server, and make sure it's not a LL */
  if (!hlined || (IsCapable(client_p, CAP_LL) && !IsCapable(client_p, CAP_HUB)))
    {
      /* OOOPs nope can't HUB */
      sendto_realops_flags(FLAGS_ALL, L_ADMIN, "Non-Hub link %s introduced %s.",
                get_client_name(client_p, HIDE_IP), name);

      sendto_realops_flags(FLAGS_ALL, L_OPER,
          "Non-Hub link %s introduced %s.",
	  get_client_name(client_p, MASK_IP), name);

      exit_client(NULL, source_p, &me, "No matching hub_mask.");
      return;
    }

  /* Check for the new server being leafed behind this HUB */
  if (llined)
    {
      /* OOOPs nope can't HUB this leaf */
      sendto_realops_flags(FLAGS_ALL, L_ADMIN,
            "Link %s introduced leafed server %s.",
	    get_client_name(client_p, HIDE_IP), name);
      sendto_realops_flags(FLAGS_ALL, L_OPER, 
            "Link %s introduced leafed server %s.",
            client_p->name, name);
      /* If it is new, we are probably misconfigured, so split the
       * non-hub server introducing this. Otherwise, split the new
       * server. -A1kmm.
       */
      /* wastes too much bandwidth, generates too many errors on
       * larger networks, dont bother. --fl_
       */
#if 0
      if ((CurrentTime - source_p->firsttime) < 20)
        {
          exit_client(NULL, source_p, &me, "Leafed Server.");
          return;
        }
      else
        {
          sendto_one(source_p, ":%s SQUIT %s :Sorry, Leafed server.",
                     me.name, name);
          return;
        }
#endif

      exit_client(NULL, client_p, &me, "Leafed Server.");
      return;
    }
  
  if(strlen(name) > HOSTLEN)
  {
    sendto_realops_flags(FLAGS_ALL, L_ADMIN,
 		         "Link %s introduced server with invalid servername %s",
		         get_client_name(client_p, HIDE_IP), name);
    sendto_realops_flags(FLAGS_ALL, L_OPER,
		         "Link %s introduced server with invalid servername %s",
			 client_p->name, name);
    
    exit_client(NULL, client_p, &me, "Invalid servername introduced.");
    return;
  }

  target_p = make_client(client_p);
  make_server(target_p);
  target_p->hopcount = hop;

  strlcpy(target_p->name, name, HOSTLEN+1);
  
  set_server_gecos(target_p, info);

  target_p->serv->up = find_or_add(parv[0]);
  target_p->servptr = source_p;

  SetServer(target_p);

  Count.server++;

  add_client_to_list(target_p);
  add_server_to_list(target_p);
  add_to_client_hash_table(target_p->name, target_p);
  add_client_to_llist(&(target_p->servptr->serv->servers), target_p);


  /*
   * Old sendto_serv_but_one() call removed because we now
   * need to send different names to different servers
   * (domain name matching)
   */
  for (ptr = serv_list.head; ptr; ptr = ptr->next)
    {
      bclient_p = ptr->data;

      if (bclient_p == client_p)
	continue;
      if (!(aconf = bclient_p->serv->sconf))
	{
	  sendto_realops_flags(FLAGS_ALL, L_ADMIN, 
	        "Lost N-line for %s on %s. Closing",
		get_client_name(client_p, HIDE_IP), name);
	  sendto_realops_flags(FLAGS_ALL, L_OPER, 
	        "Lost N-line for %s on %s. Closing",
		get_client_name(client_p, MASK_IP), name);
	  exit_client(client_p, client_p, client_p, "Lost N line");
          return;
	}
      if (match(my_name_for_link(me.name, aconf), target_p->name))
	continue;

      sendto_one(bclient_p, ":%s SERVER %s %d :%s%s",
		 parv[0], target_p->name, hop + 1,
		 target_p->hidden_server ? "(H) " : "",
		 target_p->info);
    }
    
  if (!IsRelay(target_p))  
  	sendto_realops_flags(FLAGS_EXTERNAL, L_ALL,
                       "Server %s being introduced by %s",
		       			target_p->name, source_p->name);
}