Esempio n. 1
0
void masterhandler(nick *np, int message, void **args) {
  char *msg;

  switch(message) {
    case LU_KILLED:
      cmnick=NULL;
      scheduleoneshot(time(NULL)+1, makenick, NULL);
      break;
    
    case LU_CHANMSG:
      msg=args[2];
      
      if (!ircd_strncmp(msg, "!spawn ",7)) {
        spawnclones(strtoul(msg+7,NULL,10));
      }
      
      if (!ircd_strncmp(msg,"!join ",6)) {
        join(msg+6);
      }
      
      if (!ircd_strncmp(msg,"!spam ", 6)) {
        spam(strtoul(msg+6, NULL, 10));
      }
      break; 
      
  }
}
Esempio n. 2
0
/** Set a channel topic or report an error.
 * @param[in] sptr Original topic setter.
 * @param[in] cptr Neighbor that sent the topic message.
 * @param[in] chptr Channel to set topic on.
 * @param[in] topic New topic.
 * @param[in] ts Timestamp that topic was set (0 for current time).
 */
static void do_settopic(struct Client *sptr, struct Client *cptr,
                        struct Channel *chptr, char *topic, time_t ts)
{
    struct Client *from;
    int newtopic;

    if (feature_bool(FEAT_HIS_BANWHO) && IsServer(sptr))
        from = &his;
    else
        from = sptr;
    /* Note if this is just a refresh of an old topic, and don't
     * send it to all the clients to save bandwidth.  We still send
     * it to other servers as they may have split and lost the topic.
     */
    newtopic=ircd_strncmp(chptr->topic,topic,TOPICLEN)!=0;
    /* setting a topic */
    ircd_strncpy(chptr->topic, topic, TOPICLEN);
    ircd_strncpy(chptr->topic_nick, cli_name(from), NICKLEN);
    chptr->topic_time = ts ? ts : TStime();
    /* Fixed in 2.10.11: Don't propagate local topics */
    if (!IsLocalChannel(chptr->chname))
        sendcmdto_serv(sptr, CMD_TOPIC, cptr, "%H %Tu %Tu :%s", chptr,
                       chptr->creationtime, chptr->topic_time, chptr->topic);
    if (newtopic)
        sendcmdto_channel(from, CMD_TOPIC, chptr, NULL, SKIP_SERVERS,
                          "%H :%s", chptr, chptr->topic);
    /* if this is the same topic as before we send it to the person that
     * set it (so they knew it went through ok), but don't bother sending
     * it to everyone else on the channel to save bandwidth
     */
    else if (MyUser(sptr))
        sendcmdto_one(sptr, CMD_TOPIC, sptr, "%H :%s", chptr, chptr->topic);
}
Esempio n. 3
0
/** Handle a WALLVOICES message from a local client.
 *
 * \a parv has the following elements:
 * \li \a parv[1] is the name of the channel to which to send
 * \li \a parv[\a parc - 1] is the message to send
 *
 * 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 m_wallvoices(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
{
  struct Channel *chptr;
  const char *ch;

  assert(0 != cptr);
  assert(cptr == sptr);

  if (parc < 2 || EmptyString(parv[1]))
    return send_reply(sptr, ERR_NORECIPIENT, "WALLVOICES");

  if (parc < 3 || EmptyString(parv[parc - 1]))
    return send_reply(sptr, ERR_NOTEXTTOSEND);

  if (IsChannelName(parv[1]) && (chptr = FindChannel(parv[1]))) {
    if (client_can_send_to_channel(sptr, chptr, 0) && !(chptr->mode.mode & MODE_NONOTICE)) {
      if ((chptr->mode.mode & MODE_NOPRIVMSGS) &&
          check_target_limit(sptr, chptr, chptr->chname, 0))
        return 0;

#if 0
      /* +cC checks */
      if (chptr->mode.mode & MODE_NOCOLOUR)
        for (ch=parv[parc - 1];*ch;ch++)
          if (*ch==2 || *ch==3 || *ch==22 || *ch==27 || *ch==31) {
            return 0;
          }

      if ((chptr->mode.mode & MODE_NOCTCP) && ircd_strncmp(parv[parc - 1],"\001ACTION ",8))
        for (ch=parv[parc - 1];*ch;)
          if (*ch++==1) {
            return 0;
          }
#endif
      RevealDelayedJoinIfNeeded(sptr, chptr);
      sendcmdto_channel(sptr, CMD_WALLVOICES, chptr, cptr,
                        SKIP_DEAF | SKIP_BURST | SKIP_NONVOICES,
                        "%H :+ %s", chptr, parv[parc - 1]);
    }
    else
      send_reply(sptr, ERR_CANNOTSENDTOCHAN, parv[1]);
  }
  else
    send_reply(sptr, ERR_NOSUCHCHANNEL, parv[1]);

  return 0;
}
Esempio n. 4
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;
}
Esempio n. 5
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;
}
Esempio n. 6
0
/** Modify a global Z-line.
 * @param[in] cptr Client that sent us the Z-line modification.
 * @param[in] sptr Client that originated the Z-line modification.
 * @param[in] zline Z-line being modified.
 * @param[in] action Resultant status of the Z-line.
 * @param[in] reason Reason for Z-line.
 * @param[in] expire Expiration time of Z-line.
 * @param[in] lastmod Last modification time of Z-line.
 * @param[in] lifetime Lifetime of Z-line.
 * @param[in] flags Bitwise combination of ZLINE_* flags.
 * @return Zero or CPTR_KILLED, depending on whether \a sptr is suicidal.
 */
int
zline_modify(struct Client *cptr, struct Client *sptr, struct Zline *zline,
	     enum ZlineAction action, char *reason, time_t expire,
	     time_t lastmod, time_t lifetime, unsigned int flags)
{
  char buf[BUFSIZE], *op = "";
  int pos = 0, non_auto = 0;

  assert(zline);
  assert(!ZlineIsLocal(zline));

  Debug((DEBUG_DEBUG,  "zline_modify(\"%s\", \"%s\", \"%s\", %s, \"%s\", "
	 "%Tu, %Tu, %Tu, 0x%04x)", cli_name(cptr), cli_name(sptr),
	 zline->zl_mask,
	 action == ZLINE_ACTIVATE ? "ZLINE_ACTIVATE" :
	 (action == ZLINE_DEACTIVATE ? "ZLINE_DEACTIVATE" :
	  (action == ZLINE_LOCAL_ACTIVATE ? "ZLINE_LOCAL_ACTIVATE" :
	   (action == ZLINE_LOCAL_DEACTIVATE ? "ZLINE_LOCAL_DEACTIVATE" :
	    (action == ZLINE_MODIFY ? "ZLINE_MODIFY" : "<UNKNOWN>")))),
	 reason, expire, lastmod, lifetime, flags));

  /* First, let's check lastmod... */
  if (action != ZLINE_LOCAL_ACTIVATE && action != ZLINE_LOCAL_DEACTIVATE) {
    if (ZlineLastMod(zline) > lastmod) { /* we have a more recent version */
      if (IsBurstOrBurstAck(cptr))
	return 0; /* middle of a burst, it'll resync on its own */
      return zline_resend(cptr, zline); /* resync the server */
    } else if (ZlineLastMod(zline) == lastmod)
      return 0; /* we have that version of the Z-line... */
  }

  /* All right, we know that there's a change of some sort.  What is it? */
  /* first, check out the expiration time... */
  if ((flags & ZLINE_EXPIRE) && expire) {
    if (!(flags & ZLINE_FORCE) &&
	(expire <= TStime() || expire > TStime() + ZLINE_MAX_EXPIRE)) {
      if (!IsServer(sptr) && MyConnect(sptr)) /* bad expiration time */
	send_reply(sptr, ERR_BADEXPIRE, expire);
      return 0;
    }
  } else
    flags &= ~ZLINE_EXPIRE;

  /* Now check to see if there's any change... */
  if ((flags & ZLINE_EXPIRE) && expire == zline->zl_expire) {
    flags &= ~ZLINE_EXPIRE; /* no change to expiration time... */
    expire = 0;
  }

  /* Next, check out lifetime--this one's a bit trickier... */
  if (!(flags & ZLINE_LIFETIME) || !lifetime)
    lifetime = zline->zl_lifetime; /* use Z-line lifetime */

  lifetime = IRCD_MAX(lifetime, expire); /* set lifetime to the max */

  /* OK, let's see which is greater... */
  if (lifetime > zline->zl_lifetime)
    flags |= ZLINE_LIFETIME; /* have to update lifetime */
  else {
    flags &= ~ZLINE_LIFETIME; /* no change to lifetime */
    lifetime = 0;
  }

  /* Finally, let's see if the reason needs to be updated */
  if ((flags & ZLINE_REASON) && reason &&
      !ircd_strcmp(zline->zl_reason, reason))
    flags &= ~ZLINE_REASON; /* no changes to the reason */

  /* OK, now let's take a look at the action... */
  if ((action == ZLINE_ACTIVATE && (zline->zl_flags & ZLINE_ACTIVE)) ||
      (action == ZLINE_DEACTIVATE && !(zline->zl_flags & ZLINE_ACTIVE)) ||
      (action == ZLINE_LOCAL_ACTIVATE &&
       (zline->zl_state == ZLOCAL_ACTIVATED)) ||
      (action == ZLINE_LOCAL_DEACTIVATE &&
       (zline->zl_state == ZLOCAL_DEACTIVATED)) ||
      /* can't activate an expired Z-line */
      IRCD_MAX(zline->zl_expire, expire) <= TStime())
    action = ZLINE_MODIFY; /* no activity state modifications */

  Debug((DEBUG_DEBUG,  "About to perform changes; flags 0x%04x, action %s",
	 flags, action == ZLINE_ACTIVATE ? "ZLINE_ACTIVATE" :
	 (action == ZLINE_DEACTIVATE ? "ZLINE_DEACTIVATE" :
	  (action == ZLINE_LOCAL_ACTIVATE ? "ZLINE_LOCAL_ACTIVATE" :
	   (action == ZLINE_LOCAL_DEACTIVATE ? "ZLINE_LOCAL_DEACTIVATE" :
	    (action == ZLINE_MODIFY ? "ZLINE_MODIFY" : "<UNKNOWN>"))))));

  /* If there are no changes to perform, do no changes */
  if (!(flags & ZLINE_UPDATE) && action == ZLINE_MODIFY)
    return 0;

  /* Now we know what needs to be changed, so let's process the changes... */

  /* Start by updating lastmod, if indicated... */
  if (action != ZLINE_LOCAL_ACTIVATE && action != ZLINE_LOCAL_DEACTIVATE)
    zline->zl_lastmod = lastmod;

  /* Then move on to activity status changes... */
  switch (action) {
  case ZLINE_ACTIVATE: /* Globally activating Z-line */
    zline->zl_flags |= ZLINE_ACTIVE; /* make it active... */
    zline->zl_state = ZLOCAL_GLOBAL; /* reset local activity state */
    pos += ircd_snprintf(0, buf, sizeof(buf), " globally activating Z-line");
    op = "+"; /* operation for Z-line propagation */
    break;

  case ZLINE_DEACTIVATE: /* Globally deactivating Z-line */
    zline->zl_flags &= ~ZLINE_ACTIVE; /* make it inactive... */
    zline->zl_state = ZLOCAL_GLOBAL; /* reset local activity state */
    pos += ircd_snprintf(0, buf, sizeof(buf), " globally deactivating Z-line");
    op = "-"; /* operation for Z-line propagation */
    break;

  case ZLINE_LOCAL_ACTIVATE: /* Locally activating Z-line */
    zline->zl_state = ZLOCAL_ACTIVATED; /* make it locally active */
    pos += ircd_snprintf(0, buf, sizeof(buf), " locally activating Z-line");
    break;

  case ZLINE_LOCAL_DEACTIVATE: /* Locally deactivating Z-line */
    zline->zl_state = ZLOCAL_DEACTIVATED; /* make it locally inactive */
    pos += ircd_snprintf(0, buf, sizeof(buf), " locally deactivating Z-line");
    break;

  case ZLINE_MODIFY: /* no change to activity status */
    break;
  }

  /* Handle expiration changes... */
  if (flags & ZLINE_EXPIRE) {
    zline->zl_expire = expire; /* save new expiration time */
    if (pos < BUFSIZE)
      pos += ircd_snprintf(0, buf + pos, sizeof(buf) - pos,
			   "%s%s changing expiration time to %Tu",
			   pos ? ";" : "",
			   pos && !(flags & (ZLINE_LIFETIME | ZLINE_REASON)) ?
			   " and" : "", expire);
  }

  /* Next, handle lifetime changes... */
  if (flags & ZLINE_LIFETIME) {
    zline->zl_lifetime = lifetime; /* save new lifetime */
    if (pos < BUFSIZE)
      pos += ircd_snprintf(0, buf + pos, sizeof(buf) - pos,
			   "%s%s extending record lifetime to %Tu",
			   pos ? ";" : "", pos && !(flags & ZLINE_REASON) ?
			   " and" : "", lifetime);
  }

  /* Now, handle reason changes... */
  if (flags & ZLINE_REASON) {
    non_auto = non_auto || ircd_strncmp(zline->zl_reason, "AUTO", 4);
    MyFree(zline->zl_reason); /* release old reason */
    DupString(zline->zl_reason, reason); /* store new reason */
    if (pos < BUFSIZE)
      pos += ircd_snprintf(0, buf + pos, sizeof(buf) - pos,
			   "%s%s changing reason to \"%s\"",
			   pos ? ";" : "", pos ? " and" : "", reason);
  }

  /* All right, inform ops... */
  non_auto = non_auto || ircd_strncmp(zline->zl_reason, "AUTO", 4);
  sendto_opmask_butone(0, non_auto ? SNO_GLINE : SNO_AUTO,
		       "%s modifying global ZLINE for %s:%s",
		       (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
		       cli_name(sptr) : cli_name((cli_user(sptr))->server),
		       zline->zl_mask, buf);

  /* and log the change */
  log_write(LS_GLINE, L_INFO, LOG_NOSNOTICE,
	    "%#C modifying global ZLINE for %s:%s", sptr, zline->zl_mask, buf);

  /* We'll be simple for this release, but we can update this to change
   * the propagation syntax on future updates
   */
  if (action != ZLINE_LOCAL_ACTIVATE && action != ZLINE_LOCAL_DEACTIVATE)
    sendcmdto_serv_butone(sptr, CMD_ZLINE, cptr,
			  "* %s%s%s %Tu %Tu %Tu :%s",
			  flags & ZLINE_OPERFORCE ? "!" : "", op,
			  zline->zl_mask, zline->zl_expire - TStime(),
                          zline->zl_lastmod, zline->zl_lifetime, zline->zl_reason);

  /* OK, let's do the Z-line... */
  return do_zline(cptr, sptr, zline);
}
Esempio n. 7
0
/** Create a new Z-line and add it to global lists.
 * \a ipmask must be an IP mask to create an IP-based ban.
 *
 * @param[in] cptr Client that sent us the Z-line.
 * @param[in] sptr Client that originated the Z-line.
 * @param[in] ipmask Text mask for the Z-line.
 * @param[in] reason Reason for Z-line.
 * @param[in] expire Expiration time of Z-line.
 * @param[in] lastmod Last modification time of Z-line.
 * @param[in] lifetime Lifetime of Z-line.
 * @param[in] flags Bitwise combination of ZLINE_* flags.
 * @return Zero or CPTR_KILLED, depending on whether \a sptr is suicidal.
 */
int
zline_add(struct Client *cptr, struct Client *sptr, char *ipmask,
	  char *reason, time_t expire, time_t lastmod, time_t lifetime,
	  unsigned int flags)
{
  struct Zline *azline;
  char imask[HOSTLEN + 2];
  char *mask;
  int tmp;

  assert(0 != ipmask);
  assert(0 != reason);
  assert(((flags & (ZLINE_GLOBAL | ZLINE_LOCAL)) == ZLINE_GLOBAL) ||
         ((flags & (ZLINE_GLOBAL | ZLINE_LOCAL)) == ZLINE_LOCAL));

  Debug((DEBUG_DEBUG, "zline_add(\"%s\", \"%s\", \"%s\", \"%s\", %Tu, %Tu "
	 "%Tu, 0x%04x)", cli_name(cptr), cli_name(sptr), ipmask, reason,
	 expire, lastmod, lifetime, flags));

  mask = ipmask;
  if (sizeof(imask) <
      ircd_snprintf(0, imask, sizeof(imask), "%s", mask))
    return send_reply(sptr, ERR_LONGMASK);
  else if (MyUser(sptr) || (IsUser(sptr) && flags & ZLINE_LOCAL)) {
    switch (zline_checkmask(mask)) {
      case CHECK_OVERRIDABLE: /* oper overrided restriction */
        if (flags & ZLINE_OPERFORCE)
          break;
      /*FALLTHROUGH*/
      case CHECK_REJECTED:
        return send_reply(sptr, ERR_MASKTOOWIDE, imask);
        break;
    }

    if ((tmp = count_users(imask, flags)) >=
      feature_int(FEAT_ZLINEMAXUSERCOUNT) && !(flags & ZLINE_OPERFORCE))
    return send_reply(sptr, ERR_TOOMANYUSERS, tmp);
  }

  if (!check_if_ipmask(ipmask))
    return send_reply(sptr, ERR_INVALIDMASK);

  /*
   * You cannot set a negative (or zero) expire time, nor can you set an
   * expiration time for greater than ZLINE_MAX_EXPIRE.
   */
  if (!(flags & ZLINE_FORCE) &&
      (expire <= TStime() || expire > TStime() + ZLINE_MAX_EXPIRE)) {
    if (!IsServer(sptr) && MyConnect(sptr))
      send_reply(sptr, ERR_BADEXPIRE, expire);
    return 0;
  } else if (expire <= TStime()) {
    /* This expired Z-line was forced to be added, so mark it inactive. */
    flags &= ~ZLINE_ACTIVE;
  }

  if (!lifetime) /* no lifetime set, use expiration time */
    lifetime = expire;

  /* lifetime is already an absolute timestamp */

  /* Inform ops... */
  sendto_opmask_butone(0, ircd_strncmp(reason, "AUTO", 4) ? SNO_GLINE :
                       SNO_AUTO, "%s adding %s%s ZLINE for %s, expiring at "
                       "%Tu: %s",
                       (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
                         cli_name(sptr) :
                         cli_name((cli_user(sptr))->server),
                       (flags & ZLINE_ACTIVE) ? "" : "deactivated ",
		       (flags & ZLINE_LOCAL) ? "local" : "global",
		       mask, expire, reason);

  /* and log it */
  log_write(LS_GLINE, L_INFO, LOG_NOSNOTICE,
	    "%#C adding %s ZLINE for %s, expiring at %Tu: %s", sptr,
	    flags & ZLINE_LOCAL ? "local" : "global", mask,
	    expire, reason);

  /* make the zline */
  azline = make_zline(mask, reason, expire, lastmod, lifetime, flags);

  /* since we've disabled overlapped Z-line checking, azline should
   * never be NULL...
   */
  assert(azline);

  zline_propagate(cptr, sptr, azline);

  return do_zline(cptr, sptr, azline); /* knock off users if necessary */
}
Esempio n. 8
0
/** Given a feature vector string, set the value of a feature.
 * @param[in] from Client trying to set the feature, or NULL.
 * @param[in] fields Parameters to set, starting with feature name.
 * @param[in] count Number of fields in \a fields.
 * @return Zero (or, theoretically, CPTR_KILLED).
 */
int
feature_set(struct Client* from, const char* const* fields, int count)
{
  int i, change = 0, tmp;
  const char *t_str;
  struct FeatureDesc *feat;

  if (from && !HasPriv(from, PRIV_SET) && !IsServer(from))
    return send_reply(from, ERR_NOPRIVILEGES);

  if (count < 1) {
    if (from) /* report an error in the number of arguments */
      need_more_params(from, "SET");
    else
      log_write(LS_CONFIG, L_ERROR, 0, "Not enough fields in F line");
  } else if ((feat = feature_desc(from, fields[0]))) { /* find feature */
    if (from && feat->flags & FEAT_READ)
      return send_reply(from, ERR_NOFEATURE, fields[0]);

    switch (feat_type(feat)) {
    case FEAT_NONE:
      if (feat->set && (i = (*feat->set)(from, fields + 1, count - 1))) {
	change++; /* feature handler wants a change recorded */

	if (i > 0) /* call the set callback and do marking */
	  feat->flags |= FEAT_MARK;
	else /* i < 0 */
	  feat->flags &= ~FEAT_MARK;
	break;
      }

    case FEAT_INT: /* an integer value */
    case FEAT_UINT:
      tmp = feat->v_int; /* detect changes... */

      if (count < 2) { /* reset value */
	feat->v_int = feat->def_int;
	feat->flags &= ~FEAT_MARK;
      } else { /* ok, figure out the value and whether to mark it */
	feat->v_int = strtoul(fields[1], 0, 0);
	if (feat->v_int == feat->def_int)
	  feat->flags &= ~FEAT_MARK;
	else
	  feat->flags |= FEAT_MARK;
      }

      if (feat->v_int != tmp) /* check for change */
	change++;
      break;

    case FEAT_BOOL: /* it's a boolean value--true or false */
      tmp = feat->v_int; /* detect changes... */

      if (count < 2) { /* reset value */
	feat->v_int = feat->def_int;
	feat->flags &= ~FEAT_MARK;
      } else { /* figure out the value and whether to mark it */
	if (!ircd_strncmp(fields[1], "TRUE", strlen(fields[1])) ||
	    !ircd_strncmp(fields[1], "YES", strlen(fields[1])) ||
	    (strlen(fields[1]) >= 2 &&
	     !ircd_strncmp(fields[1], "ON", strlen(fields[1]))))
	  feat->v_int = 1;
	else if (!ircd_strncmp(fields[1], "FALSE", strlen(fields[1])) ||
		 !ircd_strncmp(fields[1], "NO", strlen(fields[1])) ||
		 (strlen(fields[1]) >= 2 &&
		  !ircd_strncmp(fields[1], "OFF", strlen(fields[1]))))
	  feat->v_int = 0;
	else if (from) /* report an error... */
	  return send_reply(from, ERR_BADFEATVALUE, fields[1], feat->type);
	else {
	  log_write(LS_CONFIG, L_ERROR, 0, "Bad value \"%s\" for feature %s",
		    fields[1], feat->type);
	  return 0;
	}

	if (feat->v_int == feat->def_int) /* figure out whether to mark it */
	  feat->flags &= ~FEAT_MARK;
	else
	  feat->flags |= FEAT_MARK;
      }

      if (feat->v_int != tmp) /* check for change */
	change++;
      break;

    case FEAT_STR: /* it's a string value */
      if (count < 2)
	t_str = feat->def_str; /* changing to default */
      else
	t_str = *fields[1] ? fields[1] : 0;

      if (!t_str && !(feat->flags & FEAT_NULL)) { /* NULL value permitted? */
	if (from)
	  return send_reply(from, ERR_BADFEATVALUE, "NULL", feat->type);
	else {
	  log_write(LS_CONFIG, L_ERROR, 0, "Bad value \"NULL\" for feature %s",
		    feat->type);
	  return 0;
	}
      }

      if (t_str == feat->def_str ||
	  (t_str && feat->def_str &&
	   !(feat->flags & FEAT_CASE ? strcmp(t_str, feat->def_str) :
	     ircd_strcmp(t_str, feat->def_str)))) { /* resetting to default */
	if (feat->v_str != feat->def_str) {
	  change++; /* change from previous value */

	  if (feat->v_str)
	    MyFree(feat->v_str); /* free old value */
	}

	feat->v_str = feat->def_str; /* very special... */

	feat->flags &= ~FEAT_MARK;
      } else if (!t_str) {
	if (feat->v_str) {
	  change++; /* change from previous value */

	  if (feat->v_str != feat->def_str)
	    MyFree(feat->v_str); /* free old value */
	}

	feat->v_str = 0; /* set it to NULL */

	feat->flags |= FEAT_MARK;
      } else if (!feat->v_str ||
		 (feat->flags & FEAT_CASE ? strcmp(t_str, feat->v_str) :
		  ircd_strcmp(t_str, feat->v_str))) { /* new value */
	change++; /* change from previous value */

	if (feat->v_str && feat->v_str != feat->def_str)
	  MyFree(feat->v_str); /* free old value */
	DupString(feat->v_str, t_str); /* store new value */

	feat->flags |= FEAT_MARK;
      } else /* they match, but don't match the default */
	feat->flags |= FEAT_MARK;
      break;
    }

    if (change && feat->notify) /* call change notify function */
      (*feat->notify)();

    if (change && from) {
      
      if(!IsServer(from) && !IsMe(from))
        send_reply(from, SND_EXPLICIT | RPL_FEATURE, ":Value of %s changed",
                   feat->type);

      switch (feat_type(feat)) {
        case FEAT_NONE:
          sendto_opmask_butone(0, SNO_OLDSNO, "%C changed %s",
                               from, feat->type);
          break;
        case FEAT_INT:
          sendto_opmask_butone(0, SNO_OLDSNO, "%C changed %s to %d",
                               from, feat->type, feat->v_int);
          break;
        case FEAT_BOOL:
          sendto_opmask_butone(0, SNO_OLDSNO, "%C changed %s to %s", from,
                               feat->type, (feat->v_int ? "TRUE" : "FALSE"));
          break;
        case FEAT_STR:
          if(feat->v_str)
            sendto_opmask_butone(0, SNO_OLDSNO, "%C changed %s to: %s",
                                 from, feat->type, feat->v_str);
          else
            sendto_opmask_butone(0, SNO_OLDSNO, "%C unset %s",
                                 from, feat->type);
          break;
      } /* switch */
    } /* if (change) */
  }

  return 0;
}