Example #1
0
/*
 * ms_oper - server message handler
 */
int ms_oper(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
{
  struct Client *acptr;
  struct ConfItem *aconf;

  assert(0 != cptr);
  assert(IsServer(cptr));
  /*
   * if message arrived from server, trust it, and set to oper
   */

  if (!IsServer(sptr) && !IsOper(sptr)) {
    if (parc < 4)
      return send_reply(sptr, ERR_NOOPERHOST);

    if (!(acptr = FindNServer(parv[1])))
      return send_reply(sptr, ERR_NOOPERHOST);
    else if (!IsMe(acptr)) {
      sendcmdto_one(sptr, CMD_OPER, acptr, "%C %s %s", acptr, parv[2],
                    parv[3]);
      return 0;
    }

    if (can_oper(cptr, sptr, parv[2], parv[3], &aconf))
      do_oper(cptr, sptr, aconf);
  } else if (!IsServer(sptr))
    send_reply(sptr, RPL_YOUREOPER);

  return 0;
}
Example #2
0
/*
 * ms_rping - server message handler
 * -- by Run
 *
 *    parv[0] = sender (sptr->name thus)
 * if sender is a person: (traveling towards start server)
 *    parv[1] = pinged server[mask]
 *    parv[2] = start server (current target)
 *    parv[3] = optional remark
 * if sender is a server: (traveling towards pinged server)
 *    parv[1] = pinged server (current target)
 *    parv[2] = original sender (person)
 *    parv[3] = start time in s
 *    parv[4] = start time in us
 *    parv[5] = the optional remark
 */
int ms_rping(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
{
  struct Client* destination = 0;
  assert(0 != cptr);
  assert(0 != sptr);
  assert(IsServer(cptr));

  /*
   * shouldn't happen
   */
  if (!IsPrivileged(sptr))
    return 0;

  if (IsServer(sptr)) {
    if (parc < 6) {
      /*
       * PROTOCOL ERROR
       */
      return need_more_params(sptr, "RPING");
    }
    if ((destination = FindNServer(parv[1]))) {
      /*
       * if it's not for me, pass it on
       */
      if (IsMe(destination))
	sendcmdto_one(&me, CMD_RPONG, sptr, "%s %s %s %s :%s", cli_name(sptr),
		      parv[2], parv[3], parv[4], parv[5]);
      else
	sendcmdto_one(sptr, CMD_RPING, destination, "%C %s %s %s :%s",
		      destination, parv[2], parv[3], parv[4], parv[5]);
    }
  }
  else {
    if (parc < 3) {
      return need_more_params(sptr, "RPING");
    }
    /*
     * Haven't made it to the start server yet, if I'm not the start server
     * pass it on.
     */
    if (hunt_server_cmd(sptr, CMD_RPING, cptr, 1, "%s %C :%s", 2, parc, parv)
	!= HUNTED_ISME)
      return 0;
    /*
     * otherwise ping the destination from here
     */
    if ((destination = find_match_server(parv[1]))) {
      assert(IsServer(destination) || IsMe(destination));
      sendcmdto_one(&me, CMD_RPING, destination, "%C %C %s :%s", destination,
		    sptr, militime(0, 0), parv[3]);
    }
    else
      send_reply(sptr, ERR_NOSUCHSERVER, parv[1]);
  }
  return 0;
}
/*
 * ms_jupe - server message handler
 *
 * parv[0] = Send prefix
 *
 * From server:
 *
 * parv[1] = Target: server numeric or *
 * parv[2] = (+|-)<server name>
 * parv[3] = Expiration offset
 * parv[4] = Last modification time
 * parv[5] = Comment
 *
 */
int ms_jupe(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
{
    struct Client *acptr = 0;
    struct Jupe *ajupe;
    unsigned int flags = 0;
    time_t expire_off, lastmod;
    char *server = parv[2], *target = parv[1], *reason = parv[5];

    if (parc < 6)
        return need_more_params(sptr, "JUPE");

    if (!(target[0] == '*' && target[1] == '\0')) {
        if (!(acptr = FindNServer(target)))
            return 0; /* no such server */

        if (!IsMe(acptr)) { /* manually propagate, since we don't set it */
            sendcmdto_one(sptr, CMD_JUPE, acptr, "%s %s %s %s :%s", target, server,
                          parv[3], parv[4], reason);
            return 0;
        }

        flags |= JUPE_LOCAL;
    }

    if (*server == '-')
        server++;
    else if (*server == '+') {
        flags |= JUPE_ACTIVE;
        server++;
    }

    expire_off = atoi(parv[3]);
    lastmod = atoi(parv[4]);

    ajupe = jupe_find(server);

    if (ajupe) {
        if (JupeIsLocal(ajupe) && !(flags & JUPE_LOCAL)) /* global over local */
            jupe_free(ajupe);
        else if (JupeLastMod(ajupe) < lastmod) { /* new modification */
            if (flags & JUPE_ACTIVE)
                return jupe_activate(cptr, sptr, ajupe, lastmod, flags);
            else
                return jupe_deactivate(cptr, sptr, ajupe, lastmod, flags);
        } else if (JupeLastMod(ajupe) == lastmod || IsBurstOrBurstAck(cptr))
            return 0;
        else
            return jupe_resend(cptr, ajupe); /* other server desynched WRT jupes */
    }

    return jupe_add(cptr, sptr, server, reason, expire_off, lastmod, flags);
}
Example #4
0
int ms_set(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
{
    struct Client *acptr;
    if (parc < 4)
        return need_more_params(sptr, "SET");
    if (!(acptr = FindNServer(parv[1])))
        return 0;
    if (!IsMe(acptr)) {
        sendcmdto_serv_butone(sptr, CMD_SET, cptr, "%C %s :%s",
                              acptr, parv[2], parv[3]);
        return 0;
    }
    return feature_set(sptr, (const char* const*)parv + 2, parc - 2);
}
Example #5
0
/** Look up a user by numnick string.
 * See @ref numnicks for more details.
 * @param[in] yxx %Numeric nickname of user.
 * @return %User with that numnick (or NULL).
 */
struct Client* findNUser(const char* yxx)
{
    struct Client* server = 0;
    if (5 == strlen(yxx)) {
        if (0 != (server = FindXNServer(yxx))) {
            Debug((DEBUG_DEBUG, "findNUser: %s(%d)", yxx,
                   base64toint(yxx + 2) & cli_serv(server)->nn_mask));
            return cli_serv(server)->client_list[base64toint(yxx + 2) & cli_serv(server)->nn_mask];
        }
    }
    else if (0 != (server = FindNServer(yxx))) {
        Debug((DEBUG_DEBUG, "findNUser: %s(%d)",
               yxx, base64toint(yxx + 1) & cli_serv(server)->nn_mask));
        return cli_serv(server)->client_list[base64toint(yxx + 1) & cli_serv(server)->nn_mask];
    }
    return 0;
}
Example #6
0
/*
 *  ms_squit (server)
 *
 *    parv[0] = sender prefix
 *    parv[1] = server name
 *    parv[2] = timestamp
 *    parv[parc-1] = comment
 *
 * No longer supports wildcards from servers. 
 * No longer squits a server that gave us an malformed squit message.
 *    - Isomer 1999-12-18
 * 
 */
int ms_squit(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
{
  const char* server = parv[1];
  struct Client *acptr;
  time_t timestamp = 0;
  char *comment = 0;
  
  if (parc < 2) 
    return need_more_params(sptr, "SQUIT");

  comment = parv[parc-1];
  
  if (BadPtr(parv[parc - 1]))
  	comment = cli_name(sptr);
  	
  acptr = FindServer(server);

  if (!acptr)
    acptr = FindNServer(server);

  if (!acptr) {
    Debug((DEBUG_NOTICE, "Ignoring SQUIT to an unknown server"));
    return 0;
  }
  
  /* If they are squitting me, we reverse it */
  if (IsMe(acptr))
    acptr = cptr; /* Bugfix by Prefect */

  if (parc > 2)
    timestamp = atoi(parv[2]);
  else
    protocol_violation(cptr, "SQUIT with no timestamp/reason");

  /* If atoi(parv[2]) == 0 we must indeed squit !
   * It will be our neighbour.
   */
  if ( timestamp != 0 && timestamp != cli_serv(acptr)->timestamp)
  {
    Debug((DEBUG_NOTICE, "Ignoring SQUIT with the wrong timestamp"));
    return 0;
  }
  
  return exit_client(cptr, acptr, sptr, comment);
}
Example #7
0
/** Handle an RPONG message from a server
 * -- by Run too :)
 *
 * This message is used for reporting the results of remotely
 * initiated pings.  See ms_rping() for the theory of operation.
 *
 * Going from the rping target to the rping source, \a parv has the
 * following elements:
 * \li \a parv[1] is the rping source's name (numnick is also allowed)
 * \li \a parv[2] is the rping requester's numnick
 * \li \a parv[3] is the rping start time (seconds part)
 * \li \a parv[4] is the rping start time (microseconds part)
 * \li \a parv[5] is the requester's remark
 *
 * Going from the rping source to the rping requester, \a parv has the
 * following elements:
 * \li \a parv[1] is the rping source's name (numnick is also allowed)
 * \li \a parv[2] is the rping requester's numnick
 * \li \a parv[3] is the rping round trip time in milliseconds
 * \li \a parv[4] is the requester's remark
 *
 * See @ref m_functions for discussion of the arguments.
 * @param[in] cptr Client that sent us the message.
 * @param[in] sptr Original source of message.
 * @param[in] parc Number of arguments.
 * @param[in] parv Argument vector.
 */
int ms_rpong(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
{
  struct Client *acptr;

  if (!IsServer(sptr))
    return 0;

  if (parc < 5) {
    /*
     * PROTOCOL ERROR
     */
    return need_more_params(sptr, "RPONG");
  }
  if (parc == 6) {
    /*
     * from pinged server to source server
     */
    if (!(acptr = FindServer(parv[1])) && !(acptr = FindNServer(parv[1])))
      return 0;
   
    if (IsMe(acptr)) {
      if (!(acptr = findNUser(parv[2])))
        return 0;

      sendcmdto_one(&me, CMD_RPONG, acptr, "%C %s %s :%s", acptr, cli_name(sptr),
		    militime(parv[3], parv[4]), parv[5]);
    } else
      sendcmdto_one(sptr, CMD_RPONG, acptr, "%s %s %s %s :%s", parv[1],
		    parv[2], parv[3], parv[4], parv[5]);
  } else {
    /*
     * returned from source server to client
     */
    if (!(acptr = findNUser(parv[1])))
      return 0;

    sendcmdto_one(sptr, CMD_RPONG, acptr, "%C %s %s :%s", acptr, parv[2],
		  parv[3], parv[4]);
  }
  return 0;
}
Example #8
0
/*
 * ms_xreply - extension message reply handler
 *
 * parv[0] = sender prefix
 * parv[1] = target server numeric
 * parv[2] = routing information
 * parv[3] = extension message reply
 */
int ms_xreply(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
{
  struct Client* acptr;
  const char* routing;
  const char* reply;

  if (parc < 4) /* have enough parameters? */
    return need_more_params(sptr, "XREPLY");

  routing = parv[2];
  reply = parv[3];

  /* Look up the target */
  if (!(acptr = findNUser(parv[1])) && !(acptr = FindNServer(parv[1])))
    return send_reply(sptr, SND_EXPLICIT | ERR_NOSUCHSERVER,
		      "* :Server has disconnected");

  /* If it's not to us, forward the reply */
  if (!IsMe(acptr)) {
    sendcmdto_one(sptr, CMD_XREPLY, acptr, "%C %s :%s", acptr, routing,
		  reply);
    return 0;
  }

  /* OK, figure out where to route the message */
  if (!ircd_strncmp("iauth:", routing, 6)) {
    /* Forward the reply to the iauth */
    routing += 6;

    auth_send_xreply(sptr, routing, reply);
  } else
    /* If we don't know where to route it, log it and drop it */
    log_write(LS_SYSTEM, L_NOTICE, 0, "Received unroutable extension reply "
	      "from %#C to %#C routing %s; message: %s", sptr, acptr,
	      routing, reply);

  return 0;
}
Example #9
0
/*
 * ms_gline - server message handler
 *
 * parv[0] = Sender prefix
 * parv[1] = Target: server numeric
 * parv[2] = (+|-)<G-line mask>
 * parv[3] = G-line lifetime
 *
 * From Uworld:
 *
 * parv[4] = Comment
 *
 * From somewhere else:
 *
 * parv[4] = Last modification time
 * parv[5] = Comment
 *
 */
int
ms_gline(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
{
  struct Client *acptr = 0;
  struct Gline *agline;
  unsigned int flags = 0;
  time_t expire_off, lastmod = 0;
  char *mask = parv[2], *target = parv[1], *reason = "No reason";

  if (*mask == '!')
  {
    mask++;
    flags |= GLINE_OPERFORCE; /* assume oper had WIDE_GLINE */
  }

  if ((parc == 3 && *mask == '-') || parc == 5)
  {
    if (!find_conf_byhost(cli_confs(cptr), cli_name(sptr), CONF_UWORLD))
      return need_more_params(sptr, "GLINE");

    flags |= GLINE_FORCE;
  }
  else if (parc > 5)
    lastmod = atoi(parv[4]);
  else
    return need_more_params(sptr, "GLINE");

  if (parc > 4)
    reason = parv[parc - 1];

  if (IsServer(sptr))
    flags |= GLINE_FORCE;

  if (!(target[0] == '*' && target[1] == '\0')) {
    if (!( (acptr = FindNServer(target)) || 
           (acptr = SeekServer(target)) ) )
      return 0; /* no such server */

    if (!IsMe(acptr)) { /* manually propagate */
      if (!lastmod)
	sendcmdto_one(sptr, CMD_GLINE, acptr,
		      (parc == 3) ? "%s %s" : "%s %s %s :%s", target, mask,
		      parv[3], reason);
      else
	sendcmdto_one(sptr, CMD_GLINE, acptr, "%s %s%s %s %s :%s", target,
		      flags & GLINE_OPERFORCE ? "!" : "", mask, parv[3],
		      parv[4], reason);

      return 0;
    }

    /* For asuka we don't want glines sent this way treated as local
     * flags |= GLINE_LOCAL;
     */
  }

  if (*mask == '-')
    mask++;
  else if (*mask == '+') {
    flags |= GLINE_ACTIVE;
    mask++;
  } else
    flags |= GLINE_ACTIVE;

  expire_off = parc < 5 ? 0 : atoi(parv[3]);

  agline = gline_find(mask, GLINE_ANY | GLINE_EXACT);

  if (agline) {
    if (GlineIsLocal(agline) && !(flags & GLINE_LOCAL)) /* global over local */
      gline_free(agline);
    else if (!lastmod && ((flags & GLINE_ACTIVE) == GlineIsRemActive(agline)))
      return gline_propagate(cptr, sptr, agline);
    else if (!lastmod || GlineLastMod(agline) < lastmod) { /* new mod */
      if (flags & GLINE_ACTIVE)
	return gline_activate(cptr, sptr, agline, lastmod, flags);
      else
	return gline_deactivate(cptr, sptr, agline, lastmod, flags);
    } else if (GlineLastMod(agline) == lastmod || IsBurstOrBurstAck(cptr))
      return 0;
    else
      return gline_resend(cptr, agline); /* other server desynched WRT gline */
  } else if (parc == 3 && !(flags & GLINE_ACTIVE)) {
    /* U-lined server removing a G-line we don't have; propagate the removal
     * anyway.
     */
    if (!(flags & GLINE_LOCAL))
      sendcmdto_serv_butone(sptr, CMD_GLINE, cptr, "* -%s", mask);
    return 0;
  } else if (parc < 5)
    return need_more_params(sptr, "GLINE");

  return gline_add(cptr, sptr, mask, reason, expire_off, lastmod, flags);
}
Example #10
0
/*
 * ms_zline - server message handler
 *
 * parv[0] = Sender prefix
 * parv[1] = Target: server numeric
 * parv[2] = (+|-)<Z-line mask>
 *
 * For other parameters, see doc/readme.zline.
 */
int
ms_zline(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
{
  struct Client *acptr = 0;
  struct Zline *azline = 0;
  unsigned int flags = 0;
  enum ZlineAction action = ZLINE_MODIFY;
  time_t expire = 0, lastmod = 0, lifetime = 0;
  char *mask = parv[2], *target = parv[1], *reason = "No reason", *tmp = 0;

  if (parc < 3)
    return need_more_params(sptr, "ZLINE");

  if (IsServer(sptr))
    flags |= ZLINE_FORCE;

  if (*mask == '!') {
    mask++;
    flags |= ZLINE_OPERFORCE; /* assume oper had WIDE_ZLINE */
  }

  switch (*mask) { /* handle +, -, <, and > */
  case '+': /* activate the ZG-line */
    action = ZLINE_ACTIVATE;
    mask++;
    break;

  case '-': /* deactivate the Z-line */
    action = ZLINE_DEACTIVATE;
    mask++;
    break;

  case '>': /* locally activate the Z-line */
    action = ZLINE_LOCAL_ACTIVATE;
    mask++;
    break;

  case '<': /* locally deactivate the Z-line */
    action = ZLINE_LOCAL_DEACTIVATE;
    mask++;
    break;
  }

  /* Is there no mask left? */
  if (mask[0] == '\0')
    return need_more_params(sptr, "ZLINE");

  /* Now, let's figure out if it's a local or global Z-line */
  if (action == ZLINE_LOCAL_ACTIVATE || action == ZLINE_LOCAL_DEACTIVATE ||
      (target[0] == '*' && target[1] == '\0'))
    flags |= ZLINE_GLOBAL;
  else
    flags |= ZLINE_LOCAL;

  /* now figure out if we need to resolve a server */
  if ((action == ZLINE_LOCAL_ACTIVATE || action == ZLINE_LOCAL_DEACTIVATE ||
       (flags & ZLINE_LOCAL)) && !(acptr = FindNServer(target)))
    return 0; /* no such server, jump out */

  /* If it's a local activate/deactivate and server isn't me, propagate it */
  if ((action == ZLINE_LOCAL_ACTIVATE || action == ZLINE_LOCAL_DEACTIVATE) &&
      !IsMe(acptr)) {
    Debug((DEBUG_DEBUG, "I am forwarding a local change to a global zline "
	   "to a remote server; target %s, mask %s, operforce %s, action %c",
	   target, mask, flags & ZLINE_OPERFORCE ? "YES" : "NO",
	   action == ZLINE_LOCAL_ACTIVATE ? '>' : '<'));

    sendcmdto_one(sptr, CMD_ZLINE, acptr, "%C %s%c%s", acptr,
		  flags & ZLINE_OPERFORCE ? "!" : "",
		  action == ZLINE_LOCAL_ACTIVATE ? '>' : '<', mask);

    return 0; /* all done */
  }

  /* Next, try to find the Z-line... */
  if ((flags & ZLINE_GLOBAL) || IsMe(acptr)) /* don't bother if it's not me! */
    azline = zline_find(mask, flags | ZLINE_ANY | ZLINE_EXACT);

  /* We now have all the pieces to tell us what we've got; let's put
   * it all together and convert the rest of the arguments.
   */

  /* Handle the local Z-lines first... */
  if (flags & ZLINE_LOCAL) {
    assert(acptr);

    /* normalize the action, first */
    if (action == ZLINE_LOCAL_ACTIVATE || action == ZLINE_MODIFY)
      action = ZLINE_ACTIVATE;
    else if (action == ZLINE_LOCAL_DEACTIVATE)
      action = ZLINE_DEACTIVATE;

    if (action == ZLINE_ACTIVATE) { /* get expiration and reason */
      if (parc < 5) /* check parameter count... */
	return need_more_params(sptr, "ZLINE");

      expire = atoi(parv[3]); /* get expiration... */
      expire = abs_expire(expire); /* convert to absolute... */
      reason = parv[parc - 1]; /* and reason */

      if (IsMe(acptr)) {
	if (azline) /* Z-line already exists, so let's ignore it... */
	  return 0;

	/* OK, create the local Z-line */
	Debug((DEBUG_DEBUG, "I am creating a local Z-line here; target %s, "
	       "mask %s, operforce %s, action %s, expire %Tu, reason: %s",
	       target, mask, flags & ZLINE_OPERFORCE ? "YES" : "NO",
	       action == ZLINE_ACTIVATE ? "+" : "-", expire, reason));

	return zline_add(cptr, sptr, mask, reason, expire, lastmod,
			 lifetime, flags | ZLINE_ACTIVE);
      }
    } else if (IsMe(acptr)) { /* destroying a local Z-line */
      if (!azline) /* Z-line doesn't exist, so let's complain... */
	return send_reply(sptr, ERR_NOSUCHZLINE, mask);

      /* Let's now destroy the Z-line */;
      Debug((DEBUG_DEBUG, "I am destroying a local Z-line here; target %s, "
	     "mask %s, operforce %s, action %s", target, mask,
	     flags & ZLINE_OPERFORCE ? "YES" : "NO",
	     action == ZLINE_ACTIVATE ? "+" : "-"));

      return zline_destroy(cptr, sptr, azline);
    }

    /* OK, we've converted arguments; if it's not for us, forward */
    /* UPDATE NOTE: Once all servers are updated to u2.10.12.11, the
     * format string in this sendcmdto_one() may be updated to omit
     * <lastmod> for ZLINE_ACTIVATE and to omit <expire>, <lastmod>,
     * and <reason> for ZLINE_DEACTIVATE.
     */
    assert(!IsMe(acptr));

    Debug((DEBUG_DEBUG, "I am forwarding a local Z-line to a remote server; "
	   "target %s, mask %s, operforce %s, action %c, expire %Tu, "
	   "lastmod %Tu, reason: %s", target, mask,
	   flags & ZLINE_OPERFORCE ? "YES" : "NO",
	   action == ZLINE_ACTIVATE ? '+' :  '-', expire, TStime(),
	   reason));

    sendcmdto_one(sptr, CMD_ZLINE, acptr, "%C %s%c%s %Tu %Tu :%s",
		  acptr, flags & ZLINE_OPERFORCE ? "!" : "",
		  action == ZLINE_ACTIVATE ? '+' : '-', mask,
		  expire - TStime(), TStime(), reason);

    return 0; /* all done */
  }

  /* can't modify a Z-line that doesn't exist, so remap to activate */
  if (!azline && action == ZLINE_MODIFY)
    action = ZLINE_ACTIVATE;

  /* OK, let's figure out what other parameters we may have... */
  switch (action) {
  case ZLINE_LOCAL_ACTIVATE: /* locally activating a Z-line */
  case ZLINE_LOCAL_DEACTIVATE: /* locally deactivating a Z-line */
    if (!azline) /* no Z-line to locally activate or deactivate? */
      return send_reply(sptr, ERR_NOSUCHZLINE, mask);
    lastmod = azline->zl_lastmod;
    break; /* no additional parameters to manipulate */

  case ZLINE_ACTIVATE: /* activating a Z-line */
  case ZLINE_DEACTIVATE: /* deactivating a Z-line */
    /* in either of these cases, we have at least a lastmod parameter */
    if (parc < 4)
      return need_more_params(sptr, "ZLINE");
    else if (parc == 4) /* lastmod only form... */
      lastmod = atoi(parv[3]);
    /*FALLTHROUGH*/
  case ZLINE_MODIFY: /* modifying a Z-line */
    /* convert expire and lastmod, look for lifetime and reason */
    if (parc > 4) { /* protect against fall-through from 4-param form */
      expire = atoi(parv[3]); /* convert expiration and lastmod */
      expire = abs_expire(expire);
      lastmod = atoi(parv[4]);

      flags |= ZLINE_EXPIRE; /* we have an expiration time update */

      if (parc > 6) { /* no question, have a lifetime and reason */
	lifetime = atoi(parv[5]);
	reason = parv[parc - 1];

	flags |= ZLINE_LIFETIME | ZLINE_REASON;
      } else if (parc == 6) { /* either a lifetime or a reason */
	if (!azline || /* zline creation, has to be the reason */
	    /* trial-convert as lifetime, and if it doesn't fully convert,
	     * it must be the reason */
	    (!(lifetime = strtoul(parv[5], &tmp, 10)) && !*tmp)) {
	  lifetime = 0;
	  reason = parv[5];

	  flags |= ZLINE_REASON; /* have a reason update */
	} else if (lifetime)
	  flags |= ZLINE_LIFETIME; /* have a lifetime update */
      }
    }
  }

  if (!lastmod) /* must have a lastmod parameter by now */
    return need_more_params(sptr, "ZLINE");

  Debug((DEBUG_DEBUG, "I have a global Z-line I am acting upon now; "
	 "target %s, mask %s, operforce %s, action %s, expire %Tu, "
	 "lastmod %Tu, lifetime %Tu, reason: %s; zline %s!  (fields "
	 "present: %s %s %s)", target, mask,
	 flags & ZLINE_OPERFORCE ? "YES" : "NO",
	 action == ZLINE_ACTIVATE ? "+" :
	 (action == ZLINE_DEACTIVATE ? "-" :
	  (action == ZLINE_LOCAL_ACTIVATE ? ">" :
	   (action == ZLINE_LOCAL_DEACTIVATE ? "<" : "(MODIFY)"))),
	 expire, lastmod, lifetime, reason,
	 azline ? "EXISTS" : "does not exist",
	 flags & ZLINE_EXPIRE ? "expire" : "",
	 flags & ZLINE_LIFETIME ? "lifetime" : "",
	 flags & ZLINE_REASON ? "reason" : ""));

  /* OK, at this point, we have converted all available parameters.
   * Let's actually do the action!
   */
  if (azline)
    return zline_modify(cptr, sptr, azline, action, reason, expire,
			lastmod, lifetime, flags);

  assert(action != ZLINE_LOCAL_ACTIVATE);
  assert(action != ZLINE_LOCAL_DEACTIVATE);
  assert(action != ZLINE_MODIFY);

  if (!expire) { /* Cannot *add* a Z-line we don't have, but try hard */
    Debug((DEBUG_DEBUG, "Propagating Z-line %s for Z-line we don't have",
	   action == ZLINE_ACTIVATE ? "activation" : "deactivation"));

    /* propagate the Z-line, even though we don't have it */
    sendcmdto_serv_butone(sptr, CMD_ZLINE, cptr, "* %c%s %Tu",
			  action == ZLINE_ACTIVATE ? '+' : '-',
			  mask, lastmod);

    return 0;
  }

  return zline_add(cptr, sptr, mask, reason, expire, lastmod, lifetime,
		   flags | ((action == ZLINE_ACTIVATE) ? ZLINE_ACTIVE : 0));
}
Example #11
0
int ms_challenge(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
{
#ifdef USE_SSL
  struct ConfItem *aconf;
  RSA *rsa_public_key;
  BIO *file = NULL;
  char *challenge = NULL;
  char *name;
  char *tmpname;
  char             chan[CHANNELLEN-1];
  char*            join[2];
  int nl;
  struct Client *acptr = NULL;
  char *privbuf;

  if (!IsServer(cptr))
    return 0;

  /* if theyre an oper, reprint oper motd and ignore */
  if (IsOper(sptr))
  {
    send_reply(sptr, RPL_YOUREOPER);
    if (feature_bool(FEAT_OPERMOTD))
      m_opermotd(sptr, sptr, 1, parv);
  }

  if (parc < 3) {
    return send_reply(sptr, ERR_NOOPERHOST);
  }

  if (!(acptr = FindNServer(parv[1]))) {
    return send_reply(sptr, ERR_NOOPERHOST);
  } else if (!IsMe(acptr)) {
    sendcmdto_one(sptr, CMD_CHALLENGE, acptr, "%C %s %s", acptr, parv[2],
                  parv[3]);
    return 0;
  }

  if (*parv[2] == '+')
  {
    /* Ignore it if we aren't expecting this... -A1kmm */
    if (cli_user(sptr)->response == NULL)
      return 0;

    if (ircd_strcmp(cli_user(sptr)->response, ++parv[2]))
    {
      send_reply(sptr, ERR_PASSWDMISMATCH);
      sendto_allops(&me, SNO_OLDREALOP, "Failed OPER attempt by %s (%s@%s) (Password Incorrect)",
                         parv[0], cli_user(sptr)->realusername, cli_sockhost(sptr));
      tmpname = strdup(cli_user(sptr)->auth_oper);
      failed_challenge_notice(sptr, tmpname, "challenge failed");
      return 0;
    }

    name = strdup(cli_user(sptr)->auth_oper);
     
    aconf = find_conf_exact(cli_user(sptr)->auth_oper, cli_user(sptr)->realusername,
                            MyUser(sptr) ? cli_sockhost(sptr) :
                            cli_user(sptr)->realhost, CONF_OPS);

    if (!aconf)
      aconf = find_conf_exact(cli_user(sptr)->auth_oper, cli_user(sptr)->realusername,
                              ircd_ntoa((const char*) &(cli_ip(sptr))), CONF_OPS);

    if (!aconf)
      aconf = find_conf_cidr(cli_user(sptr)->auth_oper, cli_user(sptr)->realusername,
                              cli_ip(sptr), CONF_OPS);

    if (!aconf)
    {
      send_reply(sptr, ERR_NOOPERHOST);
      sendto_allops(&me, SNO_OLDREALOP, "Failed OPER attempt by %s (%s@%s) (No O:line)",
                         parv[0], cli_user(sptr)->realusername, cli_sockhost(sptr));
      return 0;
    }

    if (CONF_LOCOP == aconf->status) {
      ClearOper(sptr);
      SetLocOp(sptr);
    }
    else {
      /* This must be called before client_set_privs() */
      SetRemoteOper(sptr);

      if (!feature_bool(FEAT_OPERFLAGS) || (aconf->port & OFLAG_WHOIS)) {
        OSetWhois(sptr);
      }
      if (!feature_bool(FEAT_OPERFLAGS) || (aconf->port & OFLAG_IDLE)) {
        OSetIdle(sptr);
      }
      if (!feature_bool(FEAT_OPERFLAGS) || (aconf->port & OFLAG_XTRAOP)) {
        OSetXtraop(sptr);
      }
      if (!feature_bool(FEAT_OPERFLAGS) || (aconf->port & OFLAG_HIDECHANS)) {
        OSetHideChans(sptr);
      }

      /* prevent someone from being both oper and local oper */
      ClearLocOp(sptr);

      if (!feature_bool(FEAT_OPERFLAGS) || !(aconf->port & OFLAG_ADMIN)) {
        /* Global Oper */
        ClearAdmin(sptr);
        OSetGlobal(sptr);
        SetOper(sptr);
      } else {
        /* Admin */
        OSetGlobal(sptr);
        OSetAdmin(sptr);
        SetOper(sptr);
        SetAdmin(sptr);
      }

      /* Tell client_set_privs to send privileges to the user */
      client_set_privs(sptr, aconf);

      ClearOper(sptr);
      ClearAdmin(sptr);

      ClearRemoteOper(sptr);
      privbuf = client_print_privs(sptr);
      sendcmdto_one(&me, CMD_PRIVS, sptr, "%C %s", sptr, privbuf);
    }

    sendcmdto_one(&me, CMD_MODE, sptr, "%s %s", cli_name(sptr),
                  (OIsAdmin(sptr)) ? "+aoiwsg" : "+oiwsg");

    send_reply(sptr, RPL_YOUREOPER);

    if (OIsAdmin(sptr)) {
      sendto_allops(&me, SNO_OLDSNO, "%s (%s@%s) is now an IRC Administrator",
                    parv[0], cli_user(sptr)->username, cli_sockhost(sptr));

      /* Autojoin admins to admin channel and oper channel (if enabled) */
      if (feature_bool(FEAT_AUTOJOIN_ADMIN)) {
        if (feature_bool(FEAT_AUTOJOIN_ADMIN_NOTICE))
              sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s", sptr, feature_str(FEAT_AUTOJOIN_ADMIN_NOTICE_VALUE));

        ircd_strncpy(chan, feature_str(FEAT_AUTOJOIN_ADMIN_CHANNEL), CHANNELLEN-1);
        join[0] = cli_name(sptr);
        join[1] = chan;
        m_join(sptr, sptr, 2, join);
      }
      if (feature_bool(FEAT_AUTOJOIN_OPER) && OIsGlobal(sptr)) {
        if (feature_bool(FEAT_AUTOJOIN_OPER_NOTICE))
              sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s", sptr, feature_str(FEAT_AUTOJOIN_OPER_NOTICE_VALUE));

        ircd_strncpy(chan, feature_str(FEAT_AUTOJOIN_OPER_CHANNEL), CHANNELLEN-1);
        join[0] = cli_name(sptr);
        join[1] = chan;
        m_join(sptr, sptr, 2, join);
      }
    } else {
      sendto_allops(&me, SNO_OLDSNO, "%s (%s@%s) is now an IRC Operator (%c)",
                         parv[0], cli_user(sptr)->username, cli_sockhost(sptr),
                         OIsGlobal(sptr) ? 'O' : 'o');

      if (feature_bool(FEAT_AUTOJOIN_OPER) && OIsGlobal(sptr)) {
        if (feature_bool(FEAT_AUTOJOIN_OPER_NOTICE))
              sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s", sptr, feature_str(FEAT_AUTOJOIN_OPER_NOTICE_VALUE));

        ircd_strncpy(chan, feature_str(FEAT_AUTOJOIN_OPER_CHANNEL), CHANNELLEN-1);
        join[0] = cli_name(sptr);
        join[1] = chan;
        m_join(sptr, sptr, 2, join);
      }
    }

    if (feature_bool(FEAT_OPERMOTD))
      m_opermotd(sptr, sptr, 1, parv);

    log_write(LS_OPER, L_INFO, 0, "OPER (%s) by (%#C)", name, sptr);

    ircd_snprintf(0, cli_user(sptr)->response, BUFSIZE+1, "%s", "");
    return 0;
  }

  ircd_snprintf(0, cli_user(sptr)->response, BUFSIZE+1, "%s", "");
  ircd_snprintf(0, cli_user(sptr)->auth_oper, NICKLEN+1, "%s", "");

  aconf = find_conf_exact(parv[2], cli_user(sptr)->realusername,
                          cli_user(sptr)->realhost, CONF_OPS);

  if (!aconf)
    aconf = find_conf_exact(parv[2], cli_user(sptr)->realusername,
                            ircd_ntoa((const char*) &(cli_ip(sptr))), CONF_OPS);

  if (!aconf)
    aconf = find_conf_cidr(parv[2], cli_user(sptr)->realusername,
                            cli_ip(sptr), CONF_OPS);

  if (aconf == NULL)
  {
    send_reply(sptr, ERR_NOOPERHOST);
    failed_challenge_notice(sptr, parv[2], "No o:line");
    sendto_allops(&me, SNO_OLDREALOP, "Failed OPER attempt by %s (%s@%s) (No O:line)",
                       parv[0], cli_user(sptr)->realusername, cli_sockhost(sptr));
    return 0;
  }

  if (!(aconf->port & OFLAG_REMOTE)) {
    send_reply(sptr, ERR_NOOPERHOST);
    sendto_allops(&me, SNO_OLDREALOP,
      "Failed OPER attempt by %s (%s@%s) (Remote Oper)", parv[0],
      cli_user(sptr)->realusername, cli_user(sptr)->realhost);
    return 0;
  }

  if (!(aconf->port & OFLAG_RSA))
  {
    send_reply(sptr, RPL_NO_CHALL);
    return 0;
  }

  if (!verify_sslclifp(sptr, aconf))
  {
    sendto_allops(&me, SNO_OLDREALOP,
           "Failed OPER attempt by %s (%s@%s) (SSL Fingerprint Missmatch)",
           parv[0], cli_user(sptr)->realusername,
           cli_user(sptr)->realhost);
    send_reply(sptr, ERR_SSLCLIFP);
    return 0;
  }

  if ((file = BIO_new_file(aconf->passwd, "r")) == NULL)
  {
    send_reply(sptr, RPL_NO_KEY);
    return 0;
  }

  rsa_public_key = (RSA *)PEM_read_bio_RSA_PUBKEY(file, NULL, 0, NULL);
  if (rsa_public_key == NULL)
     return send_reply(sptr, RPL_INVALID_KEY);


  if (!generate_challenge(&challenge, rsa_public_key, sptr)) {
      Debug((DEBUG_DEBUG, "generating challenge sum (%s)", challenge));
      send_reply(sptr, RPL_RSACHALLENGE, challenge);
      ircd_snprintf(0, cli_user(sptr)->auth_oper, NICKLEN + 1, "%s", aconf->name);
  }
  nl = BIO_set_close(file, BIO_CLOSE);
  BIO_free(file);

  return 1;
#else
  return 1;
#endif
}
Example #12
0
/** Check whether the introduction of a new server would cause a loop
 * or be disallowed by leaf and hub configuration directives.
 * @param[in] cptr Neighbor who sent the message.
 * @param[in] sptr Client that originated the message.
 * @param[out] ghost If non-NULL, receives ghost timestamp for new server.
 * @param[in] host Name of new server.
 * @param[in] numnick Numnick mask of new server.
 * @param[in] timestamp Claimed link timestamp of new server.
 * @param[in] hop Number of hops to the new server.
 * @param[in] junction Non-zero if the new server is still bursting.
 * @return CPTR_KILLED if \a cptr was SQUIT.  0 if some other server
 * was SQUIT.  1 if the new server is allowed.
 */
static int
check_loop_and_lh(struct Client* cptr, struct Client *sptr, time_t *ghost, const char *host, const char *numnick, time_t timestamp, unsigned int hop, int junction)
{
  struct Client* acptr;
  struct Client* LHcptr = NULL;
  struct ConfItem* lhconf;
  enum lh_type active_lh_line = ALLOWED;
  int ii;

  if (ghost)
    *ghost = 0;

  /*
   * Calculate type of connect limit and applicable config item.
   */
  lhconf = find_conf_byname(cli_confs(cptr), cli_name(cptr), CONF_SERVER);
  assert(lhconf != NULL);
  if (ghost)
  {
    if (!feature_bool(FEAT_HUB))
      for (ii = 0; ii <= HighestFd; ii++)
        if (LocalClientArray[ii] && IsServer(LocalClientArray[ii])) {
          active_lh_line = I_AM_NOT_HUB;
          break;
        }
  }
  else if (hop > lhconf->maximum)
  {
    /* Because "maximum" should be 0 for non-hub links, check whether
     * there is a hub mask -- if not, complain that the server isn't
     * allowed to hub.
     */
    active_lh_line = lhconf->hub_limit ? MAX_HOPS_EXCEEDED : NOT_ALLOWED_TO_HUB;
  }
  else if (lhconf->hub_limit && match(lhconf->hub_limit, host))
  {
    struct Client *ac3ptr;
    active_lh_line = NOT_ALLOWED_TO_HUB;
    if (junction)
      for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up)
        if (IsJunction(ac3ptr)) {
          LHcptr = ac3ptr;
          break;
        }
  }

  /*
   *  We want to find IsConnecting() and IsHandshake() too,
   *  use FindClient().
   *  The second finds collisions with numeric representation of existing
   *  servers - these shouldn't happen anymore when all upgraded to 2.10.
   *  -- Run
   */
  while ((acptr = FindClient(host))
         || (numnick && (acptr = FindNServer(numnick))))
  {
    /*
     *  This link is trying feed me a server that I already have
     *  access through another path
     *
     *  Do not allow Uworld to do this.
     *  Do not allow servers that are juped.
     *  Do not allow servers that have older link timestamps
     *    then this try.
     *  Do not allow servers that use the same numeric as an existing
     *    server, but have a different name.
     *
     *  If my ircd.conf sucks, I can try to connect to myself:
     */
    if (acptr == &me)
      return exit_client_msg(cptr, cptr, &me, "nick collision with me (%s), check server number in M:?", host);
    /*
     * Detect wrong numeric.
     */
    if (0 != ircd_strcmp(cli_name(acptr), host))
    {
      sendcmdto_serv(&me, CMD_WALLOPS, cptr,
                     ":SERVER Numeric Collision: %s != %s",
                     cli_name(acptr), host);
      return exit_client_msg(cptr, cptr, &me,
          "NUMERIC collision between %s and %s."
          " Is your server numeric correct ?", host, cli_name(acptr));
    }
    /*
     *  Kill our try, if we had one.
     */
    if (IsConnecting(acptr))
    {
      if (active_lh_line == ALLOWED && exit_client(cptr, acptr, &me,
          "Just connected via another link") == CPTR_KILLED)
        return CPTR_KILLED;
      /*
       * We can have only ONE 'IsConnecting', 'IsHandshake' or
       * 'IsServer', because new 'IsConnecting's are refused to
       * the same server if we already had it.
       */
      break;
    }
    /*
     * Avoid other nick collisions...
     * This is a doubtful test though, what else would it be
     * when it has a server.name ?
     */
    else if (!IsServer(acptr) && !IsHandshake(acptr))
      return exit_client_msg(cptr, cptr, &me,
                             "Nickname %s already exists!", host);
    /*
     * Our new server might be a juped server:
     */
    else if (IsServer(acptr) && (0 == ircd_strncmp(cli_info(acptr), "JUPE", 4)))
    {
      if (!IsServer(sptr))
        return exit_client(cptr, sptr, &me, cli_info(acptr));
      sendcmdto_serv(&me, CMD_WALLOPS, cptr,
                     ":Received :%s SERVER %s from %s !?!",
                     NumServ(cptr), host, cli_name(cptr));
      return exit_new_server(cptr, sptr, host, timestamp, "%s", cli_info(acptr));
    }
    /*
     * Of course we find the handshake this link was before :)
     */
    else if (IsHandshake(acptr) && acptr == cptr)
      break;
    /*
     * Here we have a server nick collision...
     * We don't want to kill the link that was last /connected,
     * but we neither want to kill a good (old) link.
     * Therefor we kill the second youngest link.
     */
    if (1)
    {
      struct Client* c2ptr = 0;
      struct Client* c3ptr = acptr;
      struct Client* ac2ptr;
      struct Client* ac3ptr;

      /* Search youngest link: */
      for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up)
        if (cli_serv(ac3ptr)->timestamp > cli_serv(c3ptr)->timestamp)
          c3ptr = ac3ptr;
      if (IsServer(sptr))
      {
        for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = cli_serv(ac3ptr)->up)
          if (cli_serv(ac3ptr)->timestamp > cli_serv(c3ptr)->timestamp)
            c3ptr = ac3ptr;
      }
      if (timestamp > cli_serv(c3ptr)->timestamp)
      {
        c3ptr = 0;
        c2ptr = acptr;          /* Make sure they differ */
      }
      /* Search second youngest link: */
      for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = cli_serv(ac2ptr)->up)
        if (ac2ptr != c3ptr &&
            cli_serv(ac2ptr)->timestamp >
            (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
          c2ptr = ac2ptr;
      if (IsServer(sptr))
      {
        for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = cli_serv(ac2ptr)->up)
          if (ac2ptr != c3ptr &&
              cli_serv(ac2ptr)->timestamp >
              (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
            c2ptr = ac2ptr;
      }
      if (c3ptr && timestamp > (c2ptr ? cli_serv(c2ptr)->timestamp : timestamp))
        c2ptr = 0;
      /* If timestamps are equal, decide which link to break
       *  by name.
       */
      if ((c2ptr ? cli_serv(c2ptr)->timestamp : timestamp) ==
          (c3ptr ? cli_serv(c3ptr)->timestamp : timestamp))
      {
        const char *n2, *n2up, *n3, *n3up;
        if (c2ptr)
        {
          n2 = cli_name(c2ptr);
          n2up = MyConnect(c2ptr) ? cli_name(&me) : cli_name(cli_serv(c2ptr)->up);
        }
        else
        {
          n2 = host;
          n2up = IsServer(sptr) ? cli_name(sptr) : cli_name(&me);
        }
        if (c3ptr)
        {
          n3 = cli_name(c3ptr);
          n3up = MyConnect(c3ptr) ? cli_name(&me) : cli_name(cli_serv(c3ptr)->up);
        }
        else
        {
          n3 = host;
          n3up = IsServer(sptr) ? cli_name(sptr) : cli_name(&me);
        }
        if (strcmp(n2, n2up) > 0)
          n2 = n2up;
        if (strcmp(n3, n3up) > 0)
          n3 = n3up;
        if (strcmp(n3, n2) > 0)
        {
          ac2ptr = c2ptr;
          c2ptr = c3ptr;
          c3ptr = ac2ptr;
        }
      }
      /* Now squit the second youngest link: */
      if (!c2ptr)
        return exit_new_server(cptr, sptr, host, timestamp,
                               "server %s already exists and is %ld seconds younger.",
                               host, (long)cli_serv(acptr)->timestamp - (long)timestamp);
      else if (cli_from(c2ptr) == cptr || IsServer(sptr))
      {
        struct Client *killedptrfrom = cli_from(c2ptr);
        if (active_lh_line != ALLOWED)
        {
          /*
           * If the L: or H: line also gets rid of this link,
           * we sent just one squit.
           */
          if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
            break;
          /*
           * If breaking the loop here solves the L: or H:
           * line problem, we don't squit that.
           */
          if (cli_from(c2ptr) == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
            active_lh_line = ALLOWED;
          else
          {
            /*
             * If we still have a L: or H: line problem,
             * we prefer to squit the new server, solving
             * loop and L:/H: line problem with only one squit.
             */
            LHcptr = 0;
            break;
          }
        }
        /*
         * If the new server was introduced by a server that caused a
         * Ghost less then 20 seconds ago, this is probably also
         * a Ghost... (20 seconds is more then enough because all
         * SERVER messages are at the beginning of a net.burst). --Run
         */
        if (CurrentTime - cli_serv(cptr)->ghost < 20)
        {
          killedptrfrom = cli_from(acptr);
          if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
            return CPTR_KILLED;
        }
        else if (exit_client_msg(cptr, c2ptr, &me,
            "Loop <-- %s (new link is %ld seconds younger)", host,
            (c3ptr ? (long)cli_serv(c3ptr)->timestamp : timestamp) -
            (long)cli_serv(c2ptr)->timestamp) == CPTR_KILLED)
          return CPTR_KILLED;
        /*
         * Did we kill the incoming server off already ?
         */
        if (killedptrfrom == cptr)
          return 0;
      }
      else
      {
        if (active_lh_line != ALLOWED)
        {
          if (LHcptr && a_kills_b_too(LHcptr, acptr))
            break;
          if (cli_from(acptr) == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
            active_lh_line = ALLOWED;
          else
          {
            LHcptr = 0;
            break;
          }
        }
        /*
         * We can't believe it is a lagged server message
         * when it directly connects to us...
         * kill the older link at the ghost, rather then
         * at the second youngest link, assuming it isn't
         * a REAL loop.
         */
        if (ghost)
          *ghost = CurrentTime;            /* Mark that it caused a ghost */
        if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
          return CPTR_KILLED;
        break;
      }
    }
  }

  if (active_lh_line != ALLOWED)
  {
    if (!LHcptr)
      LHcptr = sptr;
    if (active_lh_line == MAX_HOPS_EXCEEDED)
    {
      return exit_client_msg(cptr, LHcptr, &me,
                             "Maximum hops exceeded for %s at %s",
                             cli_name(cptr), host);
    }
    else if (active_lh_line == NOT_ALLOWED_TO_HUB)
    {
      return exit_client_msg(cptr, LHcptr, &me,
                             "%s is not allowed to hub for %s",
                             cli_name(cptr), host);
    }
    else /* I_AM_NOT_HUB */
    {
      ServerStats->is_ref++;
      return exit_client(cptr, LHcptr, &me, "I'm a leaf, define the HUB feature");
    }
  }

  return 1;
}
Example #13
0
/** Parse a line of data from a server.
 * @param[in] cptr Client that sent the data.
 * @param[in] buffer Start of input line.
 * @param[in] bufend End of input line.
 * @return 0 on success, -1 on parse error, or CPTR_KILLED if message
 * handler returns it.
 */
int parse_server(struct Client *cptr, char *buffer, char *bufend)
{
  struct Client*  from = cptr;
  char*           ch = buffer;
  char*           s;
  int             len;
  int             i;
  int             numeric = 0;
  int             paramcount;
  struct Message* mptr;

  Debug((DEBUG_DEBUG, "Server Parsing: %s", buffer));

  if (IsDead(cptr))
    return 0;

  para[0] = cli_name(from);

  /*
   * A server ALWAYS sends a prefix. When it starts with a ':' it's the
   * protocol 9 prefix: a nick or a server name. Otherwise it's a numeric
   * nick or server
   */
  if (*ch == ':')
  {
    /* Let para[0] point to the name of the sender */
    para[0] = ch + 1;
    if (!(ch = strchr(ch, ' ')))
      return -1;
    *ch++ = '\0';

    /* And let `from' point to its client structure,
       opps.. a server is _also_ a client --Nem */
    from = FindClient(para[0]);

    /*
     * If the client corresponding to the
     * prefix is not found. We must ignore it,
     * it is simply a lagged message traveling
     * upstream a SQUIT that removed the client
     * --Run
     */
    if (from == NULL)
    {
      Debug((DEBUG_NOTICE, "Unknown prefix (%s)(%s) from (%s)",
          para[0], buffer, cli_name(cptr)));
      ++ServerStats->is_unpf;
      while (*ch == ' ')
        ch++;
      /*
       * However, the only thing that MUST be
       * allowed to travel upstream against an
       * squit, is an SQUIT itself (the timestamp
       * protects us from being used wrong)
       */
      if (ch[1] == 'Q')
      {
        para[0] = cli_name(cptr);
        from = cptr;
      }
      else
        return 0;
    }
    else if (cli_from(from) != cptr)
    {
      ++ServerStats->is_wrdi;
      Debug((DEBUG_NOTICE, "Fake direction: Message (%s) coming from (%s)",
          buffer, cli_name(cptr)));
      return 0;
    }
  }
  else
  {
    char numeric_prefix[6];
    int  i;
    for (i = 0; i < 5; ++i)
    {
      if ('\0' == ch[i] || ' ' == (numeric_prefix[i] = ch[i]))
      {
        break;
      }
    }
    numeric_prefix[i] = '\0';

    /*
     * We got a numeric nick as prefix
     * 1 or 2 character prefixes are from servers
     * 3 or 5 chars are from clients
     */
    if (0 == i)
    {
      protocol_violation(cptr,"Missing Prefix");
      from = cptr;
    }
    else if (' ' == ch[1] || ' ' == ch[2])
      from = FindNServer(numeric_prefix);
    else
      from = findNUser(numeric_prefix);

    do
    {
      ++ch;
    }
    while (*ch != ' ' && *ch);

    /*
     * If the client corresponding to the
     * prefix is not found. We must ignore it,
     * it is simply a lagged message traveling
     * upstream a SQUIT that removed the client
     * --Run
     * There turned out to be other reasons that
     * a prefix is unknown, needing an upstream
     * KILL.  Also, next to an SQUIT we better
     * allow a KILL to pass too.
     * --Run
     */
    if (from == NULL)
    {
      ServerStats->is_unpf++;
      while (*ch == ' ')
        ch++;
      if (*ch == 'N' && (ch[1] == ' ' || ch[1] == 'I'))
        /* Only sent a KILL for a nick change */
      {
        struct Client *server;
        /* Kill the unknown numeric prefix upstream if
         * it's server still exists: */
        if ((server = FindNServer(numeric_prefix)) && cli_from(server) == cptr)
	  sendcmdto_one(&me, CMD_KILL, cptr, "%s :%s (Unknown numeric nick)",
			numeric_prefix, cli_name(&me));
      }
      /*
       * Things that must be allowed to travel
       * upstream against an squit:
       */
      if (ch[1] == 'Q' || (*ch == 'D' && ch[1] == ' ') ||
          (*ch == 'K' && ch[2] == 'L'))
        from = cptr;
      else
        return 0;
    }

    /* Let para[0] point to the name of the sender */
    para[0] = cli_name(from);

    if (cli_from(from) != cptr)
    {
      ServerStats->is_wrdi++;
      Debug((DEBUG_NOTICE, "Fake direction: Message (%s) coming from (%s)",
          buffer, cli_name(cptr)));
      return 0;
    }
  }

  while (*ch == ' ')
    ch++;
  if (*ch == '\0')
  {
    ServerStats->is_empt++;
    Debug((DEBUG_NOTICE, "Empty message from host %s:%s",
        cli_name(cptr), cli_name(from)));
    return (-1);
  }

  /*
   * Extract the command code from the packet.   Point s to the end
   * of the command code and calculate the length using pointer
   * arithmetic.  Note: only need length for numerics and *all*
   * numerics must have parameters and thus a space after the command
   * code. -avalon
   */
  s = strchr(ch, ' ');          /* s -> End of the command code */
  len = (s) ? (s - ch) : 0;
  if (len == 3 && IsDigit(*ch))
  {
    numeric = (*ch - '0') * 100 + (*(ch + 1) - '0') * 10 + (*(ch + 2) - '0');
    paramcount = 2; /* destination, and the rest of it */
    ServerStats->is_num++;
    mptr = NULL;                /* Init. to avoid stupid compiler warning :/ */
  }
  else
  {
    if (s)
      *s++ = '\0';

    /* Version      Receive         Send
     * 2.9          Long            Long
     * 2.10.0       Tkn/Long        Long
     * 2.10.10      Tkn/Long        Tkn
     * 2.10.20      Tkn             Tkn
     *
     * Clients/unreg servers always receive/
     * send long commands   -record
     *
     * And for the record, this trie parser really does not care. - Dianora
     */

    mptr = msg_tree_parse(ch, &tok_tree);

    if (mptr == NULL)
    {
      mptr = msg_tree_parse(ch, &msg_tree);
    }

    if (mptr == NULL)
    {
      /*
       * Note: Give error message *only* to recognized
       * persons. It's a nightmare situation to have
       * two programs sending "Unknown command"'s or
       * equivalent to each other at full blast....
       * If it has got to person state, it at least
       * seems to be well behaving. Perhaps this message
       * should never be generated, though...   --msa
       * Hm, when is the buffer empty -- if a command
       * code has been found ?? -Armin
       */
#ifdef DEBUGMODE
      if (buffer[0] != '\0')
      {
        Debug((DEBUG_ERROR, "Unknown (%s) from %s",
              ch, get_client_name(cptr, HIDE_IP)));
      }
#endif
      ServerStats->is_unco++;
      return (-1);
    }

    paramcount = mptr->parameters;
    i = bufend - ((s) ? s : ch);
    mptr->bytes += i;
  }
  /*
   * Must the following loop really be so devious? On
   * surface it splits the message to parameters from
   * blank spaces. But, if paramcount has been reached,
   * the rest of the message goes into this last parameter
   * (about same effect as ":" has...) --msa
   */

  /* Note initially true: s==NULL || *(s-1) == '\0' !! */

  i = 0;
  if (s)
  {
    if (paramcount > MAXPARA)
      paramcount = MAXPARA;
    for (;;)
    {
      /*
       * Never "FRANCE " again!! ;-) Clean
       * out *all* blanks.. --msa
       */
      while (*s == ' ')
        *s++ = '\0';

      if (*s == '\0')
        break;
      if (*s == ':')
      {
        /*
         * The rest is single parameter--can
         * include blanks also.
         */
	if (numeric)
	  para[++i] = s; /* preserve the colon to make do_numeric happy */
	else
	  para[++i] = s + 1;
        break;
      }
      para[++i] = s;
      if (i >= paramcount)
        break;
      for (; *s != ' ' && *s; s++);
    }
  }
  para[++i] = NULL;
  if (numeric)
    return (do_numeric(numeric, (*buffer != ':'), cptr, from, i, para));
  mptr->count++;

  return (*mptr->handlers[cli_handler(cptr)]) (cptr, from, i, para);
}
Example #14
0
static
void do_trace(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
{
    int i;
    struct Client *acptr;
    struct Client *acptr2;
    const struct ConnectionClass* cl;
    char* tname;
    int doall;
    int *link_s;
    int *link_u;
    int cnt = 0;
    int wilds;
    int dow;

    if (parc < 2 || BadPtr(parv[1]))
    {
        /* just "TRACE" without parameters. Must be from local client */
        parc = 1;
        acptr = &me;
        tname = cli_name(&me);
        i = HUNTED_ISME;
    }
    else if (parc < 3 || BadPtr(parv[2]))
    {
        /* No target specified. Make one before propagating. */
        parc = 2;
        tname = parv[1];
        if ((acptr = find_match_server(parv[1])) ||
                ((acptr = FindClient(parv[1])) && !MyUser(acptr)))
        {
            if (IsUser(acptr))
                parv[2] = cli_name(cli_user(acptr)->server);
            else
                parv[2] = cli_name(acptr);
            parc = 3;
            parv[3] = 0;
            if ((i = hunt_server_cmd(sptr, CMD_TRACE, cptr, IsServer(acptr),
                                     "%s :%C", 2, parc, parv)) == HUNTED_NOSUCH)
                return;
        }
        else
            i = HUNTED_ISME;
    } else {
        /* Got "TRACE <tname> :<target>" */
        parc = 3;
        if (MyUser(sptr) || Protocol(cptr) < 10)
            acptr = find_match_server(parv[2]);
        else
            acptr = FindNServer(parv[2]);
        if ((i = hunt_server_cmd(sptr, CMD_TRACE, cptr, 0, "%s :%C", 2, parc,
                                 parv)) == HUNTED_NOSUCH)
            return;
        tname = parv[1];
    }

    if (i == HUNTED_PASS) {
        if (!acptr)
            acptr = next_client(GlobalClientList, tname);
        else
            acptr = cli_from(acptr);
        send_reply(sptr, RPL_TRACELINK,
                   version, debugmode, tname,
                   acptr ? cli_name(cli_from(acptr)) : "<No_match>");
        return;
    }

    doall = (parv[1] && (parc > 1)) ? !match(tname, cli_name(&me)) : 1;
    wilds = !parv[1] || strchr(tname, '*') || strchr(tname, '?');
    dow = wilds || doall;

    /* Don't give (long) remote listings to lusers */
    if (dow && !MyConnect(sptr) && !IsAnOper(sptr)) {
        send_reply(sptr, RPL_TRACEEND);
        return;
    }

    link_s = MyCalloc(2 * maxconnections, sizeof(link_s[0]));
    link_u = link_s + maxconnections;

    if (doall) {
        for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr)) {
            if (IsUser(acptr))
                link_u[cli_fd(cli_from(acptr))]++;
            else if (IsServer(acptr))
                link_s[cli_fd(cli_from(acptr))]++;
        }
    }

    /* report all direct connections */

    for (i = 0; i <= HighestFd; i++) {
        const char *conClass;

        if (!(acptr = LocalClientArray[i])) /* Local Connection? */
            continue;
        if (IsInvisible(acptr) && dow && !(MyConnect(sptr) && IsOper(sptr)) &&
                !IsAnOper(acptr) && (acptr != sptr))
            continue;
        if (!doall && wilds && match(tname, cli_name(acptr)))
            continue;
        if (!dow && 0 != ircd_strcmp(tname, cli_name(acptr)))
            continue;

        conClass = get_client_class(acptr);

        switch (cli_status(acptr)) {
        case STAT_CONNECTING:
            send_reply(sptr, RPL_TRACECONNECTING, conClass, cli_name(acptr));
            cnt++;
            break;
        case STAT_HANDSHAKE:
            send_reply(sptr, RPL_TRACEHANDSHAKE, conClass, cli_name(acptr));
            cnt++;
            break;
        case STAT_ME:
            break;
        case STAT_UNKNOWN:
        case STAT_UNKNOWN_USER:
            send_reply(sptr, RPL_TRACEUNKNOWN, conClass,
                       get_client_name(acptr, HIDE_IP));
            cnt++;
            break;
        case STAT_UNKNOWN_SERVER:
            send_reply(sptr, RPL_TRACEUNKNOWN, conClass, "Unknown Server");
            cnt++;
            break;
        case STAT_USER:
            /* Only opers see users if there is a wildcard
               but anyone can see all the opers. */
            if ((IsAnOper(sptr) && (MyUser(sptr) ||
                                    !(dow && IsInvisible(acptr)))) || !dow || IsAnOper(acptr)) {
                if (IsAnOper(acptr))
                    send_reply(sptr, RPL_TRACEOPERATOR, conClass,
                               get_client_name(acptr, SHOW_IP),
                               CurrentTime - cli_lasttime(acptr));
                else
                    send_reply(sptr, RPL_TRACEUSER, conClass,
                               get_client_name(acptr, SHOW_IP),
                               CurrentTime - cli_lasttime(acptr));
                cnt++;
            }
            break;
        /*
         * Connection is a server
         *
         * Serv <class> <nS> <nC> <name> <ConnBy> <last> <age>
         *
         * class        Class the server is in
         * nS           Number of servers reached via this link
         * nC           Number of clients reached via this link
         * name         Name of the server linked
         * ConnBy       Who established this link
         * last         Seconds since we got something from this link
         * age          Seconds this link has been alive
         *
         * Additional comments etc......        -Cym-<*****@*****.**>
         */

        case STAT_SERVER:
            if (cli_serv(acptr)->user) {
                if (!cli_serv(acptr)->by[0]
                        || !(acptr2 = findNUser(cli_serv(acptr)->by))
                        || (cli_user(acptr2) != cli_serv(acptr)->user))
                    acptr2 = NULL;
                send_reply(sptr, RPL_TRACESERVER, conClass, link_s[i],
                           link_u[i], cli_name(acptr),
                           acptr2 ? cli_name(acptr2) : "*",
                           cli_serv(acptr)->user->username,
                           cli_serv(acptr)->user->host,
                           CurrentTime - cli_lasttime(acptr),
                           CurrentTime - cli_serv(acptr)->timestamp);
            } else
                send_reply(sptr, RPL_TRACESERVER, conClass, link_s[i],
                           link_u[i], cli_name(acptr),
                           (*(cli_serv(acptr))->by) ?  cli_serv(acptr)->by : "*", "*",
                           cli_name(&me), CurrentTime - cli_lasttime(acptr),
                           CurrentTime - cli_serv(acptr)->timestamp);
            cnt++;
            break;
        default:                  /* We actually shouldn't come here, -msa */
            send_reply(sptr, RPL_TRACENEWTYPE, get_client_name(acptr, HIDE_IP));
            cnt++;
            break;
        }
    }
    /*
     * Add these lines to summarize the above which can get rather long
     * and messy when done remotely - Avalon
     */
    if (IsAnOper(sptr) && doall) {
        for (cl = get_class_list(); cl; cl = cl->next) {
            if (Links(cl) > 1)
                send_reply(sptr, RPL_TRACECLASS, ConClass(cl), Links(cl) - 1);
        }
    }
    send_reply(sptr, RPL_TRACEEND);
    MyFree(link_s);
}