Logo Search packages:      
Sourcecode: rageircd version File versions  Download package

m_server.c

/*
 * RageIRCd: an advanced Internet Relay Chat daemon (ircd).
 * (C) 2000-2005 the RageIRCd Development Team, all rights reserved.
 *
 * This software is free, licensed under the General Public License.
 * Please refer to doc/LICENSE and doc/README for further details.
 *
 * $Id: m_server.c,v 1.89.2.3 2005/05/06 22:57:42 amcwilliam Exp $
 */

#include "config.h"
#include "struct.h"
#include "common.h"
#include "sys.h"
#include "numeric.h"
#include "msg.h"
#include "channel.h"
#include "h.h"
#include "memory.h"
#include "patchlevel.h"
#include "modules.h"
#include <time.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>

Module MOD_HEADER(m_server) = {
      "m_server",
      "SERVER protocol",
      6, "$Revision: 1.89.2.3 $"
};

int MOD_LOAD(m_server)()
{
      if (register_command(&MOD_HEADER(m_server), &CMD_SERVER, m_server) == NULL) {
            return MOD_FAILURE;
      }
      return MOD_SUCCESS;
}

int MOD_UNLOAD(m_server)()
{
      return MOD_SUCCESS;
}

/*
 * m_server
 *    parv[0] = sender prefix
 *    parv[1] = server name
 *    parv[2] = hopcount
 *    Direct server<>server link:
 *          parv[3] = server information
 *    Remote server
 *          parv[3] = base64 servid
 *          parv[4] = server information
 */
int m_server(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
      char *servername, *s, *d, *inpath = get_client_name(cptr, HIDE_IP);
      char clean_servername[(HOSTLEN * 2) + 1], info[REALLEN + 61];
      char *b64id = NULL;
      ConfigItem_link *linkp = NULL;
      aClient *acptr = NULL, *bcptr = NULL;
      int hop = 0, bogus_server = 0, dot = 0, n;

      if (IsPerson(cptr)) {
            return 0;
      }

      ASSERT(cptr->localClient != NULL);

      if (cptr->localClient->listener != NULL) {
            if (cptr->localClient->listener->conf->flags & LISTEN_CLIENTONLY) {
                  sendto_realops_lev(REJ_LEV, "Blocking unknown connection on client-only port %d",
                        cptr->localClient->listener->port);
                  return exit_client(cptr, sptr, &me, "This port is for clients only");
            }
      }
      if (parc < 4) {
            sendto_one_client_nopostfix(cptr, NULL, &CMD_ERROR, ":Not enough parameters");
            return exit_client(cptr, sptr, &me, "Not enough parameters");
      }

      servername = parv[1];
      if (strlen(servername) > HOSTLEN) {
            servername[HOSTLEN] = '\0';
      }

      hop = atoi(parv[2]);
      *info = '\0';

      if (parc > 4 && CapID(cptr)) {
            b64id = parv[3];

            if (!is_id(b64id) || !valid_servid(b64id)) {
                  sendto_one_client_nopostfix(cptr, NULL, &CMD_ERROR, ":Invalid identity");
                  return exit_client(cptr, sptr, &me, "Invalid identity");
            }

            strncpyzt(info, parv[4], REALLEN);
      }
      else {
            strncpyzt(info, parv[3], REALLEN);
      }

      s = servername;
      d = clean_servername;
      n = (HOSTLEN * 2) - 2;

      while (*s != '\0' && n > 0) {
            if ((unsigned char)*s < (unsigned char)' ') {
                  bogus_server = 1;
                  *d++ = '^';
                  *d++ = (char)((unsigned char)*s + 0x40);
                  n -= 2;
            }
            else if ((unsigned char)*s > (unsigned char)'~') {
                  bogus_server = 1;
                  *d++ = '.';
                  n--;
            }
            else {
                  if (*s == '.') {
                        dot = 1;
                  }
                  *d++ = *s;
                  n--;
            }
            s++;
      }
      *d = '\0';

      if (!dot || bogus_server) {
            sendto_one_client_nopostfix(cptr, NULL, &CMD_ERROR, ":Bogus server name (%s)",
                  clean_servername);
            ircdlog(LOG_SERVER, "bogus server name: %s", clean_servername);
            return exit_client(cptr, sptr, &me, "Bogus server name");
      }
      if (BadPtr(cptr->localClient->passwd)) {
            sendto_one_client_nopostfix(cptr, NULL, &CMD_ERROR, ":No password");
            ircdlog(LOG_SERVER, "no password from %s", get_client_name(cptr, FALSE));
            return exit_client(cptr, sptr, &me, "No password");
      }
      if ((acptr = find_server(servername, NULL)) != NULL) {
            bcptr = cptr->firsttime > acptr->from->firsttime ? cptr : acptr->from;
            sendto_one_client_nopostfix(bcptr, NULL, &CMD_ERROR, ":Server %s already "
                  "exists", servername);
            if (bcptr == cptr) {
                  send_gnotice("Link %s cancelled, server %s already exists",
                        inpath, servername);
                  sendto_serv_msg_butone(bcptr, &me, &CMD_GNOTICE, ":Link %s cancelled, "
                        "server %s already exists", get_client_name(bcptr, HIDE_IP),
                        servername);
                  ircdlog(LOG_SERVER, "link %s cancelled: server %s alread exists",
                        get_client_name(cptr, FALSE), get_client_name(bcptr, FALSE));
                  return exit_client(bcptr, bcptr, &me, "Server exists");
            }
            send_gnotice("Link %s cancelled, server %s reintroduced by %s",
                  inpath, servername, get_client_name(bcptr, HIDE_IP));
            sendto_serv_msg_butone(bcptr, &me, &CMD_GNOTICE, ":Link %s cancelled, server %s "
                  "reintroduced by %s", inpath, servername, get_client_name(bcptr, HIDE_IP));
            ircdlog(LOG_SERVER, "link %s cancelled: server %s reintroduced by %s",
                  get_client_name(cptr, FALSE), servername, get_client_name(bcptr, FALSE));
            exit_client(bcptr, bcptr, &me, "Server exists");
      }
      if (b64id != NULL && (acptr = find_serv_by_base64_id(b64id, NULL)) != NULL) {
            send_gnotice("Link %s cancelled, identity collision with %s (%s)", inpath,
                  acptr->name, b64id);
            sendto_serv_msg_butone(cptr, &me, &CMD_GNOTICE, ":Link %s cancelled, identity "
                  "collision with %s (%s)", inpath, acptr->name, b64id);
            sendto_one_client_nopostfix(cptr, NULL, &CMD_ERROR, ":Identity collision");
            ircdlog(LOG_SERVER, "link %s cancelled: identity (%s) collision with %s",
                  get_client_name(cptr, FALSE), b64id, acptr->name);
            return exit_client(cptr, sptr, &me, "Identity collision");
      }
      if ((acptr = find_client(servername, NULL)) != NULL && (acptr != cptr)) {
            send_gnotice("Link %s cancelled, server/nick collision", inpath);
            sendto_one_client_nopostfix(cptr, NULL, &CMD_ERROR, ":Nickname %s already "
                  "exists", servername);
            ircdlog(LOG_SERVER, "link %s cancelled: server/nick collision",
                  get_client_name(cptr, FALSE));
            return exit_client(cptr, sptr, &me, "Server/nick collision");
      }
      if (IsServer(cptr)) {
            if (parc == 1 || *info == '\0') {
                  sendto_one_client_nopostfix(cptr, NULL, &CMD_ERROR, ":No server info specified for %s",
                        servername);
                  ircdlog(LOG_SERVER, "link %s cancelled: no server information", get_client_name(cptr, FALSE));
                  return 0;
            }
            if (NetworkConfig.max_link_depth && (hop > NetworkConfig.max_link_depth)) {
                  send_gnotice("Link %s cancelled, too many servers (hopcount exceeds max link depth)",
                        inpath);
                  sendto_one_client_nopostfix(cptr, NULL, &CMD_ERROR, ":Too many servers");
                  ircdlog(LOG_SERVER, "link %s cancelled: too many servers", get_client_name(cptr, FALSE));
                  return exit_client(cptr, sptr, &me, "Too many servers");
            }

            acptr = make_client(cptr, sptr);
            make_server(acptr);

            acptr->hopcount = hop;
            strncpyzt(acptr->name, servername, sizeof(acptr->name));
            strncpyzt(acptr->info, info, REALLEN);
            acptr->serv->up = find_or_add(parv[0]);

            SetServer(acptr);
            Count.server++;

            if (IsULine(sptr) || find_super(acptr->name) != NULL) {
                  send_gnotice("Link %s introducing super server %s", inpath, acptr->name);
                  SetULine(acptr);
            }

            add_client_to_list(acptr);
            add_to_client_hash_table(acptr->name, acptr);

            if (b64id != NULL) {
                  add_base64_serv(acptr, b64id);
            }

            if (HasSUID(acptr)) {
                  sendto_serv_capab_msg_butone(cptr, sptr, NO_CAPS, ID_CAPS, &CMD_SERVER,
                        "%s %d :%s", acptr->name, acptr->hopcount + 1, acptr->info);
                  sendto_serv_capab_msg_butone(cptr, sptr, ID_CAPS, NO_CAPS, &CMD_SERVER,
                        "%s %d %s :%s", acptr->name, acptr->hopcount + 1, acptr->id.string,
                        acptr->info);
            }
            else {
                  sendto_serv_msg_butone(cptr, sptr, &CMD_SERVER, "%s %d :%s", acptr->name,
                        acptr->hopcount + 1, acptr->info);
            }
            return 0;
      }
      if (!IsUnknown(cptr) && !IsHandshake(cptr)) {
            return 0;
      }

      ASSERT(cptr->localClient != NULL);

      if ((linkp = find_link(servername, cptr->localClient->sockhost)) == NULL) {
            linkp = find_link(servername, cptr->host);
      }
      if (linkp == NULL) {
            send_gnotice("Link %s cancelled, no link configuration", inpath);
            sendto_one_client_nopostfix(cptr, NULL, &CMD_ERROR, ":No link configuration");
            ircdlog(LOG_SERVER, "link %s cancelled: no link configuration", get_client_name(cptr, FALSE));
            return exit_client(cptr, sptr, &me, "No link configuration");
      }
      if ((linkp->class->clients + 1) > linkp->class->max_clients) {
            send_gnotice("Link %s cancelled, class full {%s}", inpath, linkp->class->name);
            sendto_one_client_nopostfix(cptr, NULL, &CMD_ERROR, ":Class full {%s}", linkp->class->name);
            ircdlog(LOG_SERVER, "link %s cancelled: class full {%s}", get_client_name(cptr, FALSE),
                  linkp->class->name);
            return exit_client(cptr, sptr, &me, "Class full");
      }
      if (linkp->auth == NULL) {
            send_gnotice("Link %s cancelled, no link::auth section", linkp->servername);
            sendto_one_client_nopostfix(cptr, NULL, &CMD_ERROR, ":Missing link::auth{} section");
            ircdlog(LOG_SERVER, "link %s cancelled: no link::auth configuration");
            ircdlog(LOG_DEFAULT, "no link::auth configuration for server %s", linkp->servername);
            return exit_client(cptr, sptr, &me, "No link::auth configuration");
      }
      if (!check_auth(linkp->auth, cptr->localClient->passwd)) {
            send_gnotice("Link %s cancelled, authentication failure", inpath);
            sendto_one_client_nopostfix(cptr, NULL, &CMD_ERROR, ":Authentication failure");
            ircdlog(LOG_SERVER, "link %s cancelled: authentication failure", get_client_name(cptr, FALSE));
            return exit_client(cptr, sptr, &me, "Authentication failure");
      }

      if (!ServerInfo->hub && dlink_length(&lserver_list)) {
            if (cptr != lserver_list.head->data || (lserver_list.head->next != NULL)) {
                  ircstp->is_ref++;
                  sendto_one_client_nopostfix(cptr, NULL, &CMD_ERROR, ":I'm a leaf, not a hub!");
                  ircdlog(LOG_SERVER, "link %s cancelled: i'm a leaf!", get_client_name(cptr, FALSE));
                  return exit_client(cptr, cptr, cptr, "I'm a leaf");
            }
      }

      strncpyzt(cptr->name, servername, sizeof(cptr->name));
      strncpyzt(cptr->info, (info != NULL) ? info : "IRCers United", REALLEN);
      cptr->hopcount = hop;

#ifdef USE_ZLIB
      if (linkp->flags & LINK_COMPRESS) {
            SetWantZIP(cptr);
      }
#endif
#ifdef USE_OPENSSL
      if (linkp->flags & LINK_SECURE) {
            SetWantDKEY(cptr);
      }
#endif

      if (IsUnknown(cptr)) {
            unsigned int my_capabs = Internal.default_capabs;

#ifdef USE_OPENSSL
            if (WantDKEY(cptr)) {
                  my_capabs |= CAP_DKEY;
            }
#endif

            sendto_one_client_nopostfix(cptr, NULL, &CMD_PASS, "%s :TS", linkp->auth->string);
            sendto_one_client_nopostfix(cptr, NULL, &CMD_CAPAB, "%s", get_my_cap(my_capabs));
            sendto_one_client_nopostfix(cptr, NULL, &CMD_MYID, "%s", me.id.string);
            sendto_one_client_nopostfix(cptr, NULL, &CMD_SERVER, "%s 1 :%s", me.name, me.info);
      }

      if (!CapTS(cptr)) {
            send_gnotice("Warning! Link %s is not a TS server", inpath);
            ircdlog(LOG_SERVER, "WARNING: link %s is not a TS server", get_client_name(cptr, FALSE));
      }

      sendto_one_client_nopostfix(cptr, NULL, &CMD_SVINFO, "%d %d 0 %ld %s %s", TS_CURRENT,
            TS_MIN, timeofday, CODENAME, Internal.masking_keys);

      make_server(cptr);
      cptr->serv->up = me.name;
      attach_link(cptr, linkp);
      attach_class(cptr);

#ifdef USE_THROTTLE
      throttle_remove((char *)inetntoa((const char *)&cptr->ip));
#endif

#ifdef USE_OPENSSL
      if (CapDKEY(cptr) && WantDKEY(cptr)) {
            SetDoingDKEY(cptr);
            sendto_one_client_nopostfix(cptr, NULL, &CMD_DKEY, "START");
            return 0;
      }
#endif
      return do_server_estab(cptr);
}

Generated by  Doxygen 1.6.0   Back to index