Esempio n. 1
0
/*
 * handle_opers
 *
 * inputs	- server pointer
 *		- client pointer
 *		- nick stuff to grok for opers
 *		- text to send if grok
 * output	- none
 * side effects	- all the traditional oper type messages are parsed here.
 *		  i.e. "/msg #some.host."
 *		  However, syntax has been changed.
 *		  previous syntax "/msg #some.host.mask"
 *		  now becomes     "/msg $#some.host.mask"
 *		  previous syntax of: "/msg $some.server.mask" remains
 *		  This disambiguates the syntax.
 */
static void
handle_opers(int p_or_n, char *command, struct Client *client_p,
             struct Client *source_p, char *nick, char *text)
{
  struct Client *target_p;
  char *host;
  char *server;
  char *s;
  int count;

  /*
   * the following two cases allow masks in NOTICEs
   * (for OPERs only)
   *
   * Armin, 8Jun90 ([email protected])
   */
  if(*nick == '$')
  {
    if((*(nick+1) == '$' || *(nick+1) == '#'))
      nick++;
    else if(MyOper(source_p))
    {
      sendto_one(source_p, 
                 ":%s NOTICE %s :The command %s %s is no longer supported, please use $%s",
		 me.name, source_p->name, command, nick, nick);
      return;
    }
      
    if ((s = strrchr(nick, '.')) == NULL)
    {
      sendto_one(source_p, form_str(source_p,ERR_NOTOPLEVEL),
                 me.name, source_p->name, nick);
      return;
    }
    while (*++s)
      if (*s == '.' || *s == '*' || *s == '?')
        break;
    if (*s == '*' || *s == '?')
    {
      sendto_one(source_p, form_str(source_p,ERR_WILDTOPLEVEL),
                 me.name, source_p->name, nick);
      return;
    }
    
    sendto_match_butone(IsServer(client_p) ? client_p : NULL, source_p,
                        nick + 1,
                        (*nick == '#') ? MATCH_HOST : MATCH_SERVER,
                        "%s $%s :%s", command, nick, text);

    if ((p_or_n != NOTICE) && source_p->user)
      source_p->user->last = CurrentTime;

    return;
  }

  /*
   * user[%host]@server addressed?
   */
  if ((server = strchr(nick, '@')) && (target_p = find_server(server + 1)))
  {
    count = 0;

    /*
     * Not destined for a user on me :-(
     */

    if (!IsMe(target_p))
    {
      sendto_one(target_p, ":%s %s %s :%s", source_p->name,
                 command, nick, text);
      if ((p_or_n != NOTICE) && source_p->user)
        source_p->user->last = CurrentTime;
      return;
    }

    *server = '\0';

    if ((host = strchr(nick, '%')) != NULL)
      *host++ = '\0';

    /* Check if someones msg'ing [email protected] */
    if (strcmp(nick, "opers") == 0)
    {
      sendto_realops_flags(FLAGS_ALL, L_ALL, "To opers: From: %s: %s",
                           source_p->name, text);
      return;
    }

    /*
     * Look for users which match the destination host
     * (no host == wildcard) and if one and one only is
     * found connected to me, deliver message!
     */
    target_p = find_userhost(nick, host, &count);

    if (target_p != NULL)
    {
      if (server != NULL)
	*server = '@';
      if (host != NULL)
	*--host = '%';

      if (count == 1)
      {
        sendto_anywhere(target_p, source_p, "%s %s :%s", command,
			nick, text);
        if ((p_or_n != NOTICE) && source_p->user)
          source_p->user->last = CurrentTime;
      }
      else
        sendto_one(source_p, form_str(source_p,ERR_TOOMANYTARGETS),
                   me.name, source_p->name, nick);
    }
  }
  else if (server && *(server+1) && (target_p == NULL))
    sendto_one(source_p, form_str(source_p,ERR_NOSUCHSERVER), me.name,
               source_p->name, server+1);
  else if (server && (target_p == NULL))
    sendto_one(source_p, form_str(source_p,ERR_NOSUCHNICK), me.name,
               source_p->name, nick);
}
Esempio n. 2
0
static  int     m_message(struct Client *cptr,
                          struct Client *sptr,
                          int parc,
                          char *parv[],
                          int notice)
{
  struct Client       *acptr;
#ifdef NEED_TLD_FOR_MASS_NOTICE
  char  *s;
#endif
  struct Channel *chptr;
  char  *nick, *server, *host;
  char  errbuf[BUFSIZE];
  const char *cmd;
  int type=0, msgs=0;
#ifdef FLUD
  int flud;
#endif

  cmd = notice ? MSG_NOTICE : MSG_PRIVATE;

  if (parc < 2 || *parv[1] == '\0')
    {
      sendto_one(sptr, form_str(ERR_NORECIPIENT),
                 me.name, parv[0], cmd);
      return -1;
    }

  if (parc < 3 || *parv[2] == '\0')
    {
      sendto_one(sptr, form_str(ERR_NOTEXTTOSEND), me.name, parv[0]);
      return -1;
    }

  if (MyConnect(sptr))
    {
#ifdef ANTI_SPAMBOT
#ifndef ANTI_SPAMBOT_WARN_ONLY
      /* if its a spambot, just ignore it */
      if(sptr->join_leave_count >= MAX_JOIN_LEAVE_COUNT)
        return 0;
#endif
#endif
#ifdef NO_DUPE_MULTI_MESSAGES
      if (strchr(parv[1],','))
        parv[1] = canonize(parv[1]);
#endif
    }


  /*
  ** channels are privmsg'd a lot more than other clients, moved up here
  ** plain old channel msg ?
  */
  while(msgs < MAX_MULTI_MESSAGES)
  {
     if(!msgs)
        nick = strtok(parv[1], ",");
     else
        nick = strtok(NULL, ",");

     if(!nick && msgs == 0)
        nick = parv[1];
     else if(!nick)
        break;

  if( IsChanPrefix(*nick)
      && (IsPerson(sptr) && (chptr = hash_find_channel(nick, NullChn))))
    {
#ifdef FLUD
#ifdef DEATHFLUD
      if(!notice && check_for_ctcp(parv[2])
         && check_for_flud(sptr, NULL, chptr, 1))
        return 0;
      if((flud = check_for_spam(sptr, NULL, chptr, parv[2])))
        {
          if (check_for_flud(sptr, NULL, chptr, flud))
            return 0;
        }
#else /* DEATHFLUD */
      if(!notice)
	if(check_for_ctcp(parv[2]))
	  check_for_flud(sptr, NULL, chptr, 1);
#endif /* DEATHFLUD */
#endif /* FLUD */

      /* 
       * Channel color blocking. Usually set with the +c chanmode.
       * - Andre Guibert de Bruet <*****@*****.**>
       */
      if(chptr->mode.mode & MODE_NOCOLOR)
	strip_colour(parv[2]);

      switch (can_send(sptr, chptr))
        {
        case 0:
          sendto_channel_message_butone(cptr, sptr, chptr, cmd, parv[2]);
          break;
        case MODE_QUIETUNIDENT:
          if (!notice)
            sendto_one(sptr, form_str(ERR_QUIETUNIDENT),
                       me.name, parv[0], nick);
          break;
        case MODE_MODERATED:
          if (chptr->mode.mode & MODE_OPMODERATE)
            {
              /* The flag MODE_OPMODERATE will instruct sendto_channel_type()
	       * to put bare #channel in the message (instead of @#channel);
	       * it will still be sent to ops and servers with ops only.
	       * Strange things will happen if the user is not banned
	       * remotely.
	       * -- jilles
	       */
              sendto_channel_type(cptr, sptr, chptr,
			      MODE_CHANOP | MODE_OPMODERATE, nick, cmd,
			      parv[2]);
            }
          else
            {
              if (!notice)
                sendto_one(sptr, form_str(ERR_CANNOTSENDTOCHAN),
                           me.name, parv[0], nick);
            }
          break;
        default:
          break;
        }
      msgs++;
      continue;
    }
      
  /*
  ** @# type of channel msg?
  */

  if(*nick == '@')
    type = MODE_CHANOP;
  else if(*nick == '+')
    type = MODE_CHANOP|MODE_VOICE;

  if(type)
    {
      /* Strip if using DALnet chanop/voice prefix. */
      if (*(nick+1) == '@' || *(nick+1) == '+')
        {
          nick++;
          *nick = '@';
          type = MODE_CHANOP|MODE_VOICE;
        }

      /* suggested by Mortiis */
      if(!*nick)        /* if its a '\0' dump it, there is no recipient */
        {
          sendto_one(sptr, form_str(ERR_NORECIPIENT),
                     me.name, parv[0], cmd);
          return -1;
        }

      if (!IsPerson(sptr))      /* This means, servers can't send messages */
        return -1;

      /* At this point, nick+1 should be a channel name i.e. #foo or &foo
       * if the channel is found, fine, if not report an error
       */

      if ( (chptr = hash_find_channel(nick+1, NullChn)) )
        {
#ifdef FLUD
#ifdef DEATHFLUD
          if(!notice && check_for_ctcp(parv[2])
             && check_for_flud(sptr, NULL, chptr, 1))
            return 0;
          if((flud = check_for_spam(sptr, NULL, chptr, parv[2])))
            {
              if (check_for_flud(sptr, NULL, chptr, flud))
                return 0;
            }
#else /* DEATHFLUD */
          if(!notice)
            if(check_for_ctcp(parv[2]))
              check_for_flud(sptr, NULL, chptr, 1);
#endif /* DEATHFLUD */
#endif /* FLUD */

          if (!is_chan_op(sptr,chptr))
            {
              if (!notice)
                {
                  sendto_one(sptr, form_str(ERR_CANNOTSENDTOCHAN),
                             me.name, parv[0], nick);
                }
	msgs++;
	continue;
            }
          else
            {
              sendto_channel_type(cptr,
                                  sptr,
                                  chptr,
                                  type,
                                  nick+1,
                                  cmd,
                                  parv[2]);
            }
        }
      else
        {
	  if (!IsServer(sptr))
	    sendto_one(sptr, form_str(ERR_NOSUCHNICK),
		       me.name, parv[0], nick);
	  msgs++;
	  continue;
        }
      return 0;
    }

  /*
  ** nickname addressed?
  */
  if ((acptr = find_person(nick, NULL)))
    {
#ifdef FLUD
#ifdef DEATHFLUD
      if(!notice && MyConnect(sptr) && check_for_ctcp(parv[2])
         && check_for_flud(sptr, acptr, NULL, 1))
        return 0;
      if(MyConnect(sptr) && (flud = check_for_spam(sptr, acptr, NULL, parv[2])))
        {
          if (check_for_flud(sptr, acptr, NULL, flud))
            return 0;
        }
#else /* DEATHFLUD */
      if(!notice && MyConnect(sptr))
	if(check_for_ctcp(parv[2]))
	  if(check_for_flud(sptr, acptr, NULL, 1))
	    return 0;
#endif /* DEATHFLUD */
#endif /* FLUD */
#ifdef ANTI_DRONE_FLOOD
      if(MyConnect(acptr) && IsClient(sptr) && !NoFloodProtection(sptr) && DRONETIME)
        {
          if((acptr->first_received_message_time+DRONETIME) < CurrentTime)
            {
              acptr->received_number_of_privmsgs=1;
              acptr->first_received_message_time = CurrentTime;
              acptr->drone_noticed = 0;
            }
          else
            {
              if(acptr->received_number_of_privmsgs > DRONECOUNT)
                {
                  if(acptr->drone_noticed == 0) /* tiny FSM */
                    {
                      sendto_ops_flag(UMODE_BOTS,
				      "Possible Drone Flooder %s [%s@%s] on %s target: %s",
				      sptr->name, sptr->username,
				      sptr->host,
				      sptr->user->server, acptr->name);
                      acptr->drone_noticed = 1;
                    }
                  /* heuristic here, if target has been getting a lot
                   * of privmsgs from clients, and sendq is above halfway up
                   * its allowed sendq, then throw away the privmsg, otherwise
                   * let it through. This adds some protection, yet doesn't
                   * DOS the client.
                   * -Dianora
                   */
                  if(DBufLength(&acptr->sendQ) > (get_sendq(acptr)/2UL))
                    {
                      if(acptr->drone_noticed == 1) /* tiny FSM */
                        {
                          sendto_ops_flag(UMODE_BOTS,
					  "ANTI_DRONE_FLOOD SendQ protection activated for %s",
					  acptr->name);

                          sendto_one(acptr,     
				     ":%s NOTICE %s :*** Notice -- Server drone flood protection activated for %s",
                                     me.name, acptr->name, acptr->name);
                          acptr->drone_noticed = 2;
                        }
                    }

                  if(DBufLength(&acptr->sendQ) <= (get_sendq(acptr)/4UL))
                    {
                      if(acptr->drone_noticed == 2)
                        {
                          sendto_one(acptr,     
                                     ":%s NOTICE %s :*** Notice -- Server drone flood protection de-activated for %s",
                                     me.name, acptr->name, acptr->name);
                          acptr->drone_noticed = 1;
                        }
                    }
                  if(acptr->drone_noticed > 1)
                    return 0;
                }
              else
                acptr->received_number_of_privmsgs++;
            }
        }
#endif

      /*
       * Simple herustic here... If PRIVMSG is locked down via
       * F:noidprivmsg:1, then act like every client is +E.
       * Otherwise, assume the normal behaviour. All in a nice
       * single if statement. --nenolod
       */
      if (MyClient(sptr) && sptr != acptr &&
	   (GlobalSetOptions.noidprivmsg != 0 ||
	   HasUmode(acptr,UMODE_BLOCK_NOTID)) 
	   && !HasUmode(sptr,UMODE_IDENTIFIED)
	   && !sptr->user->servlogin[0]
	   && !HasUmode(acptr,UMODE_DONTBLOCK)
	   && !HasUmode(sptr,UMODE_DONTBLOCK))
        {
	  /* Replace errbuf with either the default or custom message,
	   * then send the numeric on...
	   *    --nenolod
	   */
	  if (GlobalSetOptions.noidprivmsg != 0 &&
		GlobalSetOptions.noidprivmsg_notice[0])
	    {
	      strncpy_irc(errbuf, GlobalSetOptions.noidprivmsg_notice, BUFSIZE);
	    }
	  else
	    {
	      ircsnprintf(errbuf, BUFSIZE, get_str(STR_NOTID_DEFAULT),
		nick);
	    }

          sendto_one(sptr, form_str(ERR_BLOCKING_NOTID),
	      me.name, parv[0], errbuf);
	  return 0;
        }

#ifdef  SILENCE
      /* only check silence masks at the recipient's server -- jilles */
      if (!MyConnect(acptr) || !is_silenced(sptr, acptr)) {
#endif
        if (MyConnect(sptr) && acptr->user && (sptr != acptr))
          {
#ifdef  NCTCP
            /* NCTCP (umode +C) checks  -- PMA */
            if (parv[2][0] == 1) /* is CTCP */
	      /* Huh? No way, NOCTCP means NOCTCP. */
/*               if (!HasUmode(sptr,UMODE_IMMUNE) && */
/*                   !HasUmode(acptr,UMODE_IMMUNE)) */
	      if (HasUmode(acptr,UMODE_NOCTCP) ||            /* block to +C */
		  (notice && HasUmode(sptr,UMODE_NOCTCP)))   /* block replies from +C */
		return 0;                                    /* kill it! */
#endif /* NCTCP */
            if (!notice && acptr->user->away)
              sendto_one(sptr, form_str(RPL_AWAY), me.name,
                         parv[0], acptr->name,
                         acptr->user->away);
          }
        {
          /* here's where we actually send the message */
          int is_ctcp = check_for_ctcp(parv[2]);
          int cap = is_ctcp ? CAP_IDENTIFY_CTCP : CAP_IDENTIFY_MSG;
          sendto_prefix_one(acptr, sptr, ":%s %s %s :%s%s",
                            parv[0], cmd, nick,
                            !(acptr->caps & cap) ? "" :
                            (HasUmode(sptr, UMODE_IDENTIFIED) ? "+" : "-"),
                            parv[2]);
        }
#ifdef SILENCE
      }
#endif

      msgs++;
      continue;
    }

  /* Everything below here should be reserved for opers 
   * as pointed out by Mortiis, user%[email protected] 
   * syntax could be used to flood without FLUD protection
   * its also a delightful way for non-opers to find users who
   * have changed nicks -Dianora
   *
   * Grrr it was pointed out to me that x@service is valid
   * for non-opers too, and wouldn't allow for flooding/stalking
   * -Dianora
   *
   * Valid or not, @servername is unacceptable, it reveals what server
   * a person is on. Auspexen only.
   *  -- asuffield
   */

        
  /*
  ** the following two cases allow masks in NOTICEs
  ** (for OPERs only) (with +M -- asuffield)
  **
  ** Armin, 8Jun90 ([email protected])
  */
  if ((*nick == '$' || *nick == '>'))
    {

      if(!HasUmode(sptr,UMODE_MASSNOTICE))
        {
          sendto_one(sptr, form_str(ERR_NOSUCHNICK),
                     me.name, parv[0], nick);
          return -1;
        }

#ifdef NEED_TLD_FOR_MASS_NOTICE
      if (!(s = (char *)strrchr(nick, '.')))
        {
          sendto_one(sptr, form_str(ERR_NOTOPLEVEL),
                     me.name, parv[0], nick);
          msgs++;
	  continue;
        }
      while (*++s)
        if (*s == '.' || *s == '*' || *s == '?')
          break;
      if (*s == '*' || *s == '?')
        {
          sendto_one(sptr, form_str(ERR_WILDTOPLEVEL),
                     me.name, parv[0], nick);
	  msgs++;
	  continue;
        }
#endif /* NEED_TLD_FOR_MASS_NOTICE */
        
      sendto_match_butone(IsServer(cptr) ? cptr : NULL, 
                          sptr, nick + 1,
                          (*nick == '>') ? MATCH_HOST :
                          MATCH_SERVER,
                          ":%s %s %s :%s", parv[0],
                          cmd, nick, parv[2]);
      msgs++;
      continue;
    }
        
  /*
  ** user[%host]@server addressed?
  */
  if ((server = (char *)strchr(nick, '@')) &&
      (acptr = find_server(server + 1)))
    {
      int count = 0;

      /* Disable the whole farping mess for non-auspexen
       *  -- asuffield
       */
      if (!HasUmode(sptr,UMODE_AUSPEX))
        {
          sendto_one(sptr, form_str(ERR_NOSUCHNICK),
                     me.name, parv[0], nick);
 	  msgs++;
	  continue;
        }

      /* Disable the user%host@server form for non-opers
       * -Dianora
       */

      /* Disabled. This isn't very useful and I don't feel like mucking around with privs for it
       *  -- asuffield */
      if((char *)strchr(nick,'%'))
        {
          sendto_one(sptr, form_str(ERR_NOSUCHNICK),
                     me.name, parv[0], nick);
 	  msgs++;
	  continue;
        }
        
      /*
      ** Not destined for a user on me :-(
      */
      if (!IsMe(acptr))
        {
          sendto_one(acptr,":%s %s %s :%s", parv[0],
                     cmd, nick, parv[2]);
          msgs++;
          continue;
        }

      *server = '\0';

      /* special case opers@server */
      /* We don't want this on OPN -- asuffield */
#if 0
      if(!irccmp(nick,"opers") && SendWallops(sptr))
        {
          sendto_realops("To opers: From %s: %s",sptr->name,parv[2]);
          msgs++;
          continue;
        }
#endif
        
      if ((host = (char *)strchr(nick, '%')))
        *host++ = '\0';

      /*
      ** Look for users which match the destination host
      ** (no host == wildcard) and if one and one only is
      ** found connected to me, deliver message!
      */
      acptr = find_userhost(nick, host, NULL, &count);
      if (server)
        *server = '@';
      if (host)
        *--host = '%';
      if (acptr)
        {
          if (count == 1)
            sendto_prefix_one(acptr, sptr,
                              ":%s %s %s :%s",
                              parv[0], cmd,
                              nick, parv[2]);
          else if (!notice)
            sendto_one(sptr,
                       form_str(ERR_TOOMANYTARGETS),
                       me.name, parv[0], nick, MAX_MULTI_MESSAGES);
        }
      if (acptr)
	{
	  msgs++;
	  continue;
	}
    }
  /* Let's not send these remotely for channels */
  if (MyConnect(sptr) || (nick[0] != '#'))
    sendto_one(sptr, form_str(ERR_NOSUCHNICK), me.name,
	       parv[0], nick);
  msgs++;
  }
  if (strtok(NULL, ","))
    sendto_one(sptr, form_str(ERR_TOOMANYTARGETS),
                     me.name, parv[0], cmd, MAX_MULTI_MESSAGES);
  return 0;
}