Ejemplo n.º 1
0
/* m_knock
 *    parv[1] = channel
 *
 *  The KNOCK command has the following syntax:
 *   :<sender> KNOCK <channel>
 *
 *  If a user is not banned from the channel they can use the KNOCK
 *  command to have the server NOTICE the channel operators notifying
 *  they would like to join.  Helpful if the channel is invite-only, the
 *  key is forgotten, or the channel is full (INVITE can bypass each one
 *  of these conditions.  Concept by Dianora <*****@*****.**> and written by
 *  <anonymous>
 */
static int
m_knock(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
{
    struct Channel *chptr;
    char *p, *name;

    if(MyClient(source_p) && ConfigChannel.use_knock == 0) {
        sendto_one(source_p, form_str(ERR_KNOCKDISABLED),
                   me.name, source_p->name);
        return 0;
    }

    name = LOCAL_COPY(parv[1]);

    /* dont allow one knock to multiple chans */
    if((p = strchr(name, ',')))
        *p = '\0';

    if(!IsChannelName(name)) {
        sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
                           form_str(ERR_NOSUCHCHANNEL), name);
        return 0;
    }

    if((chptr = find_channel(name)) == NULL) {
        sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
                           form_str(ERR_NOSUCHCHANNEL), name);
        return 0;
    }

    if(IsMember(source_p, chptr)) {
        if(MyClient(source_p))
            sendto_one(source_p, form_str(ERR_KNOCKONCHAN),
                       me.name, source_p->name, name);
        return 0;
    }

    if(!((chptr->mode.mode & MODE_INVITEONLY) || (*chptr->mode.key) ||
         (chptr->mode.limit &&
          rb_dlink_list_length(&chptr->members) >= (unsigned long)chptr->mode.limit))) {
        sendto_one_numeric(source_p, ERR_CHANOPEN,
                           form_str(ERR_CHANOPEN), name);
        return 0;
    }

    /* cant knock to a +p channel */
    if(HiddenChannel(chptr)) {
        sendto_one_numeric(source_p, ERR_CANNOTSENDTOCHAN,
                           form_str(ERR_CANNOTSENDTOCHAN), name, "channel does not accept knocks");
        return 0;
    }


    if(MyClient(source_p)) {
        /* don't allow a knock if the user is banned */
        if(is_banned(chptr, source_p, NULL, NULL, NULL) == CHFL_BAN ||
           is_quieted(chptr, source_p, NULL, NULL, NULL) == CHFL_BAN) {
            sendto_one_numeric(source_p, ERR_CANNOTSENDTOCHAN,
                               form_str(ERR_CANNOTSENDTOCHAN), name, "you are banned from this channel");
            return 0;
        }

        /* local flood protection:
         * allow one knock per user per knock_delay
         * allow one knock per channel per knock_delay_channel
         */
        if(!IsOper(source_p) &&
           (source_p->localClient->last_knock + ConfigChannel.knock_delay) > rb_current_time()) {
            sendto_one(source_p, form_str(ERR_TOOMANYKNOCK),
                       me.name, source_p->name, name, "user");
            return 0;
        } else if((chptr->last_knock + ConfigChannel.knock_delay_channel) > rb_current_time()) {
            sendto_one(source_p, form_str(ERR_TOOMANYKNOCK),
                       me.name, source_p->name, name, "channel");
            return 0;
        }

        /* ok, we actually can send the knock, tell client */
        source_p->localClient->last_knock = rb_current_time();

        sendto_one(source_p, form_str(RPL_KNOCKDLVR),
                   me.name, source_p->name, name);
    }

    chptr->last_knock = rb_current_time();

    if(ConfigChannel.use_knock)
        sendto_channel_local(chptr->mode.mode & MODE_FREEINVITE ? ALL_MEMBERS : ONLY_CHANOPS,
                             chptr, form_str(RPL_KNOCK),
                             me.name, name, name, source_p->name,
                             source_p->username, source_p->host);

    sendto_server(client_p, chptr, CAP_KNOCK|CAP_TS6, NOCAPS,
                  ":%s KNOCK %s", use_id(source_p), name);
    sendto_server(client_p, chptr, CAP_KNOCK, CAP_TS6,
                  ":%s KNOCK %s", source_p->name, name);
    return 0;
}
Ejemplo n.º 2
0
static int can_see(aClient *sptr, aClient *acptr, aChannel *channel)
{
int ret = 0;
char has_common_chan = 0;
	do {
		/* can only see people */
		if (!IsPerson(acptr))
			return WHO_CANTSEE;

		/* can only see opers if thats what they want */
		if (who_flags & WF_OPERONLY)
		{
			if (!IsAnOper(acptr))
				return ret | WHO_CANTSEE;
			if (IsHideOper(acptr)) {
				if (IsAnOper(sptr))
					ret |= WHO_OPERSEE;
				else
					return ret | WHO_CANTSEE;
			}
		}

		/* if they only want people who are away */
		if ((wfl.want_away == WHO_WANT && !acptr->user->away) ||
		    (wfl.want_away == WHO_DONTWANT && acptr->user->away))
			return WHO_CANTSEE;

		/* if they only want people on a certain channel. */
		if (wfl.want_channel != WHO_DONTCARE)
 		{
			aChannel *chan = find_channel(wfl.channel, NULL);
			if (!chan && wfl.want_channel == WHO_WANT)
				return WHO_CANTSEE;
			if ((wfl.want_channel == WHO_WANT) && !IsMember(acptr, chan))
				return WHO_CANTSEE;
			if ((wfl.want_channel == WHO_DONTWANT) && IsMember(acptr, chan))
				return WHO_CANTSEE;
		}

		/* if they only want people with a certain gecos */
		if (wfl.want_gecos != WHO_DONTCARE)
		{
			if (((wfl.want_gecos == WHO_WANT) && match(wfl.gecos, acptr->info)) ||
			    ((wfl.want_gecos == WHO_DONTWANT) && !match(wfl.gecos, acptr->info)))
			{
				return WHO_CANTSEE;
			}
		}

		/* if they only want people with a certain server */
		if (wfl.want_server != WHO_DONTCARE)
		{
			if (((wfl.want_server == WHO_WANT) && stricmp(wfl.server, acptr->user->server)) ||
			    ((wfl.want_server == WHO_DONTWANT) && !stricmp(wfl.server, acptr->user->server)))
			{
				return WHO_CANTSEE;
			}
		}

		/* if they only want people with a certain host */
		if (wfl.want_host != WHO_DONTCARE)
		{
			char *host;

			if (IsAnOper(sptr))
				host = acptr->user->realhost;
			else
				host = GetHost(acptr);

			if (((wfl.want_host == WHO_WANT) && match(wfl.host, host)) ||
			    ((wfl.want_host == WHO_DONTWANT) && !match(wfl.host, host)))
			{
				return WHO_CANTSEE;
			}
		}

		/* if they only want people with a certain IP */
		if (wfl.want_ip != WHO_DONTCARE)
		{
			char *ip;

			ip = acptr->user->ip_str;
			if (!ip)
				return WHO_CANTSEE;

			if (((wfl.want_ip == WHO_WANT) && match(wfl.ip, ip)) ||
			    ((wfl.want_ip == WHO_DONTWANT) && !match(wfl.ip, ip)))
			{
				return WHO_CANTSEE;
			}
		}

		/* if they only want people with a certain nick.. */
		if (wfl.want_nick != WHO_DONTCARE)
		{
			if (((wfl.want_nick == WHO_WANT) && match(wfl.nick, acptr->name)) ||
			    ((wfl.want_nick == WHO_DONTWANT) && !match(wfl.nick, acptr->name)))
			{
				return WHO_CANTSEE;
			}
		}

		/* if they only want people with a certain username */
		if (wfl.want_user != WHO_DONTCARE)
		{
			if (((wfl.want_user == WHO_WANT) && match(wfl.user, acptr->user->username)) ||
			    ((wfl.want_user == WHO_DONTWANT) && !match(wfl.user, acptr->user->username)))
			{
				return WHO_CANTSEE;
			}
		}

		/* if they only want people with a certain umode */
		if (wfl.umodes_want)
		{
			if (!(acptr->umodes & wfl.umodes_want) || (!IsAnOper(sptr) && (acptr->umodes & UMODE_HIDEOPER)))
				return WHO_CANTSEE;
		}

		if (wfl.umodes_dontwant)
		{
			if ((acptr->umodes & wfl.umodes_dontwant) && (!(acptr->umodes & UMODE_HIDEOPER) || IsAnOper(sptr)))
				return WHO_CANTSEE;
		}

		/* if they only want common channels */
		if (wfl.common_channels_only)
		{
			if (!has_common_channels(sptr, acptr))
				return WHO_CANTSEE;
			has_common_chan = 1;
		}

		if (channel)
		{
			int member = who_flags & WF_ONCHANNEL;

			if (SecretChannel(channel) || HiddenChannel(channel))
			{
				/* if they aren't on it.. they can't see it */
				if (!(who_flags & WF_ONCHANNEL))
					break;
			}
			if (IsInvisible(acptr) && !member)
				break;
			if ((channel->mode.mode & MODE_AUDITORIUM) &&
			    !is_chan_op(acptr, channel) && !is_chan_op(sptr, channel))
				break;
		}
		else
		{
			/* a user/mask who */

			/* If the common channel info hasn't been set, set it now */
			if (!wfl.common_channels_only)
				has_common_chan = has_common_channels(sptr, acptr);

			if (IsInvisible(acptr) && !has_common_chan)
			{
				/* don't show them unless it's an exact match 
				   or it is the user requesting the /who */
				if ((who_flags & WF_WILDCARD) && sptr != acptr)
					break;
			}
		}

		/* phew.. show them. */
		return WHO_CANSEE;
	} while (0);

	/* if we get here, it's oper-dependant. */
	if (IsAnOper(sptr))
		return ret | WHO_OPERSEE | WHO_CANSEE;
	else
	{
		if (sptr == acptr)
			return ret | WHO_CANSEE;
		else
			return ret | WHO_CANTSEE;
	}
}
Ejemplo n.º 3
0
/*
** m_who
**      parv[0] = sender prefix
**      parv[1] = nickname mask list
**      parv[2] = additional selection flag, only 'o' for now.
*/
int     m_who(struct Client *cptr,
              struct Client *sptr,
              int parc,
              char *parv[])
{
  struct Client *acptr;
  char  *mask = parc > 1 ? parv[1] : NULL;
  Link  *lp;
  struct Channel *chptr;
  struct Channel *mychannel = NULL;
  char  *channame = NULL;
  int   oper = parc > 2 ? (*parv[2] == 'o' ): 0; /* Show OPERS only */
  int   member;
  int   maxmatches = 500;

  mychannel = NullChn;
  if (sptr->user)
    if ((lp = sptr->user->channel))
      mychannel = lp->value.chptr;

  /*
  **  Following code is some ugly hacking to preserve the
  **  functions of the old implementation. (Also, people
  **  will complain when they try to use masks like "12tes*"
  **  and get people on channel 12 ;) --msa
  */
  if (mask)
    {
      if (!strcmp(mask, "**"))
        mask = NULL;
      else if (*mask == (char) 0)
        mask = NULL;
      else
        (void)collapse(mask);
    }
  if (!mask || (*mask == (char) 0))
    {
      if (!HasUmode(sptr,UMODE_USER_AUSPEX))
        {
          sendto_one(sptr, form_str(RPL_ENDOFWHO), me.name, parv[0],
                     EmptyString(mask) ?  "*" : mask);
          return 0;
        }
    }
  else if ((*(mask+1) == (char) 0) && (*mask == '*'))
    {
      if (!mychannel)
        {
          sendto_one(sptr, form_str(RPL_ENDOFWHO), me.name, parv[0],
                     EmptyString(mask) ?  "*" : mask);
          return 0;
        }
      channame = mychannel->chname;
    }
  else
    channame = mask;

  if (IsChannelName(channame))
    {
      /*
       * List all users on a given channel
       */
      if (!oper || SeesOpers(sptr)) /* If you're doing an oper search, you need SeesOpers() */
	{
	  chptr = hash_find_channel(channame, NULL);
	  if (chptr)
	    {
	      member = IsMember(sptr, chptr) || IsLogger(sptr, chptr) || HasUmode(sptr,UMODE_USER_AUSPEX);
	      if (member || !SecretChannel(chptr))
		for (lp = chptr->members; lp; lp = lp->next)
		  {
		    if (oper && !HasUmode(lp->value.cptr,UMODE_OPER))
		      continue;
		    if (IsInvisible(lp->value.cptr) && !member)
		      continue;
		    do_who(sptr, lp->value.cptr, chptr, lp);
		  }
	    }
	}
    }
  else if (mask && 
           ((acptr = find_client(mask, NULL)) != NULL) &&
           IsPerson(acptr) && (!oper || (HasUmode(acptr,UMODE_OPER) && SeesOpers(sptr))))
    {
      int isinvis = 0;
      struct Channel *ch2ptr = NULL;

      isinvis = IsInvisible(acptr);
      for (lp = acptr->user->channel; lp; lp = lp->next)
        {
          chptr = lp->value.chptr;
          member = IsMember(sptr, chptr) || HasUmode(sptr,UMODE_USER_AUSPEX);
          if (isinvis && !member)
            continue;
          if (member || (!isinvis && PubChannel(chptr)))
            {
              ch2ptr = chptr;
              break;
            }
        }
      do_who(sptr, acptr, ch2ptr, NULL);
    }
  else if (!oper || SeesOpers(sptr))
    for (acptr = GlobalClientList; acptr; acptr = acptr->next)
    {
      struct Channel *ch2ptr = NULL;
      int       showperson, isinvis;

      if (!IsPerson(acptr))
        continue;
      if (oper && !HasUmode(acptr,UMODE_OPER))
        continue;
      
      showperson = 0;
      /*
       * Show user if they are on the same channel, or not
       * invisible and on a non secret channel (if any).
       * Do this before brute force match on all relevant fields
       * since these are less cpu intensive (I hope :-) and should
       * provide better/more shortcuts - avalon
       */
      isinvis = IsInvisible(acptr);
      for (lp = acptr->user->channel; lp; lp = lp->next)
        {
          chptr = lp->value.chptr;
          member = IsMember(sptr, chptr) || HasUmode(sptr, UMODE_USER_AUSPEX);
          if (isinvis && !member)
            continue;
          if (member || (!isinvis && PubChannel(chptr)))
            {
              ch2ptr = chptr;
              showperson = 1;
              break;
            }
          if (HiddenChannel(chptr) && !SecretChannel(chptr) &&
              !isinvis)
            showperson = 1;
        }
      if (!acptr->user->channel && !isinvis)
        showperson = 1;
        
      if ((HasUmode(sptr,UMODE_USER_AUSPEX) || showperson) &&
          (!mask ||
           match(mask, acptr->name) ||
           match(mask, acptr->username) ||
           match(mask, acptr->host) ||
           (HasUmode(sptr, UMODE_AUSPEX) && match(mask, acptr->user->server)) ||
           match(mask, acptr->info)))
        {
          do_who(sptr, acptr, ch2ptr, NULL);
          if (!HasUmode(sptr,UMODE_USER_AUSPEX) && !--maxmatches)
            {
              sendto_one(sptr, form_str(RPL_ENDOFWHO), me.name, parv[0],
                         EmptyString(mask) ?  "*" : mask);
              return 0;
            }
        }
    }

  sendto_one(sptr, form_str(RPL_ENDOFWHO), me.name, parv[0],
             EmptyString(mask) ?  "*" : mask);
  return 0;
}
Ejemplo n.º 4
0
/*
 * Search and return as many people as matched by the wild 'nick'.
 * returns the number of people found (or, obviously, 0, if none where
 * found).
 */
static int do_wilds(struct Client* sptr, char *nick, int count, int parc)
{
  struct Client *acptr; /* Current client we're considering */
  struct User *user; 	/* the user portion of the client */
  const char *name; 	/* the name of this client */
  struct Membership* chan; 
  int invis; 		/* does +i apply? */
  int member;		/* Is this user on any channels? */
  int showperson;       /* Should we show this person? */
  int found = 0 ;	/* How many were found? */
  
  /* Ech! This is hideous! */
  for (acptr = GlobalClientList; (acptr = next_client(acptr, nick));
      acptr = cli_next(acptr))
  {
    if (!IsRegistered(acptr)) 
      continue;
      
    if (IsServer(acptr))
      continue;
    /*
     * I'm always last :-) and acptr->next == 0!!
     *
     * Isomer: Does this strike anyone else as being a horrible hideous
     *         hack?
     */
    if (IsMe(acptr)) {
      assert(!cli_next(acptr));
      break;
    }
    
    /*
     * 'Rules' established for sending a WHOIS reply:
     *
     * - if wildcards are being used don't send a reply if
     *   the querier isn't any common channels and the
     *   client in question is invisible.
     *
     * - only send replies about common or public channels
     *   the target user(s) are on;
     */
    user = cli_user(acptr);
    name = (!*(cli_name(acptr))) ? "?" : cli_name(acptr);
    assert(user);

    invis = (acptr != sptr) && IsInvisible(acptr);
    member = (user && user->channel) ? 1 : 0;
    showperson = !invis && !member;
    
    /* Should we show this person now? */
    if (showperson) {
    	found++;
    	do_whois(sptr, acptr, parc);
    	if (count+found>MAX_WHOIS_LINES)
    	  return found;
    	continue;
    }
    
    /* Step through the channels this user is on */
    for (chan = user->channel; chan; chan = chan->next_channel)
    {
      struct Channel *chptr = chan->channel;

      /* If this is a public channel, show the person */
      if (!invis && PubChannel(chptr)) {
        showperson = 1;
        break;
      }
      
      /* if this channel is +p and not +s, show them */
      if (!invis && HiddenChannel(chptr) && !SecretChannel(chptr)) {
          showperson = 1;
          break;
      }
      
      member = find_channel_member(sptr, chptr) ? 1 : 0;
      if (invis && !member)
        continue;

      /* If sptr isn't really on this channel, skip it */
      if (IsZombie(chan))
        continue;
       
      /* Is this a common channel? */ 
      if (member) {
        showperson = 1;
        break;
      }
    } /* of for (chan in channels) */
    
    /* Don't show this person */
    if (!showperson)
      continue;
      
    do_whois(sptr, acptr, parc);
    found++;
    if (count+found>MAX_WHOIS_LINES)
       return found;  
  } /* of global client list */
  
  return found;
}