Beispiel #1
0
/* IDLE updates the idle time */
int m_idle(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
{
  struct Client *acptr = sptr;
  time_t last = CurrentTime;

  if (parc > 1)
    if (!(acptr = find_client(parv[1], NULL)))
      return 0;

  if (parc > 2)
    last = strtoul(parv[2], NULL, 0);

  acptr->user->last = last;
#if 0 /* this is broken and its consequences are poorly understood -- jilles */
  /* If more than MAX_IDLE_DESYNC seconds have elapsed, propagate the IDLE */
  if ((last + MAX_IDLE_DESYNC) < CurrentTime)
    {
      /* Redundant but do it anyway for consistancy */
      acptr->user->last_sent = CurrentTime;
      /* Propagate the message... */
#ifdef HAVE_LONG_LONG
      sendto_serv_butone(cptr, ":%s IDLE %s %.1lld", me.name, acptr->name, (long long)last);
#else
      sendto_serv_butone(cptr, ":%s IDLE %s %.1ld", me.name, acptr->name, (long)last);
#endif
    }
#endif
  return 0;
}
Beispiel #2
0
/* This function adds as an extra (weird) operoverride.
 * Currently it's only used if you try to operoverride for a +z channel,
 * if you then do '/join #chan override' it will put the channel -z and allow you directly in.
 * This is to avoid attackers from using 'race conditions' to prevent you from joining.
 * PARAMETERS: sptr = the client, chptr = the channel, mval = mode value (eg MODE_ONLYSECURE),
 *             mchar = mode char (eg 'z')
 * RETURNS: 1 if operoverride, 0 if not.
 */
int extended_operoverride(aClient *sptr, aChannel *chptr, char *key, int mval, char mchar)
{
    unsigned char invited = 0;
    Link *lp;

    if (!IsAnOper(sptr) || !OPCanOverride(sptr))
        return 0;

    for (lp = sptr->user->invited; lp; lp = lp->next)
        if (lp->value.chptr == chptr)
        {
            invited = 1;
            break;
        }
    if (invited)
    {
        if (key && !strcasecmp(key, "override"))
        {
            sendto_channelprefix_butone(NULL, &me, chptr, PREFIX_OP|PREFIX_ADMIN|PREFIX_OWNER,
                                        ":%s NOTICE @%s :setting channel -%c due to OperOverride request from %s",
                                        me.name, chptr->chname, mchar, sptr->name);
            sendto_serv_butone(&me, ":%s MODE %s -%c 0", me.name, chptr->chname, mchar);
            sendto_channel_butserv(chptr, &me, ":%s MODE %s -%c", me.name, chptr->chname, mchar);
            chptr->mode.mode &= ~mval;
            return 1;
        }
    }
    return 0;
}
Beispiel #3
0
/*
 * m_lnotice (send notice to all local users)
 *      parv[0] = sender prefix
 *      parv[1] = message text
 */
int m_lnotice(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
{ 
  char* message;
  struct Client *acptr;

  message = parc > 1 ? parv[1] : NULL;
  
  if (EmptyString(message))
    {
      sendto_one(sptr, form_str(ERR_NEEDMOREPARAMS),
                 me.name, parv[0], "LNOTICE");
      return 0;
    }

  if (MyClient(sptr) && !IsAnOper(sptr))
    {
      sendto_one(sptr, form_str(ERR_NOPRIVILEGES), me.name, parv[0]);
      return(0);
    }

  for(acptr = local_cptr_list; acptr; acptr = acptr->next_local_client)
    {      
      sendto_one(acptr,":%s NOTICE %s :%s",
         me.name, acptr->name, parv[1]);
    }

  sendto_ops("LNOTICE sent by \2%s\2",parv[0]);
  sendto_serv_butone(&me, ":%s GLOBOPS :LNOTICE on %s :%s", 
    me.name, sptr->name, parv[1]);

  return 0;      
}	                                 	
Beispiel #4
0
/*
 * m_globops (write to *all* opers currently online)
 *      parv[0] = sender prefix
 *      parv[1] = message text
 */
int m_globops(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
{ 
  char* message;

  message = parc > 1 ? parv[1] : NULL;
  
  if (EmptyString(message))
    {
      sendto_one(sptr, form_str(ERR_NEEDMOREPARAMS),
                 me.name, parv[0], "GLOBOPS");
      return 0;
    }

  if (!IsServer(sptr) && MyConnect(sptr) && !IsAnOper(sptr))
    {
      sendto_one(sptr, form_str(ERR_NOPRIVILEGES), me.name, parv[0]);
      return(0);
    }

  sendto_serv_butone(IsServer(cptr) ? cptr : NULL,
                       ":%s GLOBOPS :%s", parv[0], message);
					   
  sendto_globops("from %s: %s", parv[0], message);
	
  return 0;
}
Beispiel #5
0
void send_opnotice(service_t *sp, char *msg, ...) {
    char fmsg[512];
    va_list vl;

    va_start(vl, msg);
    vsnprintf(fmsg, 512, msg, vl);
    sendto_serv_butone(NULL, (sp == NULL ? NULL : sp->client),
            (sp == NULL ? ircd.me : NULL), NULL,
            (sp == NULL ? "GNOTICE" : "GLOBOPS"), ":%s", fmsg);
    va_end(vl);
}
Beispiel #6
0
/*
 * m_wallops (write to *all* opers currently online)
 *      parv[0] = sender prefix
 *      parv[1] = message text
 */
int m_wallops(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
{ 
  char* message;

  message = parc > 1 ? parv[1] : NULL;
  
  if (EmptyString(message))
    {
      sendto_one(sptr, form_str(ERR_NEEDMOREPARAMS),
                 me.name, parv[0], "WALLOPS");
      return 0;
    }

  if (!IsServer(sptr) && MyConnect(sptr) && !IsAnOper(sptr))
    {
      sendto_one(sptr, form_str(ERR_NOPRIVILEGES), me.name, parv[0]);
      return(0);
    }

  /* If its coming from a server, do the normal thing
     if its coming from an oper, send the wallops along
     and only send the wallops to our local opers (those who are +ow)
     -Dianora
  */

  if(!IsServer(sptr))   /* If source of message is not a server, i.e. oper */
    {

#ifdef PACE_WALLOPS
      if( MyClient(sptr) )
        {
          if( (LastUsedWallops + WALLOPS_WAIT) > CurrentTime )
            { 
          	sendto_one(sptr, ":%s NOTICE %s :Oh, one of those annoying opers who doesn't know how to use a channel",
                     me.name,parv[0]);
          	return 0;
            }
          LastUsedWallops = CurrentTime;
        }
#endif

      send_operwall(sptr, "WALLOPS", message);
      sendto_serv_butone( IsServer(cptr) ? cptr : NULL,
                          ":%s WALLOPS :%s", parv[0], message);
    }
  else                  /* its a server wallops */
    sendto_wallops_butone(IsServer(cptr) ? cptr : NULL, sptr,
                            ":%s WALLOPS :%s", parv[0], message);
  return 0;
}
Beispiel #7
0
/*
 * m_sxline() - add info ban line
 *
 *	parv[0] = sender prefix
 *	parv[1] =  info banned mask
 */
int	m_sxline(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
  {
    aConfItem *aconf;
    char *reason = NULL;
    char *mask;
    int len;

	if (!IsService(sptr) && !IsServer(cptr))
	  {
		sendto_one(sptr, form_str(ERR_NOPRIVILEGES), me.name, parv[0]);
		return 0;
	  }	  
		
	if(parc<3)
	  {
		sendto_one(sptr, form_str(ERR_NEEDMOREPARAMS),
      	  me.name, parv[0], "SXLINE");
        return 0;
	  }
      
    len=atoi(parv[1]);
    mask = parv[2];
    
    if ((strlen(mask) > len) && (mask[len])==':')
      {
        mask[len] = '\0';
        reason = mask+len+1;
      } 
    else
      { /* Bogus */
        return 0;
      }
    
    if (!find_sxline(mask)) /* sxline does not exist */
	  {

		aconf = make_conf();
		DupString(aconf->name, mask);
		DupString(aconf->passwd, reason);
	    aconf->next = sxlines;
		sxlines = aconf;		

        sendto_serv_butone(cptr, ":%s SXLINE %d :%s:%s", sptr->name, len,
                       aconf->name,aconf->passwd);
	  }

	return 0;
  }
void do_chanflood_action(aChannel *chptr, int what, char *text)
{
long modeflag = 0;
aCtab *tab = &cFlagTab[0];
char m;

	m = chptr->mode.floodprot->a[what];
	if (!m)
		return;

	/* [TODO: add extended channel mode support] */
	
	while(tab->mode != 0x0)
	{
		if (tab->flag == m)
		{
			modeflag = tab->mode;
			break;
		}
		tab++;
	}

	if (!modeflag)
		return;
		
	if (!(chptr->mode.mode & modeflag))
	{
		char comment[1024], target[CHANNELLEN + 8];
		ircsprintf(comment, "*** Channel %sflood detected (limit is %d per %d seconds), setting mode +%c",
			text, chptr->mode.floodprot->l[what], chptr->mode.floodprot->per, m);
		ircsprintf(target, "%%%s", chptr->chname);
		sendto_channelprefix_butone_tok(NULL, &me, chptr,
			PREFIX_HALFOP|PREFIX_OP|PREFIX_ADMIN|PREFIX_OWNER,
			MSG_NOTICE, TOK_NOTICE, target, comment, 0);
		sendto_serv_butone(&me, ":%s MODE %s +%c 0", me.name, chptr->chname, m);
		sendto_channel_butserv(chptr, &me, ":%s MODE %s +%c", me.name, chptr->chname, m);
		chptr->mode.mode |= modeflag;
		if (chptr->mode.floodprot->r[what]) /* Add remove-chanmode timer... */
		{
			chanfloodtimer_add(chptr, m, modeflag, TStime() + ((long)chptr->mode.floodprot->r[what] * 60) - 5);
			/* (since the chanflood timer event is called every 10s, we do -5 here so the accurancy will
			 *  be -5..+5, without it it would be 0..+10.)
			 */
		}
	}
}
Beispiel #9
0
void change_nick(aClient *acptr, char *newnick)
{
  char     nick[NICKLEN + 2];
    
  strncpy_irc(nick, newnick, NICKLEN);
  nick[NICKLEN] = '\0';

  ClearIdentified(acptr);	/* maybe not needed, but safe -Lamego */

  /* send change to common channels */
  sendto_common_channels(acptr, ":%s NICK :%s", acptr->name, nick);
  if (acptr->user)
    {
      acptr->tsinfo = CurrentTime;
      add_history(acptr,1);
      /* propagate to all servers */
      sendto_serv_butone(NULL, ":%s NICK %s :%lu",
      acptr->name, nick, acptr->tsinfo);
    }          
		  	
  /*
   **  Finally set new nick name.
  */
  if (acptr->name[0]) 
    {
      del_from_client_hash_table(acptr->name, acptr);
      hash_check_watch(acptr, RPL_LOGOFF);     
    }
		
  strcpy(acptr->name, nick);
  add_to_client_hash_table(nick, acptr);
  hash_check_watch(acptr, RPL_LOGON);
	  
  /* Lets apply nick change delay (if needed) */
  acptr->services_nick_change++;
  if(acptr->services_nick_change>1)
    {
      acptr->number_of_nick_changes = MAX_NICK_CHANGES+1;
      acptr->last_nick_change = CurrentTime;
      acptr->services_nick_change = 0;
    }
}
Beispiel #10
0
/* m_setname - for SETNAME command
 * allow users to change it's real name
 *  -- openglx, on a boring 25/12/2003
 */
int m_setname(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
{

  struct Client *acptr = sptr;
  char *newname = parv[1];
  char *mename = me.name;
  
  if(acptr->user && acptr->user->vlink)
    mename = acptr->user->vlink->name;

  if (!AllowSetNameToEveryone && !IsPrivileged(sptr))
    {
      sendto_one(sptr, form_str(ERR_NOPRIVILEGES), me.name, parv[0]);
      return 0;
    }
  
  if (parc<2 || EmptyString(parv[1]))
    {
      if(MyClient(sptr))
        sendto_one(sptr, ":%s NOTICE %s :*** Syntax: /SETNAME <real name>", mename, parv[0]);
      return 0;
    }
  
  if (strlen(newname) > REALLEN) /* just to be sure */
    {
      if(MyClient(sptr))
        sendto_one(sptr, ":%s NOTICE %s :*** SETNAME: select a real name under %d chars", 
                   mename, acptr->name, REALLEN);
      return 0;
    }   
  
  strcpy(acptr->info, newname);
  
  sendto_serv_butone(cptr, ":%s SETNAME :%s", parv[0], newname);
  
  if (MyClient(acptr)) 
     sendto_one(acptr, ":%s NOTICE %s :*** New real name set: \2%s\2", mename, acptr->name,
                acptr->info);

  return 0; /* I wonder why shouldn't this be 1 */
                              
}
int m_operwall(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
{
  char *message = parc > 1 ? parv[1] : NULL;


  if (check_registered_user(sptr))
    return 0;
  if (!SendOperwall(sptr) || IsServer(sptr))
    {
      if (MyClient(sptr) && !IsServer(sptr))
        sendto_one(sptr, form_str(ERR_NOPRIVILEGES),
                   me.name, parv[0]);
      return 0;
    }
  if (EmptyString(message))
    {
      if (MyClient(sptr))
        sendto_one(sptr, form_str(ERR_NEEDMOREPARAMS),
                   me.name, parv[0], "OPERWALL");
      return 0;
    }

#ifdef PACE_WALLOPS
  if( MyClient(sptr) )
    {
          if( (LastUsedWallops + WALLOPS_WAIT) > CurrentTime ) 
            {
                sendto_one(sptr, ":%s NOTICE %s :Oh, one of those annoying opers who doesn't know how to use a channel",
                     me.name,parv[0]);
                return 0;
            }
          LastUsedWallops = CurrentTime;
     }
#endif

  sendto_serv_butone(IsServer(cptr) ? cptr : NULL, ":%s OPERWALL :%s",
                     parv[0], message);
  send_operwall(sptr, "OPERWALL", message);
  return 0;
}
Beispiel #12
0
/*
 * m_unsxline() - remove sxline
 *
 *	parv[0] = sender prefix
 *	parv[1] = sxlined name
 */
int	m_unsxline(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
  {
	aConfItem *sxl = sxlines;
	aConfItem *last_sxl = NULL;
		
	if (!IsService(sptr) && !IsServer(cptr))
	  {
		sendto_one(sptr, form_str(ERR_NOPRIVILEGES), me.name, parv[0]);
		return 0;
	  }	  
		
	if(parc<2)
	  {
		sendto_one(sptr, form_str(ERR_NEEDMOREPARAMS),
      	  me.name, parv[0], "UNSXLINE");
        return 0;
	  }		  
	
	while(sxl && irccmp(sxl->name, parv[1]))
	  {
		last_sxl = sxl;
		sxl = sxl->next;
	  }
	  
    if (sxl) /* if sxline does exist */
	  {
		if(last_sxl) /* this is not the first sxline */
			last_sxl->next=sxl->next; /* adjust list link -> */
		  else
			sxlines = sxl->next;
			
		free_conf(sxl);
		
	    sendto_serv_butone(cptr, ":%s UNSXLINE :%s",
			parv[0], parv[1]);
	  }
	  
	return 0;
  }
Beispiel #13
0
/*
 * m_rnotice (send notice to all users on a given server)
 *      parv[0] = sender prefix
 *      parv[1] = target server
 *	parv[2] = message
 */
int m_rnotice(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
{ 
  char* message;
  struct Client *acptr;

  /* firs check if user has enough privileges */
  if (MyClient(sptr) && !IsAnOper(sptr))
    {
      sendto_one(sptr, form_str(ERR_NOPRIVILEGES), me.name, parv[0]);
      return(0);
    }

  message = parv[2];      
  /* now check if sufficiente parameters */
  if (EmptyString(message) || parc<3 )
    {
      if(MyClient(sptr))
      sendto_one(sptr, form_str(ERR_NEEDMOREPARAMS),
                 me.name, parv[0], "RNOTICE");
      return 0;
    }
  
  /* check we are the hunted server (send to server if not) */
  if(hunt_server (cptr, sptr, ":%s RNOTICE %s :%s", 1, parc, parv) != HUNTED_ISME)
	return 0;

  for(acptr = local_cptr_list; acptr; acptr = acptr->next_local_client)
    {      
      sendto_one(acptr,":%s NOTICE %s :%s",
         me.name, acptr->name, message);
    }

  sendto_ops("RNOTICE sent by \2%s\2",parv[0]);
  sendto_serv_butone(&me, ":%s GLOBOPS :LNOTICE to %s :%s", 
  	sptr->name, parv[1], parv[2]);

  return 0;      
}	                                 	
Beispiel #14
0
/*
 * m_wallops (write to *all* opers currently online)
 *      parv[0] = sender prefix
 *      parv[1] = message text
 */
int m_wallops(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
{ 
  char* message;

  message = parc > 1 ? parv[1] : NULL;
  
  if (EmptyString(message))
    {
      sendto_one(sptr, form_str(ERR_NEEDMOREPARAMS),
                 me.name, parv[0], "WALLOPS");
      return 0;
    }

  if (!IsServer(sptr) && MyConnect(sptr) && !IsAnOper(sptr))
    {
      sendto_one(sptr, form_str(ERR_NOPRIVILEGES), me.name, parv[0]);
      return(0);
    }

  /* If its coming from a server, do the normal thing
     if its coming from an oper, send the wallops along
     and only send the wallops to our local opers (those who are +oz)
     -Dianora
  */

  if(!IsServer(sptr))   /* If source of message is not a server, i.e. oper */
    {
      send_operwall(sptr, "WALLOPS", message);
      sendto_serv_butone( IsServer(cptr) ? cptr : NULL,
                          ":%s WALLOPS :%s", parv[0], message);
    }
  else                  /* its a server wallops */
    sendto_wallops_butone(IsServer(cptr) ? cptr : NULL, sptr,
                            ":%s WALLOPS :%s", parv[0], message);
  return 0;
}
Beispiel #15
0
/*
 * parse a buffer.
 *
 * NOTE: parse() should not be called recusively by any other functions!
 */
int parse(aClient *cptr, char *pbuffer, char *bufend)
{
  aClient *from = cptr;
  char  *ch;
  char  *s;
  size_t i;
  char* numeric = 0;
  unsigned int paramcount;
  struct Message *mptr;

  Debug((DEBUG_DEBUG, "Parsing %s: %s",
         get_client_name(cptr, TRUE), pbuffer));

  if (IsDead(cptr))
    return -1;

  s = sender;
  *s = '\0';

  for (ch = pbuffer; *ch == ' '; ch++)   /* skip spaces */
    /* null statement */ ;

  para[0] = from->name;
  if (*ch == ':')
    {
      ch++;

      /*
      ** Copy the prefix to 'sender' assuming it terminates
      ** with SPACE (or NULL, which is an error, though).
      */
      for (i = 0; *ch && *ch != ' '; i++ )
	{
	  if (i < (sizeof(sender)-1))
	    *s++ = *ch; /* leave room for NULL */
	  ch++;
	}
      *s = '\0';
      i = 0;

      /*
      ** Actually, only messages coming from servers can have
      ** the prefix--prefix silently ignored, if coming from
      ** a user client...
      **
      ** ...sigh, the current release "v2.2PL1" generates also
      ** null prefixes, at least to NOTIFY messages (e.g. it
      ** puts "sptr->nickname" as prefix from server structures
      ** where it's null--the following will handle this case
      ** as "no prefix" at all --msa  (": NOTICE nick ...")
      */
      if (*sender && IsServer(cptr))
        {
          from = find_client(sender, (aClient *) NULL);
          if (!from || !match(from->name, sender))
            from = find_server(sender);

          para[0] = sender;
          
          /* Hmm! If the client corresponding to the
           * prefix is not found--what is the correct
           * action??? Now, I will ignore the message
           * (old IRC just let it through as if the
           * prefix just wasn't there...) --msa
           */
          if (!from)
            {
	      sendto_ops_flag_butone(cptr, UMODE_DEBUG, "Unknown prefix (%s) from (%s)",
				     sender, cptr->name);
              Debug((DEBUG_ERROR, "Unknown prefix (%s)(%s) from (%s)",
                     sender, pbuffer, cptr->name));
              ServerStats->is_unpf++;

              remove_unknown(cptr, sender, pbuffer);

              return -1;
            }
          if (from->from != cptr)
            {
              ServerStats->is_wrdi++;
              Debug((DEBUG_ERROR, "Message (%s) coming from (%s)",
                     buffer, cptr->name));
	      sendto_ops_flag_butone(cptr, UMODE_DEBUG, "Message coming from (%s), but %s is at %s",
				     cptr->name, from->name, from->from->name);

              return cancel_clients(cptr, from, pbuffer);
            }
        }
      while (*ch == ' ')
        ch++;
    }

  if (*ch == '\0')
    {
      ServerStats->is_empt++;
      Debug((DEBUG_NOTICE, "Empty message from host %s:%s",
             cptr->name, from->name));
      if (IsServer(cptr))
	sendto_ops_flag_butone(cptr, UMODE_DEBUG, "Empty message from %s:%s",
			       cptr->name, from->name);
      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
  *
  * ummm???? - Dianora
  */

  if( *(ch + 3) == ' ' && /* ok, lets see if its a possible numeric.. */
      IsDigit(*ch) && IsDigit(*(ch + 1)) && IsDigit(*(ch + 2)) )
    {
      mptr = (struct Message *)NULL;
      numeric = ch;
      paramcount = MAXPARA;
      ServerStats->is_num++;
      s = ch + 3;       /* I know this is ' ' from above if */
      *s++ = '\0';      /* blow away the ' ', and point s to next part */
    }
  else
    {
      s = strchr(ch, ' ');      /* moved from above,now need it here */
      if (s)
        *s++ = '\0';

      mptr = tree_parse(ch);

      if (!mptr || !mptr->cmd)
        {
          /*
           * 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
	   *
	   * Same thing goes for remote commands. If their local
	   * server accepted it, then we should not be sending
	   * a warning message.
	   */
          if (pbuffer[0] != '\0')
            {
              if (IsPerson(from) && MyClient(from))
                sendto_one(from,
                           ":%s %d %s %s :Unknown command",
                           me.name, ERR_UNKNOWNCOMMAND,
                           from->name, ch);
              Debug((DEBUG_ERROR,"Unknown (%s) from %s",
                     ch, get_client_name(cptr, TRUE)));
            }
          ServerStats->is_unco++;
          return(-1);
        }

      paramcount = mptr->parameters;
      i = bufend - ((s) ? s : ch);
      mptr->bytes += i;

      /* Allow only 1 msg per 2 seconds
       * (on average) to prevent dumping.
       * to keep the response rate up,
       * bursts of up to 5 msgs are allowed
       * -SRB
       * Opers can send 1 msg per second, burst of ~20
       * -Taner
       */
      if ((mptr->flags & 1) && !(IsServer(cptr)))
        {
#ifdef NO_OPER_FLOOD
#ifndef TRUE_NO_OPER_FLOOD
	  /* note: both have to be defined for the real no-flood */
          if (NoFloodProtection(cptr))
            /* "randomly" (weighted) increase the since */
            cptr->since += (cptr->receiveM % 5) ? 1 : 0;
          else
#else
          if (!NoFloodProtection(cptr))
#endif
#endif
            cptr->since += (2 + i / 120);
        }
    }
  /*
  ** 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' !! */

  /* ZZZ hmmmmmmmm whats this then? */
#if 0
  if (me.user)
    para[0] = sender;
#endif

  i = 1;

  if (s)
    {
      if (paramcount > MAXPARA)
        paramcount = MAXPARA;

      for (;;)
        {
	  while(*s == ' ')	/* tabs are not considered space */
	    *s++ = '\0';

          if(!*s)
            break;

          if (*s == ':')
            {
              /*
              ** The rest is single parameter--can
              ** include blanks also.
              */
              para[i++] = s + 1;
              break;
            }
	  else
	    {
	      para[i++] = s;
              if (i > paramcount)
                {
                  break;
                }
              /* scan for end of string, either ' ' or '\0' */
              while (IsNonEOS(*s))
                s++;
	    }
        }
    }

  para[i] = NULL;
  if (mptr == (struct Message *)NULL)
    return (do_numeric(numeric, cptr, from, i, para));

  mptr->count++;

  /* patch to avoid server flooding from unregistered connects */
  /* check allow_unregistered_use flag I've set up instead of function
     comparing *yech* - Dianora */

  if (!IsRegistered(cptr) && !mptr->allow_unregistered_use )
    {
      /* if its from a possible server connection
       * ignore it.. more than likely its a header thats sneaked through
       */

      if(IsHandshake(cptr) || IsConnecting(cptr) || IsServer(cptr))
        return -1;

      sendto_one(from,
                 ":%s %d %s %s :Register first.",
                 me.name, ERR_NOTREGISTERED,
                 BadPtr(from->name) ? "*" : from->name, ch);
      return -1;
    }

  /* Silently drop the messages that can't be used in the honeypot */
  if (IsHoneypot(cptr) && !mptr->allow_honeypot)
    return -1;

  /* Again, instead of function address comparing, see if
   * this function resets idle time as given from mptr
   * if IDLE_FROM_MSG is undefined, the sense of the flag is reversed.
   * i.e. if the flag is 0, then reset idle time, otherwise don't reset it.
   *
   * - Dianora
   */

  if (IsRegisteredUser(from) && mptr->reset_idle)
    {
      /* If a local registered user, propagate anti-idle updates as needed */
      if (MyClient(from) && from->user && ((from->user->last_sent + MAX_IDLE_DESYNC) < CurrentTime))
	{
#if 0
	  /* Note the misnamed message, this indicates that they are NOT idle */
#ifdef HAVE_LONG_LONG
	  sendto_serv_butone(NULL, ":%s IDLE %s %.1lld", cptr->name, from->name, (long long)CurrentTime);
#else
	  sendto_serv_butone(NULL, ":%s IDLE %s %.1ld", cptr->name, from->name, (long)CurrentTime);
#endif
#endif
	  from->user->last_sent = CurrentTime;
	}
      from->user->last = CurrentTime;
    }

  /* don't allow other commands while a list is blocked. since we treat
     them specially with respect to sendq. */
  if ((IsDoingList(cptr)) && (*mptr->func != m_list))
      return -1;
  return (*mptr->func)(cptr, from, i, para);
}
Beispiel #16
0
/* m_sajoin() - Lamego - Wed Jul 21 20:04:48 1999
   Copied off PTlink IRCd (C) PTlink coders team.
   Coded for Sadmin by Stskeeps
   also Modified by NiQuiL ([email protected])
	parv[0] - sender
	parv[1] - nick to make join
	parv[2] - channel(s) to join
*/
DLLFUNC CMD_FUNC(m_sajoin)
{
	aClient *acptr;
	char jbuf[BUFSIZE];
	int did_anything = 0;

	if (!IsSAdmin(sptr) && !IsULine(sptr))
	{
	 sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
	 return 0;
	}

	if (parc < 3)
	{
	 sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "SAJOIN");
	 return 0;
	}

	if (!(acptr = find_person(parv[1], NULL)))
	{
		sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], parv[1]);
		return 0;
	}
	if (MyClient(acptr))
	{
		char *name, *p = NULL;
		int i, parted = 0;
	
		*jbuf = 0;

		/* Now works like m_join */
		for (i = 0, name = strtoken(&p, parv[2], ","); name; name = strtoken(&p,
		     NULL, ","))
		{
			aChannel *chptr;
			Membership *lp;

			if (strlen(name) > CHANNELLEN)
				name[CHANNELLEN] = 0;
			clean_channelname(name);
			if (*name == '0' && !atoi(name))
			{
				(void)strcpy(jbuf, "0");
				i = 1;
				parted = 1;
				continue;
			}
			if (check_channelmask(sptr, cptr, name) == -1 || *name == '0' ||
			    !IsChannelName(name))
			{
				sendto_one(sptr,
				    err_str(ERR_NOSUCHCHANNEL), me.name,
				    parv[0], name);
				continue;
			}

			chptr = get_channel(acptr, name, 0);
			if (!parted && chptr && (lp = find_membership_link(acptr->user->channel, chptr)))
			{
				sendto_one(sptr, err_str(ERR_USERONCHANNEL), me.name, parv[0], 
					   parv[1], name);
				continue;
			}
			if (*jbuf)
				(void)strlcat(jbuf, ",", sizeof jbuf);
			(void)strlncat(jbuf, name, sizeof jbuf, sizeof(jbuf) - i - 1);
			i += strlen(name) + 1;
		}
		if (!*jbuf)
			return -1;
		i = 0;
		strcpy(parv[2], jbuf);
		*jbuf = 0;
		for (name = strtoken(&p, parv[2], ","); name; name = strtoken(&p, NULL, ","))
		{
			int flags;
			aChannel *chptr;
			Membership *lp;

			if (*name == '0' && !atoi(name))
			{
				did_anything = 1;
				while ((lp = acptr->user->channel))
				{
					chptr = lp->chptr;
					sendto_channel_butserv(chptr, acptr,
					    ":%s PART %s :%s", acptr->name, chptr->chname,
					    "Left all channels");
					if (MyConnect(acptr))
						RunHook4(HOOKTYPE_LOCAL_PART, acptr, acptr, chptr,
							 "Left all channels");
					remove_user_from_channel(acptr, chptr);
				}
				sendto_serv_butone_token(acptr, acptr->name,
				    MSG_JOIN, TOK_JOIN, "0");
				strcpy(jbuf, "0");
				i = 1;
				continue;
			}
			flags = (ChannelExists(name)) ? CHFL_DEOPPED : CHFL_CHANOP;
			chptr = get_channel(acptr, name, CREATE);
			if (chptr && (lp = find_membership_link(acptr->user->channel, chptr)))
				continue;
			if ((chptr->mode.mode & MODE_ONLYSECURE) && !IsSecure(acptr))
			{
				sendnotice(sptr, "You cannot SAJOIN %s to %s because the channel is +z and the user is not connected via SSL",
					acptr->name, chptr->chname);
				continue;
			}
			join_channel(chptr, acptr, acptr, flags);
			did_anything = 1;
			if (*jbuf)
				(void)strlcat(jbuf, ",", sizeof jbuf);
			(void)strlncat(jbuf, name, sizeof jbuf, sizeof(jbuf) - i - 1);
			i += strlen(name) + 1;
		}
		
		if (did_anything)
		{
			sendnotice(acptr, "*** You were forced to join %s", jbuf);
			sendto_realops("%s used SAJOIN to make %s join %s", sptr->name, acptr->name,
				       jbuf);
			sendto_serv_butone(&me, ":%s GLOBOPS :%s used SAJOIN to make %s join %s",
					   me.name, sptr->name, acptr->name, jbuf);
			/* Logging function added by XeRXeS */
			ircd_log(LOG_SACMDS,"SAJOIN: %s used SAJOIN to make %s join %s",
				sptr->name, parv[1], jbuf);
		}
	}
	else
	{
		sendto_one(acptr, ":%s SAJOIN %s %s", parv[0],
		    parv[1], parv[2]);

		/* Logging function added by XeRXeS */
		ircd_log(LOG_SACMDS,"SAJOIN: %s used SAJOIN to make %s join %s",
			sptr->name, parv[1], parv[2]);
	}

	return 0;
}
Beispiel #17
0
/*
** m_nick
**	parv[0] = sender prefix
**	parv[1] = nickname
**  if from new client  -taz
**	parv[2] = nick password
**  if from server:
**      parv[2] = hopcount
**      parv[3] = timestamp
**      parv[4] = username
**      parv[5] = hostname
**      parv[6] = servername
**  if NICK version 1:
**      parv[7] = servicestamp
**	parv[8] = info
**  if NICK version 2:
**	parv[7] = servicestamp
**      parv[8] = umodes
**	parv[9] = virthost, * if none
**	parv[10] = info
**  if NICKIP:
**      parv[10] = ip
**      parv[11] = info
*/
DLLFUNC CMD_FUNC(m_nick)
{
	aTKline *tklban;
	int ishold;
	aClient *acptr, *serv = NULL;
	aClient *acptrs;
	char nick[NICKLEN + 2], *s;
	Membership *mp;
	time_t lastnick = (time_t) 0;
	int  differ = 1, update_watch = 1;
	unsigned char newusr = 0, removemoder = 1;
	/*
	 * If the user didn't specify a nickname, complain
	 */
	if (parc < 2)
	{
		sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN),
		    me.name, parv[0]);
		return 0;
	}

	strncpyzt(nick, parv[1], NICKLEN + 1);

	if (MyConnect(sptr) && sptr->user && !IsAnOper(sptr))
	{
		if ((sptr->user->flood.nick_c >= NICK_COUNT) && 
		    (TStime() - sptr->user->flood.nick_t < NICK_PERIOD))
		{
			/* Throttle... */
			sendto_one(sptr, err_str(ERR_NCHANGETOOFAST), me.name, sptr->name, nick,
				(int)(NICK_PERIOD - (TStime() - sptr->user->flood.nick_t)));
			return 0;
		}
	}

	/* For a local clients, do proper nickname checking via do_nick_name()
	 * and reject the nick if it returns false.
	 * For remote clients, do a quick check by using do_remote_nick_name(),
	 * if this returned false then reject and kill it. -- Syzop
	 */
	if ((IsServer(cptr) && !do_remote_nick_name(nick)) ||
	    (!IsServer(cptr) && !do_nick_name(nick)))
	{
		sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME),
		    me.name, parv[0], parv[1], "Illegal characters");

		if (IsServer(cptr))
		{
			ircstp->is_kill++;
			sendto_failops("Bad Nick: %s From: %s %s",
			    parv[1], parv[0], get_client_name(cptr, FALSE));
			sendto_one(cptr, ":%s KILL %s :%s (%s <- %s[%s])",
			    me.name, parv[1], me.name, parv[1],
			    nick, cptr->name);
			if (sptr != cptr)
			{	/* bad nick change */
				sendto_serv_butone(cptr,
				    ":%s KILL %s :%s (%s <- %s!%s@%s)",
				    me.name, parv[0], me.name,
				    get_client_name(cptr, FALSE),
				    parv[0],
				    sptr->user ? sptr->username : "",
				    sptr->user ? sptr->user->server :
				    cptr->name);
				sptr->flags |= FLAGS_KILLED;
				return exit_client(cptr, sptr, &me, "BadNick");
			}
		}
		return 0;
	}

	/* Kill quarantined opers early... */
	if (IsServer(cptr) && (sptr->from->flags & FLAGS_QUARANTINE) &&
	    (parc >= 11) && strchr(parv[8], 'o'))
	{
		ircstp->is_kill++;
		/* Send kill to uplink only, hasn't been broadcasted to the rest, anyway */
		sendto_one(cptr, ":%s KILL %s :%s (Quarantined: no global oper privileges allowed)",
			me.name, parv[1], me.name);
		sendto_realops("QUARANTINE: Oper %s on server %s killed, due to quarantine",
			parv[1], sptr->name);
		/* (nothing to exit_client or to free, since user was never added) */
		return 0;
	}

	/*
	   ** Protocol 4 doesn't send the server as prefix, so it is possible
	   ** the server doesn't exist (a lagged net.burst), in which case
	   ** we simply need to ignore the NICK. Also when we got that server
	   ** name (again) but from another direction. --Run
	 */
	/*
	   ** We should really only deal with this for msgs from servers.
	   ** -- Aeto
	 */
	if (IsServer(cptr) &&
	    (parc > 7
	    && (!(serv = (aClient *)find_server_b64_or_real(parv[6]))
	    || serv->from != cptr->from)))
	{
		sendto_realops("Cannot find server %s (%s)", parv[6],
		    backupbuf);
		return 0;
	}
	/*
	   ** Check against nick name collisions.
	   **
	   ** Put this 'if' here so that the nesting goes nicely on the screen :)
	   ** We check against server name list before determining if the nickname
	   ** is present in the nicklist (due to the way the below for loop is
	   ** constructed). -avalon
	 */
	/* I managed to f**k this up i guess --stskeeps */
	if ((acptr = find_server(nick, NULL)))
	{
		if (MyConnect(sptr))
		{
#ifdef GUEST
			if (IsUnknown(sptr))
			{
				RunHook4(HOOKTYPE_GUEST, cptr, sptr, parc, parv);
				return 0;
			}
#endif
			sendto_one(sptr, err_str(ERR_NICKNAMEINUSE), me.name,
			    BadPtr(parv[0]) ? "*" : parv[0], nick);
			return 0;	/* NICK message ignored */
		}
	}

	/*
	   ** Check for a Q-lined nickname. If we find it, and it's our
	   ** client, just reject it. -Lefler
	   ** Allow opers to use Q-lined nicknames. -Russell
	 */
	if (!stricmp("ircd", nick))
	{
		sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME), me.name,
		    BadPtr(parv[0]) ? "*" : parv[0], nick,
		    "Reserved for internal IRCd purposes");
		return 0;
	}
	if (!stricmp("irc", nick))
	{
		sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME), me.name,
		    BadPtr(parv[0]) ? "*" : parv[0], nick,
		    "Reserved for internal IRCd purposes");
		return 0;
	}
	if (MyClient(sptr)) /* local client changin nick afterwards.. */
	{
		int xx;
		spamfilter_build_user_string(spamfilter_user, nick, sptr);
		xx = dospamfilter(sptr, spamfilter_user, SPAMF_USER, NULL, 0, NULL);
		if (xx < 0)
			return xx;
	}
	if (!IsULine(sptr) && (tklban = find_qline(sptr, nick, &ishold)))
	{
		if (IsServer(sptr) && !ishold) /* server introducing new client */
		{
			acptrs =
			    (aClient *)find_server_b64_or_real(sptr->user ==
			    NULL ? (char *)parv[6] : (char *)sptr->user->
			    server);
			/* (NEW: no unregistered q:line msgs anymore during linking) */
			if (!acptrs || (acptrs->serv && acptrs->serv->flags.synced))
				sendto_snomask(SNO_QLINE, "Q:lined nick %s from %s on %s", nick,
				    (*sptr->name != 0
				    && !IsServer(sptr) ? sptr->name : "<unregistered>"),
				    acptrs ? acptrs->name : "unknown server");
		}
		
		if (IsServer(cptr) && IsPerson(sptr) && !ishold) /* remote user changing nick */
		{
			sendto_snomask(SNO_QLINE, "Q:lined nick %s from %s on %s", nick,
				sptr->name, sptr->srvptr ? sptr->srvptr->name : "<unknown>");
		}

		if (!IsServer(cptr)) /* local */
		{
			if (ishold)
			{
				sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME),
				    me.name, BadPtr(parv[0]) ? "*" : parv[0],
				    nick, tklban->reason);
				return 0;
			}
			if (!IsOper(cptr))
			{
				sptr->since += 4; /* lag them up */
				sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME),
				    me.name, BadPtr(parv[0]) ? "*" : parv[0],
				    nick, tklban->reason);
				sendto_snomask(SNO_QLINE, "Forbidding Q-lined nick %s from %s.",
				    nick, get_client_name(cptr, FALSE));
				return 0;	/* NICK message ignored */
			}
		}
	}
	/*
	   ** acptr already has result from previous find_server()
	 */
	if (acptr)
	{
		/*
		   ** We have a nickname trying to use the same name as
		   ** a server. Send out a nick collision KILL to remove
		   ** the nickname. As long as only a KILL is sent out,
		   ** there is no danger of the server being disconnected.
		   ** Ultimate way to jupiter a nick ? >;-). -avalon
		 */
		sendto_failops("Nick collision on %s(%s <- %s)",
		    sptr->name, acptr->from->name,
		    get_client_name(cptr, FALSE));
		ircstp->is_kill++;
		sendto_one(cptr, ":%s KILL %s :%s (%s <- %s)",
		    me.name, sptr->name, me.name, acptr->from->name,
		    /* NOTE: Cannot use get_client_name
		       ** twice here, it returns static
		       ** string pointer--the other info
		       ** would be lost
		     */
		    get_client_name(cptr, FALSE));
		sptr->flags |= FLAGS_KILLED;
		return exit_client(cptr, sptr, &me, "Nick/Server collision");
	}

	if (MyClient(cptr) && !IsOper(cptr))
		cptr->since += 3;	/* Nick-flood prot. -Donwulff */

	if (!(acptr = find_client(nick, NULL)))
		goto nickkilldone;	/* No collisions, all clear... */
	/*
	   ** If the older one is "non-person", the new entry is just
	   ** allowed to overwrite it. Just silently drop non-person,
	   ** and proceed with the nick. This should take care of the
	   ** "dormant nick" way of generating collisions...
	 */
	/* Moved before Lost User Field to fix some bugs... -- Barubary */
	if (IsUnknown(acptr) && MyConnect(acptr))
	{
		/* This may help - copying code below */
		if (acptr == cptr)
			return 0;
		acptr->flags |= FLAGS_KILLED;
		exit_client(NULL, acptr, &me, "Overridden");
		goto nickkilldone;
	}
	/* A sanity check in the user field... */
	if (acptr->user == NULL)
	{
		/* This is a Bad Thing */
		sendto_failops("Lost user field for %s in change from %s",
		    acptr->name, get_client_name(cptr, FALSE));
		ircstp->is_kill++;
		sendto_one(acptr, ":%s KILL %s :%s (Lost user field!)",
		    me.name, acptr->name, me.name);
		acptr->flags |= FLAGS_KILLED;
		/* Here's the previous versions' desynch.  If the old one is
		   messed up, trash the old one and accept the new one.
		   Remember - at this point there is a new nick coming in!
		   Handle appropriately. -- Barubary */
		exit_client(NULL, acptr, &me, "Lost user field");
		goto nickkilldone;
	}
	/*
	   ** If acptr == sptr, then we have a client doing a nick
	   ** change between *equivalent* nicknames as far as server
	   ** is concerned (user is changing the case of his/her
	   ** nickname or somesuch)
	 */
	if (acptr == sptr) {
		if (strcmp(acptr->name, nick) != 0)
		{
			/* Allows change of case in his/her nick */
			removemoder = 0; /* don't set the user -r */
			goto nickkilldone;	/* -- go and process change */
		} else
			/*
			 ** This is just ':old NICK old' type thing.
			 ** Just forget the whole thing here. There is
			 ** no point forwarding it to anywhere,
			 ** especially since servers prior to this
			 ** version would treat it as nick collision.
			 */
			return 0;	/* NICK Message ignored */
	}
	/*
	   ** Note: From this point forward it can be assumed that
	   ** acptr != sptr (point to different client structures).
	 */
	/*
	   ** Decide, we really have a nick collision and deal with it
	 */
	if (!IsServer(cptr))
	{
		/*
		   ** NICK is coming from local client connection. Just
		   ** send error reply and ignore the command.
		 */
#ifdef GUEST
		if (IsUnknown(sptr))
		{
			RunHook4(HOOKTYPE_GUEST, cptr, sptr, parc, parv);
			return 0;
		}
#endif
		sendto_one(sptr, err_str(ERR_NICKNAMEINUSE),
		    /* parv[0] is empty when connecting */
		    me.name, BadPtr(parv[0]) ? "*" : parv[0], nick);
		return 0;	/* NICK message ignored */
	}
	/*
	   ** NICK was coming from a server connection.
	   ** This means we have a race condition (two users signing on
	   ** at the same time), or two net fragments reconnecting with
	   ** the same nick.
	   ** The latter can happen because two different users connected
	   ** or because one and the same user switched server during a
	   ** net break.
	   ** If we have the old protocol (no TimeStamp and no user@host)
	   ** or if the TimeStamps are equal, we kill both (or only 'new'
	   ** if it was a "NICK new"). Otherwise we kill the youngest
	   ** when user@host differ, or the oldest when they are the same.
	   ** --Run
	   **
	 */
	if (IsServer(sptr))
	{
		/*
		   ** A new NICK being introduced by a neighbouring
		   ** server (e.g. message type "NICK new" received)
		 */
		if (parc > 3)
		{
			lastnick = TS2ts(parv[3]);
			if (parc > 5)
				differ = (mycmp(acptr->user->username, parv[4])
				    || mycmp(acptr->user->realhost, parv[5]));
		}
		sendto_failops("Nick collision on %s (%s %ld <- %s %ld)",
		    acptr->name, acptr->from->name, acptr->lastnick,
		    cptr->name, lastnick);
		/*
		   **    I'm putting the KILL handling here just to make it easier
		   ** to read, it's hard to follow it the way it used to be.
		   ** Basically, this is what it will do.  It will kill both
		   ** users if no timestamp is given, or they are equal.  It will
		   ** kill the user on our side if the other server is "correct"
		   ** (user@host differ and their user is older, or user@host are
		   ** the same and their user is younger), otherwise just kill the
		   ** user an reintroduce our correct user.
		   **    The old code just sat there and "hoped" the other server
		   ** would kill their user.  Not anymore.
		   **                                               -- binary
		 */
		if (!(parc > 3) || (acptr->lastnick == lastnick))
		{
			ircstp->is_kill++;
			sendto_serv_butone(NULL,
			    ":%s KILL %s :%s (Nick Collision)",
			    me.name, acptr->name, me.name);
			acptr->flags |= FLAGS_KILLED;
			(void)exit_client(NULL, acptr, &me,
			    "Nick collision with no timestamp/equal timestamps");
			return 0;	/* We killed both users, now stop the process. */
		}

		if ((differ && (acptr->lastnick > lastnick)) ||
		    (!differ && (acptr->lastnick < lastnick)) || acptr->from == cptr)	/* we missed a QUIT somewhere ? */
		{
			ircstp->is_kill++;
			sendto_serv_butone(cptr,
			    ":%s KILL %s :%s (Nick Collision)",
			    me.name, acptr->name, me.name);
			acptr->flags |= FLAGS_KILLED;
			(void)exit_client(NULL, acptr, &me, "Nick collision");
			goto nickkilldone;	/* OK, we got rid of the "wrong" user,
						   ** now we're going to add the user the
						   ** other server introduced.
						 */
		}

		if ((differ && (acptr->lastnick < lastnick)) ||
		    (!differ && (acptr->lastnick > lastnick)))
		{
			/*
			 * Introduce our "correct" user to the other server
			 */

			sendto_one(cptr, ":%s KILL %s :%s (Nick Collision)",
			    me.name, parv[1], me.name);
			send_umode(NULL, acptr, 0, SEND_UMODES, buf);
			sendto_one_nickcmd(cptr, acptr, buf);
			if (acptr->user->away)
				sendto_one(cptr, ":%s AWAY :%s", acptr->name,
				    acptr->user->away);
			send_user_joins(cptr, acptr);
			return 0;	/* Ignore the NICK */
		}
		return 0;
	}
	else
	{
		/*
		   ** A NICK change has collided (e.g. message type ":old NICK new").
		 */
		if (parc > 2)
			lastnick = TS2ts(parv[2]);
		differ = (mycmp(acptr->user->username, sptr->user->username) ||
		    mycmp(acptr->user->realhost, sptr->user->realhost));
		sendto_failops
		    ("Nick change collision from %s to %s (%s %ld <- %s %ld)",
		    sptr->name, acptr->name, acptr->from->name, acptr->lastnick,
		    sptr->from->name, lastnick);
		if (!(parc > 2) || lastnick == acptr->lastnick)
		{
			ircstp->is_kill += 2;
			sendto_serv_butone(NULL,	/* First kill the new nick. */
			    ":%s KILL %s :%s (Self Collision)",
			    me.name, acptr->name, me.name);
			sendto_serv_butone(cptr,	/* Tell my servers to kill the old */
			    ":%s KILL %s :%s (Self Collision)",
			    me.name, sptr->name, me.name);
			sptr->flags |= FLAGS_KILLED;
			acptr->flags |= FLAGS_KILLED;
			(void)exit_client(NULL, sptr, &me, "Self Collision");
			(void)exit_client(NULL, acptr, &me, "Self Collision");
			return 0;	/* Now that I killed them both, ignore the NICK */
		}
		if ((differ && (acptr->lastnick > lastnick)) ||
		    (!differ && (acptr->lastnick < lastnick)))
		{
			/* sptr (their user) won, let's kill acptr (our user) */
			ircstp->is_kill++;
			sendto_serv_butone(cptr,
			    ":%s KILL %s :%s (Nick collision: %s <- %s)",
			    me.name, acptr->name, me.name,
			    acptr->from->name, sptr->from->name);
			acptr->flags |= FLAGS_KILLED;
			(void)exit_client(NULL, acptr, &me, "Nick collision");
			goto nickkilldone;	/* their user won, introduce new nick */
		}
		if ((differ && (acptr->lastnick < lastnick)) ||
		    (!differ && (acptr->lastnick > lastnick)))
		{
			/* acptr (our user) won, let's kill sptr (their user),
			   ** and reintroduce our "correct" user
			 */
			ircstp->is_kill++;
			/* Kill the user trying to change their nick. */
			sendto_serv_butone(cptr,
			    ":%s KILL %s :%s (Nick collision: %s <- %s)",
			    me.name, sptr->name, me.name,
			    sptr->from->name, acptr->from->name);
			sptr->flags |= FLAGS_KILLED;
			(void)exit_client(NULL, sptr, &me, "Nick collision");
			/*
			 * Introduce our "correct" user to the other server
			 */
			/* Kill their user. */
			sendto_one(cptr, ":%s KILL %s :%s (Nick Collision)",
			    me.name, parv[1], me.name);
			send_umode(NULL, acptr, 0, SEND_UMODES, buf);
			sendto_one_nickcmd(cptr, acptr, buf);
			if (acptr->user->away)
				sendto_one(cptr, ":%s AWAY :%s", acptr->name,
				    acptr->user->away);

			send_user_joins(cptr, acptr);
			return 0;	/* their user lost, ignore the NICK */
		}

	}
	return 0;		/* just in case */
      nickkilldone:
	if (IsServer(sptr))
	{
		/* A server introducing a new client, change source */

		sptr = make_client(cptr, serv);
		add_client_to_list(sptr);
		if (parc > 2)
			sptr->hopcount = TS2ts(parv[2]);
		if (parc > 3)
			sptr->lastnick = TS2ts(parv[3]);
		else		/* Little bit better, as long as not all upgraded */
			sptr->lastnick = TStime();
		if (sptr->lastnick < 0)
		{
			sendto_realops
			    ("Negative timestamp recieved from %s, resetting to TStime (%s)",
			    cptr->name, backupbuf);
			sptr->lastnick = TStime();
		}
		newusr = 1;
	}
	else if (sptr->name[0] && IsPerson(sptr))
	{
		/*
		   ** If the client belongs to me, then check to see
		   ** if client is currently on any channels where it
		   ** is currently banned.  If so, do not allow the nick
		   ** change to occur.
		   ** Also set 'lastnick' to current time, if changed.
		 */
		if (MyClient(sptr))
		{
			for (mp = sptr->user->channel; mp; mp = mp->next)
			{
				if (!is_skochanop(sptr, mp->chptr) && is_banned(sptr, mp->chptr, BANCHK_NICK))
				{
					sendto_one(sptr,
					    err_str(ERR_BANNICKCHANGE),
					    me.name, parv[0],
					    mp->chptr->chname);
					return 0;
				}
				if (CHECK_TARGET_NICK_BANS && !is_skochanop(sptr, mp->chptr) && is_banned_with_nick(sptr, mp->chptr, BANCHK_NICK, nick))
				{
					sendto_one(sptr,
					    ":%s 437 %s %s :Cannot change to a nickname banned on channel",
					    me.name, parv[0],
					    mp->chptr->chname);
					return 0;
				}
				if (!IsOper(sptr) && !IsULine(sptr)
				    && mp->chptr->mode.mode & MODE_NONICKCHANGE
				    && !is_chanownprotop(sptr, mp->chptr))
				{
					sendto_one(sptr,
					    err_str(ERR_NONICKCHANGE),
					    me.name, parv[0],
					    mp->chptr->chname);
					return 0;
				}
			}

			if (TStime() - sptr->user->flood.nick_t >= NICK_PERIOD)
			{
				sptr->user->flood.nick_t = TStime();
				sptr->user->flood.nick_c = 1;
			} else
				sptr->user->flood.nick_c++;

			sendto_snomask(SNO_NICKCHANGE, "*** Notice -- %s (%s@%s) has changed his/her nickname to %s",
				sptr->name, sptr->user->username, sptr->user->realhost, nick);

			RunHook2(HOOKTYPE_LOCAL_NICKCHANGE, sptr, nick);
		} else {
			if (!IsULine(sptr))
				sendto_snomask(SNO_FNICKCHANGE, "*** Notice -- %s (%s@%s) has changed his/her nickname to %s",
					sptr->name, sptr->user->username, sptr->user->realhost, nick);

			RunHook3(HOOKTYPE_REMOTE_NICKCHANGE, cptr, sptr, nick);
		}
		/*
		 * Client just changing his/her nick. If he/she is
		 * on a channel, send note of change to all clients
		 * on that channel. Propagate notice to other servers.
		 */
		if (mycmp(parv[0], nick) ||
		    /* Next line can be removed when all upgraded  --Run */
		    (!MyClient(sptr) && parc > 2
		    && TS2ts(parv[2]) < sptr->lastnick))
			sptr->lastnick = (MyClient(sptr)
			    || parc < 3) ? TStime() : TS2ts(parv[2]);
		if (sptr->lastnick < 0)
		{
			sendto_realops("Negative timestamp (%s)", backupbuf);
			sptr->lastnick = TStime();
		}
		add_history(sptr, 1);
		sendto_common_channels(sptr, ":%s NICK :%s", parv[0], nick);
		sendto_serv_butone_token(cptr, parv[0], MSG_NICK, TOK_NICK,
		    "%s %ld", nick, sptr->lastnick);
		if (removemoder)
			sptr->umodes &= ~UMODE_REGNICK;
	}
	else if (!sptr->name[0])
	{
#ifdef NOSPOOF
		/*
		 * Client setting NICK the first time.
		 *
		 * Generate a random string for them to pong with.
		 */
		sptr->nospoof = getrandom32();

		if (PINGPONG_WARNING)
			sendto_one(sptr, ":%s NOTICE %s :*** If you are having problems"
			    " connecting due to ping timeouts, please"
			    " type /quote pong %X or /raw pong %X now.",
			    me.name, nick, sptr->nospoof, sptr->nospoof);

		sendto_one(sptr, "PING :%X", sptr->nospoof);
#endif /* NOSPOOF */
#ifdef CONTACT_EMAIL
		sendto_one(sptr,
		    ":%s NOTICE %s :*** If you need assistance with a"
		    " connection problem, please email " CONTACT_EMAIL
		    " with the name and version of the client you are"
		    " using, and the server you tried to connect to: %s",
		    me.name, nick, me.name);
#endif /* CONTACT_EMAIL */
#ifdef CONTACT_URL
		sendto_one(sptr,
		    ":%s NOTICE %s :*** If you need assistance with"
		    " connecting to this server, %s, please refer to: "
		    CONTACT_URL, me.name, nick, me.name);
#endif /* CONTACT_URL */

		/* Copy password to the passwd field if it's given after NICK
		 * - originally by taz, modified by Wizzu
		 */
		if ((parc > 2) && (strlen(parv[2]) <= PASSWDLEN)
		    && !(sptr->listener->umodes & LISTENER_JAVACLIENT))
		{
			if (sptr->passwd)
				MyFree(sptr->passwd);
			sptr->passwd = MyMalloc(strlen(parv[2]) + 1);
			(void)strcpy(sptr->passwd, parv[2]);
		}
		/* This had to be copied here to avoid problems.. */
		(void)strcpy(sptr->name, nick);
		if (sptr->user && IsNotSpoof(sptr))
		{
			/*
			   ** USER already received, now we have NICK.
			   ** *NOTE* For servers "NICK" *must* precede the
			   ** user message (giving USER before NICK is possible
			   ** only for local client connection!). register_user
			   ** may reject the client and call exit_client for it
			   ** --must test this and exit m_nick too!!!
			 */
#ifndef NOSPOOF
			if (USE_BAN_VERSION && MyConnect(sptr))
				sendto_one(sptr, ":IRC!IRC@%s PRIVMSG %s :\1VERSION\1",
					me.name, nick);
#endif
			sptr->lastnick = TStime();	/* Always local client */
			if (register_user(cptr, sptr, nick,
			    sptr->user->username, NULL, NULL, NULL) == FLUSH_BUFFER)
				return FLUSH_BUFFER;
			strcpy(nick, sptr->name); /* don't ask, but I need this. do not remove! -- Syzop */
			update_watch = 0;
			newusr = 1;
		}
	}
	/*
	 *  Finally set new nick name.
	 */
	if (update_watch && sptr->name[0])
	{
		(void)del_from_client_hash_table(sptr->name, sptr);
		if (IsPerson(sptr))
			hash_check_watch(sptr, RPL_LOGOFF);
	}
	(void)strcpy(sptr->name, nick);
	(void)add_to_client_hash_table(nick, sptr);
	if (IsServer(cptr) && parc > 7)
	{
		parv[3] = nick;
		do_cmd(cptr, sptr, "USER", parc - 3, &parv[3]);
		if (GotNetInfo(cptr) && !IsULine(sptr))
			sendto_fconnectnotice(sptr->name, sptr->user, sptr, 0, NULL);
	}
	else if (IsPerson(sptr) && update_watch)
		hash_check_watch(sptr, RPL_LOGON);

#ifdef NEWCHFLOODPROT
	if (sptr->user && !newusr && !IsULine(sptr))
	{
		for (mp = sptr->user->channel; mp; mp = mp->next)
		{
			aChannel *chptr = mp->chptr;
			if (chptr && !(mp->flags & (CHFL_CHANOP|CHFL_VOICE|CHFL_CHANOWNER|CHFL_HALFOP|CHFL_CHANPROT)) &&
			    chptr->mode.floodprot && do_chanflood(chptr->mode.floodprot, FLD_NICK) && MyClient(sptr))
			{
				do_chanflood_action(chptr, FLD_NICK, "nick");
			}
		}	
	}
#endif
	if (newusr && !MyClient(sptr) && IsPerson(sptr))
	{
		RunHook(HOOKTYPE_REMOTE_CONNECT, sptr);
	}

	return 0;
}
Beispiel #18
0
/*
 * m_ungline
 * Remove a local user@host ban.
 *
 *     parv[0] = sender
 *     parv[1] = user@host mask
 */
int m_ungline(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
    char hbuf[512];
    char *user;
    char *host;
    struct userBan *ban;
    struct userBan *existing;

    if (!IsPrivileged(sptr))
    {
        sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
        return 0;
    }

    if (parc < 2)
    {
        sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0],
                   "UNGline");
        return 0;
    }

    if ((host = strchr(parv[1], '@')))
    {
        *host++ = 0;
        user = parv[1];
    }
    else
    {
        user = "******";
        host = parv[1];
    }

    if (!(ban = make_hostbased_ban(user, host)))
    {
        sendto_one(sptr, ":%s NOTICE %s :UNGline: No such ban %s@%s", me.name,
                   parv[0], user, host);
        return 0;
    }

    ban->flags |= UBAN_GLINE;
    existing = find_userban_exact(ban, UBAN_GLINE);
    host = get_userban_host(ban, hbuf, sizeof(hbuf));
    userban_free(ban);

    if (!existing)
    {
        sendto_one(sptr, ":%s NOTICE %s :UNGLINE: No such ban %s@%s", me.name,
                   parv[0], user, host);
        return 0;
    }

    if (existing->flags & UBAN_CONF)
    {
        sendto_one(sptr, ":%s NOTICE %s :UNGLINE: %s@%s is specified in the"
                   " configuration file and cannot be removed online", me.name,
                   parv[0], user, host);
        return 0;
    }

    remove_userban(existing);
    glinestore_remove(existing);
    userban_free(existing);

    sendto_ops("%s has removed the G-Line for: [%s@%s]", sptr->name, user, host);
    sendto_serv_butone(MyConnect(sptr) ? NULL : cptr, ":%s UNGLINE %s@%s", sptr->name, user, host);
    return 0;
}
Beispiel #19
0
int  check_for_chan_flood(aClient *cptr, aClient *sptr, aChannel *chptr)
{
	Membership *lp;
	MembershipL *lp2;
	int c_limit, t_limit, banthem;

	if (!MyClient(sptr))
		return 0;
	if (IsOper(sptr) || IsULine(sptr))
		return 0;
	if (is_skochanop(sptr, chptr))
		return 0;

	if (!(lp = find_membership_link(sptr->user->channel, chptr)))
		return 0;

	lp2 = (MembershipL *) lp;

#ifdef NEWCHFLOODPROT
	if (!chptr->mode.floodprot || !chptr->mode.floodprot->l[FLD_TEXT])
		return 0;
	c_limit = chptr->mode.floodprot->l[FLD_TEXT];
	t_limit = chptr->mode.floodprot->per;
	banthem = (chptr->mode.floodprot->a[FLD_TEXT] == 'b') ? 1 : 0;
#else
	if ((chptr->mode.msgs < 1) || (chptr->mode.per < 1))
		return 0;
	c_limit = chptr->mode.msgs;
	t_limit = chptr->mode.per;
	banthem = chptr->mode.kmode;
#endif
	/* if current - firstmsgtime >= mode.per, then reset,
	 * if nummsg > mode.msgs then kick/ban
	 */
	Debug((DEBUG_ERROR, "Checking for flood +f: firstmsg=%d (%ds ago), new nmsgs: %d, limit is: %d:%d",
		lp2->flood.firstmsg, TStime() - lp2->flood.firstmsg, lp2->flood.nmsg + 1,
		c_limit, t_limit));
	if ((TStime() - lp2->flood.firstmsg) >= t_limit)
	{
		/* reset */
		lp2->flood.firstmsg = TStime();
		lp2->flood.nmsg = 1;
		return 0; /* forget about it.. */
	}

	/* increase msgs */
	lp2->flood.nmsg++;

	if ((lp2->flood.nmsg) > c_limit)
	{
		char comment[1024], mask[1024];
		ircsprintf(comment,
		    "Flooding (Limit is %i lines per %i seconds)",
		    c_limit, t_limit);
		if (banthem)
		{		/* ban. */
			ircsprintf(mask, "*!*@%s", GetHost(sptr));
			add_listmode(&chptr->banlist, &me, chptr, mask);
			sendto_serv_butone(&me, ":%s MODE %s +b %s 0",
			    me.name, chptr->chname, mask);
			sendto_channel_butserv(chptr, &me,
			    ":%s MODE %s +b %s", me.name, chptr->chname, mask);
		}
		sendto_channel_butserv(chptr, &me,
		    ":%s KICK %s %s :%s", me.name,
		    chptr->chname, sptr->name, comment);
		sendto_serv_butone_token(cptr, me.name,
			MSG_KICK, TOK_KICK, 
			"%s %s :%s",
		   chptr->chname, sptr->name, comment);
		remove_user_from_channel(sptr, chptr);
		return 1;
	}
	return 0;
}
Beispiel #20
0
/*
** m_kill
**	parv[0] = sender prefix
**	parv[1] = kill victim(s) - comma separated list
**	parv[2] = kill path
*/
DLLFUNC int  m_kill(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
	aClient *acptr;
	anUser *auser;
	char inpath[HOSTLEN * 2 + USERLEN + 5];
	char *oinpath = get_client_name(cptr, FALSE);
	char *user, *path, *killer, *nick, *p, *s;
	int  chasing = 0, kcount = 0;



	if (parc < 2 || *parv[1] == '\0')
	{
		sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
		    me.name, parv[0], "KILL");
		return 0;
	}

	user = parv[1];
	path = parv[2];		/* Either defined or NULL (parc >= 2!!) */

	strlcpy(inpath, oinpath, sizeof inpath);

#ifndef ROXnet
	if (IsServer(cptr) && (s = (char *)index(inpath, '.')) != NULL)
		*s = '\0';	/* Truncate at first "." */
#endif

	if (!IsPrivileged(cptr))
	{
		sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
		return 0;
	}
	if (IsAnOper(cptr))
	{
		if (BadPtr(path))
		{
			sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
			    me.name, parv[0], "KILL");
			return 0;
		}
		if (strlen(path) > (size_t)TOPICLEN)
			path[TOPICLEN] = '\0';
	}

	if (MyClient(sptr))
		user = (char *)canonize(user);

	for (p = NULL, nick = strtoken(&p, user, ","); nick;
	    nick = strtoken(&p, NULL, ","))
	{

		chasing = 0;

		if (!(acptr = find_client(nick, NULL)))
		{
			/*
			   ** If the user has recently changed nick, we automaticly
			   ** rewrite the KILL for this new nickname--this keeps
			   ** servers in synch when nick change and kill collide
			 */
			if (!(acptr =
			    get_history(nick, (long)KILLCHASETIMELIMIT)))
			{
				sendto_one(sptr, err_str(ERR_NOSUCHNICK),
				    me.name, parv[0], nick);
				continue;
			}
			sendto_one(sptr,
			    ":%s %s %s :*** KILL changed from %s to %s",
			    me.name, IsWebTV(sptr) ? "PRIVMSG" : "NOTICE", parv[0], nick, acptr->name);
			chasing = 1;
		}
		if ((!MyConnect(acptr) && MyClient(cptr) && !OPCanGKill(cptr))
		    || (MyConnect(acptr) && MyClient(cptr)
		    && !OPCanLKill(cptr)))
		{
			sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name,
			    parv[0]);
			continue;
		}
		if (IsServer(acptr) || IsMe(acptr))
		{
			sendto_one(sptr, err_str(ERR_CANTKILLSERVER),
			    me.name, parv[0]);
			continue;
		}
		if (!IsPerson(acptr))
		{
			/* Nick exists but user is not registered yet: IOTW "doesn't exist". -- Syzop */
			sendto_one(sptr, err_str(ERR_NOSUCHNICK),
			    me.name, parv[0], nick);
			continue;
		}

		if (IsServices(acptr) && !(IsNetAdmin(sptr) || IsULine(sptr)))
		{
			sendto_one(sptr, err_str(ERR_KILLDENY), me.name,
			    parv[0], parv[1]);
			return 0;
		}
		/* From here on, the kill is probably going to be successful. */

		kcount++;

		if (!IsServer(sptr) && (kcount > MAXKILLS))
		{
			sendto_one(sptr,
			    ":%s %s %s :*** Too many targets, kill list was truncated. Maximum is %d.",
			    me.name, IsWebTV(sptr) ? "PRIVMSG" : "NOTICE", parv[0], MAXKILLS);
			break;
		}
		if (!IsServer(cptr))
		{
			/*
			   ** The kill originates from this server, initialize path.
			   ** (In which case the 'path' may contain user suplied
			   ** explanation ...or some nasty comment, sigh... >;-)
			   **
			   **   ...!operhost!oper
			   **   ...!operhost!oper (comment)
			 */
			strlcpy(inpath, GetHost(cptr), sizeof inpath);
			if (kcount < 2) {	/* Only check the path the first time
					   around, or it gets appended to itself. */
				if (!BadPtr(path))
				{
					(void)ircsprintf(buf, "%s%s (%s)",
					    cptr->name,
					    IsOper(sptr) ? "" : "(L)", path);
					path = buf;
				}
				else
					path = cptr->name;
			}
		}
		else if (BadPtr(path))
			path = "*no-path*";	/* Bogus server sending??? */
		/*
		   ** Notify all *local* opers about the KILL (this includes the one
		   ** originating the kill, if from this server--the special numeric
		   ** reply message is not generated anymore).
		   **
		   ** Note: "acptr->name" is used instead of "user" because we may
		   **    have changed the target because of the nickname change.
		 */

		auser = acptr->user;

		sendto_snomask_normal(SNO_KILLS,
		    "*** Notice -- Received KILL message for %s!%s@%s from %s Path: %s!%s",
		    acptr->name, auser->username,
		    IsHidden(acptr) ? auser->virthost : auser->realhost,
		    parv[0], inpath, path);
#if defined(USE_SYSLOG) && defined(SYSLOG_KILL)
		if (IsOper(sptr))
			syslog(LOG_DEBUG, "KILL From %s For %s Path %s!%s",
			    parv[0], acptr->name, inpath, path);
#endif
		/*
		 * By otherguy
		*/
                ircd_log
                    (LOG_KILL, "KILL (%s) by  %s(%s!%s)",
                           make_nick_user_host
                     (acptr->name, acptr->user->username, GetHost(acptr)),
                            parv[0],
                            inpath,
                            path);
		/*
		   ** And pass on the message to other servers. Note, that if KILL
		   ** was changed, the message has to be sent to all links, also
		   ** back.
		   ** Suicide kills are NOT passed on --SRB
		 */
		if (!MyConnect(acptr) || !MyConnect(sptr) || !IsAnOper(sptr))
		{
			sendto_serv_butone(cptr, ":%s KILL %s :%s!%s",
			    parv[0], acptr->name, inpath, path);
			if (chasing && IsServer(cptr))
				sendto_one(cptr, ":%s KILL %s :%s!%s",
				    me.name, acptr->name, inpath, path);
			acptr->flags |= FLAGS_KILLED;
		}

		/*
		   ** Tell the victim she/he has been zapped, but *only* if
		   ** the victim is on current server--no sense in sending the
		   ** notification chasing the above kill, it won't get far
		   ** anyway (as this user don't exist there any more either)
		 */
		if (MyConnect(acptr))
			sendto_prefix_one(acptr, sptr, ":%s KILL %s :%s!%s",
			    parv[0], acptr->name, inpath, path);
		/*
		   ** Set FLAGS_KILLED. This prevents exit_one_client from sending
		   ** the unnecessary QUIT for this. (This flag should never be
		   ** set in any other place)
		 */
		if (MyConnect(acptr) && MyConnect(sptr) && IsAnOper(sptr))

			(void)ircsprintf(buf2, "[%s] Local kill by %s (%s)",
			    me.name, sptr->name,
			    BadPtr(parv[2]) ? sptr->name : parv[2]);
		else
		{
			if ((killer = index(path, ' ')))
			{
				while ((killer >= path) && *killer && *killer != '!')
					killer--;
				if (!*killer)
					killer = path;
				else
					killer++;
			}
			else
				killer = path;
			(void)ircsprintf(buf2, "Killed (%s)", killer);
		}

		if (MyClient(sptr))
			RunHook3(HOOKTYPE_LOCAL_KILL, sptr, acptr, parv[2]);
		if (exit_client(cptr, acptr, sptr, buf2) == FLUSH_BUFFER)
			return FLUSH_BUFFER;
	}
	return 0;
}
Beispiel #21
0
/*
 * m_gline
 * Add a local user@host ban.
 *
 *    parv[0] = sender
 *    parv[1] = duration (optional)
 *    parv[2] = nick or user@host mask
 *    parv[3] = reason (optional)
 */
int
m_gline(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
    char rbuf[512];
    char *target;
    char *user;
    char *host;
    char *reason = "<no reason>";
    int tgminutes = DEFAULT_GLINE_TIME;
    int tgseconds;
    long lval;
    struct userBan *ban;
    struct userBan *existing;

    if (!IsPrivileged(sptr))
    {
        sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
        return 0;
    }

    if (parc < 2)
    {
        sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0],
                   "gline");
        return 0;
    }

    lval = strtol(parv[1], &target, 10);
    if (*target != 0)
    {
        target = parv[1];
        if (parc > 2)
            reason = parv[2];
    }
    else
    {
        /* valid expiration time */
        tgminutes = lval;

        if (parc < 3)
        {
            sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0],
                       "Gline");
            return 0;
        }

        target = parv[2];

        if (parc > 3)
            reason = parv[3];
    }

    /* negative times, or times greater than a year, are permanent */
    if (tgminutes < 0 || tgminutes > (365 * 24 * 60))
        tgminutes = 0;
    tgseconds = tgminutes * 60;

    if ((host = strchr(target, '@')))
    {
        *host++ = 0;
        user = target;
    }
    else
    {
        user = "******";
        host = target;
    }

    if (!match(user, "akjhfkahfasfjd") &&
        !match(host, "ldksjfl.kss...kdjfd.jfklsjf"))
    {
        sendto_one(sptr, ":%s NOTICE %s :gline: %s@%s mask is too wide",
                   me.name, parv[0], user, host);
        return 0;
    }

    /*
     * XXX: nick target support to be re-added
     */

    if (!(ban = make_hostbased_ban(user, host)))
    {
        sendto_one(sptr, ":%s NOTICE %s :gline: invalid ban mask %s@%s",
                   me.name, parv[0], user, host);
        return 0;
    }

    ban->flags |= UBAN_GLINE;

    /* only looks for duplicate glines, not akills */
    if ((existing = find_userban_exact(ban, UBAN_GLINE)))
    {
        if (!IsServer(sptr))
        sendto_one(sptr, ":%s NOTICE %s :gline: %s@%s is already %s: %s",
                   me.name, parv[0], user, host, NETWORK_GLINE_NAME,
                   existing->reason ? existing->reason : "<no reason>");
        userban_free(ban);
        return 0;
    }

    if (MyClient(sptr) && user_match_ban(sptr, ban))
    {
        sendto_one(sptr, ":%s NOTICE %s :gline: %s@%s matches you, rejected",
                   me.name, parv[0], user, host);
        userban_free(ban);
        return 0;
    }

    if (!IsServer(sptr))
        ircsnprintf(rbuf, sizeof(rbuf), "%s (%s)", reason, smalldate(0));
    else
        ircsnprintf(rbuf, sizeof(rbuf), "%s", reason);

    ban->reason = MyMalloc(strlen(rbuf) + 1);
    strcpy(ban->reason, rbuf);

    if (tgseconds)
    {
        ban->flags |= UBAN_TEMPORARY;
        ban->timeset = NOW;
        ban->duration = tgseconds;
    }

    add_hostbased_userban(ban);

    if (!tgminutes || tgminutes >= GLINE_MIN_STORE_TIME)
        glinestore_add(ban);

    userban_sweep(ban);

    host = get_userban_host(ban, rbuf, sizeof(rbuf));

    sendto_serv_butone(MyConnect(sptr) ? NULL : cptr, ":%s GLINE %l %s@%s :%s", sptr->name, tgseconds, user, host, reason);

    if (tgminutes)

        sendto_realops("%s added temporary %d min. "NETWORK_GLINE_NAME" for"
                       " [%s@%s] [%s]", parv[0], tgminutes, user, host,
                       reason);
    else

        sendto_realops("%s added "NETWORK_GLINE_NAME" for [%s@%s] [%s]", parv[0],
                       user, host, reason);

    return 0;
}
Beispiel #22
0
/*
 *  m_server
 *       parv[0] = sender prefix
 *       parv[1] = servername
 *       parv[2] = serverinfo/hopcount
 *       parv[3] = serverinfo
 */
int m_server(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
    int     i;
    char        info[REALLEN + 1], *host;
    aClient    *acptr, *bcptr;
    aConnect   *aconn;
    int         hop;
    char        nbuf[HOSTLEN * 2 + USERLEN + 5]; /* same size as in s_misc.c */

    info[0] = '\0';

    if (parc < 2 || *parv[1] == '\0')
    {
        sendto_one(cptr, "ERROR :No servername");
        return 0;
    }

    hop = 0;
    host = parv[1];
    if (parc > 3 && atoi(parv[2]))
    {
        hop = atoi(parv[2]);
        strncpyzt(info, parv[3], REALLEN + 1);
    }
    else if (parc > 2)
    {
        strncpyzt(info, parv[2], REALLEN + 1);
        if ((parc > 3) && ((i = strlen(info)) < (REALLEN - 2)))
        {
            strcat(info, " ");
            strncat(info, parv[3], REALLEN - i - 2);
            info[REALLEN] = '\0';
        }
    }
    /*
     * July 5, 1997
     * Rewritten to throw away server cruft from users,
     * combined the hostname validity test with cleanup of host name,
     * so a cleaned up hostname can be returned as an error if
     * necessary. - Dianora
     */

    /* yes, the if(strlen) below is really needed!! */
    if (strlen(host) > HOSTLEN)
        host[HOSTLEN] = '\0';

    if (IsPerson(cptr))
    {
        /* A local link that has been identified as a USER tries
         * something fishy... ;-)
         */
        sendto_one(cptr, err_str(ERR_UNKNOWNCOMMAND),
                   me.name, parv[0], "SERVER");

        return 0;
    }
    else
        /* hostile servername check */
    {
        /*
         * Lets check for bogus names and clean them up we don't bother
         * cleaning up ones from users, becasuse we will never see them
         * any more - Dianora
         */

        int bogus_server = 0;
        int found_dot = 0;
        char clean_host[(2 * HOSTLEN) + 1];
        char *s;
        char *d;
        int n;

        s = host;
        d = clean_host;
        n = (2 * HOSTLEN) - 2;

        while (*s && n > 0)
        {
            if ((unsigned char) *s < (unsigned char) ' ')
                /* Is it a control character? */
            {
                bogus_server = 1;
                *d++ = '^';
                *d++ = (char) ((unsigned char) *s + 0x40);
                /* turn it into a printable */
                n -= 2;
            }
            else if ((unsigned char) *s > (unsigned char) '~')
            {
                bogus_server = 1;
                *d++ = '.';
                n--;
            }
            else
            {
                if (*s == '.')
                    found_dot = 1;
                *d++ = *s;
                n--;
            }
            s++;
        }
        *d = '\0';

        if ((!found_dot) || bogus_server)
        {
            sendto_one(sptr, "ERROR :Bogus server name (%s)",
                       clean_host);
            return exit_client(cptr, cptr, cptr, "Bogus server name");
        }
    }

    /* new connection */
    if (IsUnknown(cptr) || IsHandshake(cptr))
    {
        strncpyzt(cptr->name, host, sizeof(cptr->name));
        strncpyzt(cptr->info, info[0] ? info : me.name, REALLEN + 1);
        cptr->hopcount = hop;

        switch (check_server_init(cptr))
        {
            case 0:
                return m_server_estab(cptr);
            case 1:
                sendto_ops("Access check for %s in progress",
                           get_client_name(cptr, HIDEME));
                return 1;
            default:
                ircstp->is_ref++;
                sendto_ops_lev(ADMIN_LEV, "Link %s dropped, no Connect block",
                           get_client_name(cptr, TRUE));
                return exit_client(cptr, cptr, cptr, "No Connect block");
        }
    }
    
    /* already linked server */
    if (!IsServer(cptr))
        return 0;

    if ((acptr = find_name(host, NULL)))
    {
        /*
         * * This link is trying feed me a server that I already have
         * access through another path -- multiple paths not accepted
         * currently, kill this link immediately!!
         *
         * Rather than KILL the link which introduced it, KILL the
         * youngest of the two links. -avalon
         */

        bcptr = (cptr->firsttime > acptr->from->firsttime) ? cptr :
            acptr->from;
        sendto_one(bcptr, "ERROR :Server %s already exists", host);
        if (bcptr == cptr)
        {
            /* Don't complain for servers that are juped */
            /* (don't complain if the server that already exists is U: lined,
                unless I actually have a .conf U: line for it */
            if(!IsULine(acptr) || find_aUserver(acptr->name))
            {
                sendto_gnotice("from %s: Link %s cancelled, server %s already "
                               "exists", me.name, get_client_name(bcptr, HIDEME),
                               host);
                sendto_serv_butone(bcptr, ":%s GNOTICE :Link %s cancelled, "
                                   "server %s already exists", me.name,
                                   get_client_name(bcptr, HIDEME), host);
            }
            return exit_client(bcptr, bcptr, &me, "Server Exists");
        }
        /* inform all those who care (set +n) -epi */
        strcpy(nbuf, get_client_name(bcptr, HIDEME));
        sendto_gnotice("from %s: Link %s cancelled, server %s reintroduced "
                       "by %s", me.name, nbuf, host,
                       get_client_name(cptr, HIDEME));
        sendto_serv_butone(bcptr, ":%s GNOTICE :Link %s cancelled, server %s "
                           "reintroduced by %s", me.name, nbuf, host,
                           get_client_name(cptr, HIDEME));
        exit_client(bcptr, bcptr, &me, "Server Exists");
    }
    /*
     * The following if statement would be nice to remove since user
     * nicks never have '.' in them and servers must always have '.' in
     * them. There should never be a server/nick name collision, but it
     * is possible a capricious server admin could deliberately do
     * something strange.
     *
     * -Dianora
     */

    if ((acptr = find_client(host, NULL)) && acptr != cptr)
    {
        /*
         * * Server trying to use the same name as a person. Would
         * cause a fair bit of confusion. Enough to make it hellish for
         * a while and servers to send stuff to the wrong place.
         */
        sendto_one(cptr, "ERROR :Nickname %s already exists!", host);
        strcpy(nbuf, get_client_name(cptr, HIDEME));
        sendto_gnotice("from %s: Link %s cancelled, servername/nick collision",
                       me.name, nbuf);
        sendto_serv_butone(cptr, ":%s GNOTICE :Link %s cancelled, "
                           "servername/nick collision", me.name, nbuf);
        return exit_client(cptr, cptr, cptr, "Nick as Server");
    }

    if (IsServer(cptr))
    {
        /*
         * * Server is informing about a new server behind this link.
         * Create REMOTE server structure, add it to list and propagate
         * word to my other server links...
         */
        if (parc == 1 || info[0] == '\0')
        {
            sendto_one(cptr, "ERROR :No server info specified for %s", host);
            return 0;
        }
        /*
         * * See if the newly found server is behind a guaranteed leaf
         * (L-line). If so, close the link.
         *
         * Depreciated.  Kinda redundant with Hlines. -epi
         */
        if (!(cptr->serv->aconn->flags & CONN_HUB))
        {
            aconn = cptr->serv->aconn;
            sendto_gnotice("from %s: Non-Hub link %s introduced %s",
                           me.name, get_client_name(cptr, HIDEME), host);
            sendto_serv_butone(cptr,":%s GNOTICE :Non-Hub link %s introduced "
                               "%s", me.name, get_client_name(cptr, HIDEME),
                               host);
            sendto_one(cptr, "ERROR :You're not a hub (introducing %s)",
                       host);
            return exit_client(cptr, cptr, cptr, "Too many servers");
        }

        acptr = make_client(cptr, sptr);
        make_server(acptr);
        acptr->hopcount = hop;
        strncpyzt(acptr->name, host, sizeof(acptr->name));
        strncpyzt(acptr->info, info, REALLEN + 1);
        acptr->serv->up = find_or_add(parv[0]);

        fakelinkserver_update(acptr->name, acptr->info);
        SetServer(acptr);

        /*
         * if this server is behind a U-lined server, make it U-lined as
         * well. - lucas
         */

        if (IsULine(sptr) || find_aUserver(acptr->name))
        {
            acptr->flags |= FLAGS_ULINE;
            sendto_realops_lev(DEBUG_LEV, "%s introducing super server %s",
                               cptr->name, acptr->name);
        }

        Count.server++;

        add_client_to_list(acptr);
        add_to_client_hash_table(acptr->name, acptr);
        /*
         * Old sendto_serv_but_one() call removed because we now need
         * to send different names to different servers (domain name matching)
         */
        for (i = 0; i <= highest_fd; i++)
        {
            if (!(bcptr = local[i]) || !IsServer(bcptr) || bcptr == cptr ||
                IsMe(bcptr))
                continue;
            if (!(aconn = bcptr->serv->aconn))
            {
                sendto_gnotice("from %s: Lost Connect block for %s on %s."
                               " Closing", me.name,
                               get_client_name(cptr, HIDEME), host);
                sendto_serv_butone(cptr, ":%s GNOTICE :Lost Connect block for"
                                   " %s on %s. Closing", me.name,
                                   get_client_name(cptr, HIDEME), host);
                return exit_client(cptr, cptr, cptr, "Lost Connect block");
            }
            if (match(my_name_for_link(me.name, aconn), acptr->name) == 0)
                continue;
            sendto_one(bcptr, ":%s SERVER %s %d :%s",
                       parv[0], acptr->name, hop + 1, acptr->info);
        }
        return 0;
    }

    return 0;
}
Beispiel #23
0
static int
m_server_estab(aClient *cptr)
{
    aConnect *aconn;
    aClient *acptr;

    char       *inpath, *host, *s, *encr;

    inpath = get_client_name(cptr, HIDEME);  /* "refresh" inpath with host  */
    host = cptr->name;

    if (!(aconn = cptr->serv->aconn))
    {
        ircstp->is_ref++;
        sendto_one(cptr, "ERROR :Lost Connect block");
        sendto_ops_lev(ADMIN_LEV, "Lost Connect block for server %s",
                           get_client_name(cptr, TRUE));
        return exit_client(cptr, cptr, cptr, "Lost Connect block");
    }

    encr = cptr->passwd;
    if (*aconn->apasswd && !StrEq(aconn->apasswd, encr))
    {
        ircstp->is_ref++;
        sendto_one(cptr, "ERROR :Wrong link password");
        sendto_ops("Link %s dropped, wrong password", inpath);
        return exit_client(cptr, cptr, cptr, "Bad Password");
    }
    memset(cptr->passwd, '\0', sizeof(cptr->passwd));

    if ((acptr = find_client(host, NULL)))
    {
        /* Don't complain about juped servers */
        if(!IsULine(acptr) || find_aUserver(acptr->name))
        {
            sendto_gnotice("from %s: Link %s dropped, server already exists",
                           me.name, inpath);
            sendto_serv_butone(cptr, ":%s GNOTICE :Link %s dropped, server already"
                               " exists", me.name, inpath);
        }
        return exit_client(cptr, cptr, cptr, "Server Exists");
    }

    if(!(confopts & FLAGS_HUB))
    {
        int i;
        for (i = 0; i <= highest_fd; i++)
            if (local[i] && IsServer(local[i]))
            {
                ircstp->is_ref++;
                sendto_one(cptr, "ERROR :I'm a leaf not a hub");
                return exit_client(cptr, cptr, cptr, "I'm a leaf");
            }
    }

    /* aconf->port is a CAPAB field, kind-of. kludge. mm, mm. */
    /* no longer! this should still get better though */
    if((aconn->flags & CONN_ZIP))
        SetZipCapable(cptr);
    if((aconn->flags & CONN_DKEY))
        SetWantDKEY(cptr);
    if (IsUnknown(cptr))
    {
        if (aconn->cpasswd[0])
            sendto_one(cptr, "PASS %s :TS", aconn->cpasswd);

        /* Pass my info to the new server */

#ifdef HAVE_ENCRYPTION_ON
        if(!WantDKEY(cptr))
            sendto_one(cptr, "CAPAB SSJOIN NOQUIT BURST UNCONNECT ZIP "
                       "NICKIP NICKIPSTR TSMODE");
        else
            sendto_one(cptr, "CAPAB SSJOIN NOQUIT BURST UNCONNECT DKEY "
                       "ZIP NICKIP NICKIPSTR TSMODE");
#else
        sendto_one(cptr, "CAPAB SSJOIN NOQUIT BURST UNCONNECT ZIP NICKIP NICKIPSTR TSMODE");
#endif

        sendto_one(cptr, "SERVER %s 1 :%s",
                   my_name_for_link(me.name, aconn),
                   (me.info[0]) ? (me.info) : "IRCers United");
    }
    else 
    {
        s = (char *) strchr(aconn->host, '@');
        *s = '\0';      /* should never be NULL -- wanna bet? -Dianora */

        Debug((DEBUG_INFO, "Check Usernames [%s]vs[%s]", aconn->host,
               cptr->username));
        if (match(aconn->host, cptr->username))
        {
            *s = '@';
            ircstp->is_ref++;
            sendto_ops("Username mismatch [%s]v[%s] : %s",
                       aconn->host, cptr->username,
                       get_client_name(cptr, HIDEME));
            sendto_one(cptr, "ERROR :No Username Match");
            return exit_client(cptr, cptr, cptr, "Bad User");
        }
        *s = '@';
    }

    /* send routing notice, this should never happen anymore */
    if (!DoesTS(cptr))
    {
        sendto_gnotice("from %s: Warning: %s linked, non-TS server",
                       me.name, get_client_name(cptr, HIDEME));
        sendto_serv_butone(cptr,
                           ":%s GNOTICE :Warning: %s linked, non-TS server",
                           me.name, get_client_name(cptr, HIDEME));
    }

    sendto_one(cptr, "SVINFO %d %d 0 :%ld", TS_CURRENT, TS_MIN,
               (ts_val) timeofday);

    /* sendto one(cptr, "CAPAB ...."); moved to after PASS but before SERVER
     * now in two places.. up above and in s_bsd.c. - lucas
     * This is to make sure we pass on our capabilities before we establish
     * a server connection
     */

    /*
     * *WARNING*
     *   In the following code in place of plain
     * server's name we send what is returned by
     * get_client_name which may add the "sockhost" after the name.
     * It's *very* *important* that there is a SPACE between
     * the name and sockhost (if present). The receiving server
     * will start the information field from this first blank and
     * thus puts the sockhost into info. ...a bit tricky, but
     * you have been warned, besides code is more neat this way...
     * --msa
     */

    cptr->serv->up = me.name;
    cptr->serv->aconn = aconn;

    throttle_remove(cipntoa(cptr));

#ifdef HAVE_ENCRYPTION_ON
    if(!CanDoDKEY(cptr) || !WantDKEY(cptr))
        return do_server_estab(cptr);
    else
    {
        SetNegoServer(cptr); /* VERY IMPORTANT THAT THIS IS HERE */
        sendto_one(cptr, "DKEY START");
    }
#else
    return do_server_estab(cptr);
#endif

    return 0;
}
Beispiel #24
0
int
m_scan_idle(struct Client *cptr, struct Client *sptr, int parc, char *parv[], char *varparv[])
{
	struct Client *ptr, *target = NULL;
	char *eptr, buffer[321];
	int idle_time, check_time, len = 0, count = 0;

	if(MyClient(sptr) && !HasUmode(sptr, UMODE_USER_AUSPEX))
	{
		if(SeesOperMessages(sptr))
			sendto_one(sptr,":%s NOTICE %s :You have no a umode", me.name, parv[0]);
		else
			sendto_one(sptr, form_str(ERR_NOPRIVILEGES), me.name, parv[0]);
		return 0;
	}

	if(parc < 3)
	{
		if (!IsServer(sptr))
			sendto_one(sptr, form_str(ERR_NEEDMOREPARAMS),
					me.name, parv[0], "SCAN IDLE");
		return 0;
	}

	idle_time = strtoul(parv[2], &eptr, 10);
	if(eptr == parv[2])
		return 0;
	/* Store the timestamp which last_sent should be >= to save time */
	check_time = CurrentTime - idle_time;

	/* If the query is for another server, pass it on and return. */
	if(parc > 3)
	{
		if(MyClient(sptr) && !HasUmode(sptr, UMODE_REMOTEINFO))
		{
			if(SeesOperMessages(sptr))
				sendto_one(sptr,":%s NOTICE %s :You have no S umode(cannot send remote)", me.name, parv[0]);
			else
				sendto_one(sptr, form_str(ERR_NOPRIVILEGES), me.name, parv[0]);
			return 0;
		}

		if(!irccmp(parv[3], "GLOBAL") || !irccmp(parv[3], "*"))
			sendto_serv_butone(cptr, ":%s SCAN IDLE %d *", parv[0], idle_time);
		else if((target = find_server(parv[3])) == NULL) {
			sendto_one(sptr, form_str(ERR_NOSUCHSERVER),
					me.name, parv[0], parv[3]);
			return 0;
		}else if(!IsMe(target)) { /* But only if the query is not on us... */

			sendto_prefix_one(target, sptr, ":%s SCAN IDLE %d %s", parv[0],
					idle_time, target->name);
			return 0;
		}
	}

	buffer[0] = '\0';
	for(ptr = local_cptr_list; ptr; ptr = ptr->next_local_client)
	{
		if(ptr->user->last_sent < check_time)
			continue;

		if(len + strlen(ptr->name) > 319)
		{
			buffer[len - 1] = '\0'; /* Strip the trailing space */
			send_markup(sptr, &me, "SCAN-IDLE", "%d %s", idle_time, buffer);
			buffer[0] = '\0';
			len = 0;
		}

		strcat(buffer, ptr->name);
		strcat(buffer, " ");
		len += strlen(ptr->name) + 1;
		count++;
	}

	if(buffer[0])
	{
		buffer[len - 1] = '\0';
		send_markup(sptr, &me, "SCAN-IDLE", "%d %s", idle_time, buffer);
	}

	send_markup(sptr, &me, "IDLE-END", "End of idle listing");
	if(count > 0 || target || parc == 3) /* Don't give a summary for globals if no results matched */
		send_markup(sptr, &me, "SCAN-SUMMARY", "%d matched", count);

	return 0;
}
int m_snick(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
{
  struct Client *acptr;

  if (IsPerson(sptr))
    {
      if (IsServer(cptr))
        {
	  sendto_ops_flag(UMODE_SERVNOTICE, "SNICK command from remote user %s -- %s is a hacked server",
			  sptr->name, cptr->name);
        }
      else
        {
          sendto_one(sptr, form_str(ERR_UNKNOWNCOMMAND),
                     me.name, parv[0], "SNICK");
        }
      return 0;
    }

  if (!IsServer(sptr))
    return 0;

  if (parc < 3)
    {
      sendto_ops_flag(UMODE_DEBUG, "%s sent SNICK with no parameters", sptr->name);
      return 0;
    }

  if (!(acptr = find_client(parv[1], NULL)))
    {
#if 0 /* we don't need this, SNICK is only sent after NICK -- jilles */
      /* Ghost. Kill it. */
      sendto_ops_flag(UMODE_SERVNOTICE, "Ghosted: %s from %s",
		      parv[1], cptr->name);
      sendto_one(cptr, ":%s KILL %s :%s (%s ghosted %s)",
		 me.name, parv[1], me.name, me.name, parv[1]);
#endif
      return 0;
    }

  if (cptr != acptr->from)
    {
      /* Wrong direction. Ignore it to prevent it from being applied
       * to the wrong user. This code would never have been necessary
       * if the command had been :<user> SNICK in the first place.
       * -- jilles */
      ServerStats->is_wrdi++;
      sendto_ops_flag(UMODE_DEBUG, "%s sent SNICK for %s, but %s is at %s",
		      cptr->name, acptr->name, acptr->name, acptr->from->name);
      return 0;
    }

  if (!IsPerson(acptr))
    {
      sendto_ops_flag(UMODE_DEBUG, "%s sent SNICK for non-person %s", sptr->name, acptr->name);
      return 0;
    }

  if (parc > 2)
    strncpy_irc(acptr->origname, parv[2], HOSTLEN + 1);
  if (parc > 3)
    strncpy_irc(acptr->spoofhost, parv[3], HOSTLEN + 1);
  if (parc > 4)
    acptr->firsttime = atol(parv[4]);
  if (parc > 5)
    strncpy_irc(acptr->dnshost, parv[5], HOSTLEN + 1);
  if (parc > 6)
    {
      strncpy_irc(acptr->user->servlogin,
		      irccmp(parv[6], SERVLOGIN_NONE) ? parv[6] : "",
		      SERVLOGINLEN + 1);
    }

  sendto_serv_butone(cptr, "SNICK %s %s %s %.1ld %s %s", acptr->name,
		     acptr->origname, acptr->spoofhost, acptr->firsttime,
		     acptr->dnshost, acptr->user->servlogin[0] ?
		     acptr->user->servlogin : SERVLOGIN_NONE);

  return 0;
}
Beispiel #26
0
/*
** m_sendumode - Stskeeps
**      parv[0] = sender prefix
**      parv[1] = target
**      parv[2] = message text
** Pretty handy proc.. 
** Servers can use this to f.x:
**   :server.unreal.net SENDUMODE F :Client connecting at server server.unreal.net port 4141 usw..
** or for sending msgs to locops.. :P
*/
DLLFUNC int m_sendumode(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
	char *message;
	char *p;
	int i;
	long umode_s = 0;
	long snomask = 0;

	aClient* acptr;

	message = (parc > 3) ? parv[3] : parv[2];

	if (parc < 3)
	{
		sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
		    me.name, parv[0], "SENDUMODE");
		return 0;
	}

	if (!IsServer(sptr))
	{
		sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
		return 0;
	}

	sendto_serv_butone(IsServer(cptr) ? cptr : NULL,
	    ":%s SMO %s :%s", parv[0], parv[1], message);

	for (p = parv[1]; *p; p++)
	{
		umode_s = 0;
		
		for(i = 0; i <= Usermode_highest; i++)
		{
			if (!Usermode_Table[i].flag)
				continue;
			if (Usermode_Table[i].flag == *p)
			{
				umode_s |= Usermode_Table[i].mode;
				break;
			}
		}
		if (i <= Usermode_highest)
			continue;

		for(i = 0; i <= Snomask_highest; i++)
		{
			if (Snomask_Table[i].flag == *p)
			{
				snomask |= Snomask_Table[i].mode;
				break;
			}
		}
	}

	if (parc > 3)
	    for(p = parv[2]; *p; p++)
	{
		for (i = 0; i <= Snomask_highest; i++)
		{
			if (Snomask_Table[i].flag == *p)
			{
				snomask |= Snomask_Table[i].mode;
				break;
			}
		}
	}

	for(i = 0; i <= LastSlot; i++)
	    if((acptr = local[i]) && IsPerson(acptr) && ((acptr->user->snomask & snomask) ||
		(acptr->umodes & umode_s)))
	{
		sendto_one(acptr, ":%s NOTICE %s :%s", me.name, acptr->name, message);
	}

	return 0;
}
Beispiel #27
0
static int
do_server_estab(aClient *cptr)
{
    aClient *acptr;
    aConnect *aconn;
    aChannel *chptr;
    int i;
    /* "refresh" inpath with host  */
    char *inpath = get_client_name(cptr, HIDEME);

    SetServer(cptr);

    Count.unknown--;
    Count.server++;
    Count.myserver++;

    if(IsZipCapable(cptr) && DoZipThis(cptr))
    {
        sendto_one(cptr, "SVINFO ZIP");
        SetZipOut(cptr);
        cptr->serv->zip_out = zip_create_output_session();
    }

#ifdef MAXBUFFERS
    /* let's try to bump up server sock_opts... -Taner */
    reset_sock_opts(cptr->fd, 1);
#endif

    /* adds to server list */
    add_to_list(&server_list, cptr);

    set_effective_class(cptr);

    /* Check one more time for good measure... is it there? */
    if ((acptr = find_name(cptr->name, NULL)))
    {
        char        nbuf[HOSTLEN * 2 + USERLEN + 5];
        aClient *bcptr;

        /*
         * While negotiating stuff, another copy of this server appeared.
         *
         * Rather than KILL the link which introduced it, KILL the
         * youngest of the two links. -avalon
         */

        bcptr = (cptr->firsttime > acptr->from->firsttime) ? cptr :
            acptr->from;
        sendto_one(bcptr, "ERROR :Server %s already exists", cptr->name);
        if (bcptr == cptr)
        {
            sendto_gnotice("from %s: Link %s cancelled, server %s already "
                           "exists (final phase)", me.name,
                           get_client_name(bcptr, HIDEME), cptr->name);
            sendto_serv_butone(bcptr, ":%s GNOTICE :Link %s cancelled, "
                                "server %s already exists (final phase)",
                                me.name, get_client_name(bcptr, HIDEME),
                                cptr->name);
            return exit_client(bcptr, bcptr, &me,
                               "Server Exists (final phase)");
        }
        /* inform all those who care (set +n) -epi */

        strcpy(nbuf, get_client_name(bcptr, HIDEME));
        sendto_gnotice("from %s: Link %s cancelled, server %s reintroduced "
                       "by %s (final phase)", me.name, nbuf, cptr->name,
                       get_client_name(cptr, HIDEME));
        sendto_serv_butone(bcptr, ":%s GNOTICE :Link %s cancelled, server %s "
                           "reintroduced by %s (final phase)", me.name, nbuf,
                           cptr->name, get_client_name(cptr, HIDEME));
        exit_client(bcptr, bcptr, &me, "Server Exists (final phase)");
    }

    /* error, error, error! if a server is U:'d, and it connects to us,
     * we need to figure that out! So, do it here. - lucas
     */

    if (find_aUserver(cptr->name))
    {
        Count.myulined++;
        cptr->flags |= FLAGS_ULINE;

        /* If the server has special u:line flags, let's set them.. */
        cptr->serv->uflags = cptr->serv->aconn->uflags;
    }

    fakelinkserver_update(cptr->name, cptr->info);

    sendto_gnotice("from %s: Link with %s established, states:%s%s%s%s",
                   me.name, inpath, ZipOut(cptr) ? " Output-compressed" : "",
                   RC4EncLink(cptr) ? " encrypted" : "",
                   IsULine(cptr) ? " ULined" : "",
                   DoesTS(cptr) ? " TS" : " Non-TS");

    /*
     * Notify everyone of the fact that this has just linked: the entire
     * network should get two of these, one explaining the link between
     * me->serv and the other between serv->me
     */

    sendto_serv_butone(NULL, ":%s GNOTICE :Link with %s established: %s",
                       me.name, inpath,
                       DoesTS(cptr) ? "TS link" : "Non-TS link!");

    add_to_client_hash_table(cptr->name, cptr);

    /* add it to scache */

    find_or_add(cptr->name);

    /*
     * Old sendto_serv_but_one() call removed because we now need to
     * send different names to different servers (domain name
     * matching) Send new server to other servers.
     */
    for (i = 0; i <= highest_fd; i++)
    {
        if (!(acptr = local[i]) || !IsServer(acptr) || acptr == cptr ||
            IsMe(acptr))
            continue;
        if ((aconn = acptr->serv->aconn) &&
            !match(my_name_for_link(me.name, aconn), cptr->name))
            continue;
        sendto_one(acptr, ":%s SERVER %s 2 :%s", me.name, cptr->name,
                   cptr->info);
    }

    /*
     * Pass on my client information to the new server
     *
     * First, pass only servers (idea is that if the link gets
     * cancelled beacause the server was already there, there are no
     * NICK's to be cancelled...). Of course, if cancellation occurs,
     * all this info is sent anyway, and I guess the link dies when a
     * read is attempted...? --msa
     *
     * Note: Link cancellation to occur at this point means that at
     * least two servers from my fragment are building up connection
     * this other fragment at the same time, it's a race condition,
     * not the normal way of operation...
     *
     * ALSO NOTE: using the get_client_name for server names-- see
     * previous *WARNING*!!! (Also, original inpath is
     * destroyed...)
     */

    aconn = cptr->serv->aconn;
    for (acptr = &me; acptr; acptr = acptr->prev)
    {
        if (acptr->from == cptr)
            continue;
        if (IsServer(acptr))
        {
            if (match(my_name_for_link(me.name, aconn), acptr->name) == 0)
                continue;
            sendto_one(cptr, ":%s SERVER %s %d :%s",
                       acptr->serv->up, acptr->name,
                       acptr->hopcount + 1, acptr->info);
        }
    }

    /* send out our SQLINES and SGLINES too */
    send_simbans(cptr, SBAN_CHAN|SBAN_NETWORK);
    send_simbans(cptr, SBAN_NICK|SBAN_NETWORK);
    send_simbans(cptr, SBAN_GCOS|SBAN_NETWORK);

    /* Send out fake server list and other 'fake' stuff */
    fakeserver_sendserver(cptr);

    /* Send UHM (user host-masking) type */
    if(confopts & FLAGS_HUB)
        sendto_one(cptr, "SVSUHM %d", uhm_type);

    /* send clone list */
    clones_send(cptr);

    /* Bursts are about to start.. send a BURST */
    if (IsBurst(cptr))
        sendto_one(cptr, "BURST");

    /*
     * * Send it in the shortened format with the TS, if it's a TS
     * server; walk the list of channels, sending all the nicks that
     * haven't been sent yet for each channel, then send the channel
     * itself -- it's less obvious than sending all nicks first, but
     * on the receiving side memory will be allocated more nicely
     * saving a few seconds in the handling of a split -orabidoo
     */
    {
        chanMember       *cm;
        static char nickissent = 1;

        nickissent = 3 - nickissent;
        /*
         * flag used for each nick to check if we've sent it yet - must
         * be different each time and !=0, so we alternate between 1 and
         * 2 -orabidoo
         */
        for (chptr = channel; chptr; chptr = chptr->nextch)
        {
            for (cm = chptr->members; cm; cm = cm->next)
            {
                acptr = cm->cptr;
                if (acptr->nicksent != nickissent)
                {
                    acptr->nicksent = nickissent;
                    if (acptr->from != cptr)
                        sendnick_TS(cptr, acptr);
                }
            }
            send_channel_modes(cptr, chptr);
        }
        /* also send out those that are not on any channel */
        for (acptr = &me; acptr; acptr = acptr->prev)
            if (acptr->nicksent != nickissent)
            {
                acptr->nicksent = nickissent;
                if (acptr->from != cptr)
                    sendnick_TS(cptr, acptr);
            }
    }

    if(confopts & FLAGS_HUB)
        fakelusers_sendlock(cptr);

    if(ZipOut(cptr))
    {
        unsigned long inb, outb;
        double rat;

        zip_out_get_stats(cptr->serv->zip_out, &inb, &outb, &rat);

        if(inb)
        {
            sendto_gnotice("from %s: Connect burst to %s: %lu bytes normal, "
                           "%lu compressed (%3.2f%%)", me.name,
                           get_client_name(cptr, HIDEME), inb, outb, rat);
            sendto_serv_butone(cptr, ":%s GNOTICE :Connect burst to %s: %lu "
                               "bytes normal, %lu compressed (%3.2f%%)",
                               me.name, get_client_name(cptr, HIDEME), inb,
                               outb, rat);
        }
    }

    /* stuff a PING at the end of this burst so we can figure out when
       the other side has finished processing it. */
    cptr->flags |= FLAGS_BURST|FLAGS_PINGSENT;
    if (IsBurst(cptr)) cptr->flags |= FLAGS_SOBSENT;
    sendto_one(cptr, "PING :%s", me.name);

    return 0;
}
Beispiel #28
0
static      time_t
check_pings(time_t currenttime)
{
aClient 	*cptr;
aConfItem 	*aconf = (aConfItem *) NULL;
int     	 killflag, zkillflag, ping = 0, i;
time_t      	 oldest = 0; /* timeout removed, see EXPLANATION below */
char       	*reason, *ktype, fbuf[512];
char 		*errtxt = "No response from %s, closing link";


   for (i = 0; i <= highest_fd; i++) 
   {
      if (!(cptr = local[i]) || IsMe(cptr) || IsLog(cptr))
	 continue;

       /* Note: No need to notify opers here. It's 
	* already done when "FLAGS_DEADSOCKET" is set.
        */

      if (cptr->flags & FLAGS_DEADSOCKET) 
      {
	 (void) exit_client(cptr, cptr, &me, (cptr->flags & FLAGS_SENDQEX) ?
			    "SendQ exceeded" : "Dead socket");
	 i--;
	 continue;
      }

      killflag = NO;
      zkillflag = NO;

      if (rehashed) 
      {
	 if (zline_in_progress) 
	 {
	    if (IsPerson(cptr)) 
	    {
	       if ((aconf = find_zkill(cptr)))	
		  zkillflag = YES;
	    }
	 }
	 else 
	 {
	    if(IsPerson(cptr)) 
	    {
	       if((aconf = find_kill(cptr)))	
		  killflag = YES;	
	    }
	 }
      }

      /* Added a bit of code here to differentiate 
       * between K and Z-lines. -ThemBones
       */

      if (zkillflag || killflag)
      {
         ktype = zkillflag ? "Z-lined" : 
            ((aconf->status == CONF_KILL) ? "K-lined" : "Autokilled");

	 if (killflag) 
         {
	    sendto_ops("%s active for %s",
                       (aconf->status == CONF_KILL) ? "K-line" : "Autokill",
		       get_client_name(cptr, FALSE));
	    reason = aconf->passwd ? aconf->passwd : ktype;
	 }
	 else 
         {			/* its a Z line */
	    sendto_ops("Z-line active for %s",
		       get_client_name(cptr, FALSE));
	    reason = aconf->passwd ? aconf->passwd : "Z-lined";
	 }

	 sendto_one(cptr, err_str(ERR_YOUREBANNEDCREEP),
		    me.name, cptr->name, ktype);

         ircsprintf(fbuf, "%s: %s", ktype, reason);
	 (void) exit_client(cptr, cptr, &me, fbuf);
	 i--;			/* subtract out this fd so we check it again.. */			
	 continue;
      }

      if (IsRegistered(cptr))
	 ping = cptr->pingval;
      else
	 ping = CONNECTTIMEOUT;

      /*
       * Ok, so goto's are ugly and can be avoided here but this code
       * is already indented enough so I think its justified. -avalon
       *
       * justified by what? laziness? <g>
       * If the client pingtime is fine (ie, not larger than the client ping) 
       * skip over all the checks below. - lucas
       */

      if (ping < (currenttime - cptr->lasttime))
      {
         /*
          * If the server hasnt talked to us in 2*ping seconds and it has
          * a ping time, then close its connection. If the client is a
          * user and a KILL line was found to be active, close this
          * connection too.
          */
         if (((cptr->flags & FLAGS_PINGSENT) && ((currenttime - cptr->lasttime) >= (2 * ping))) ||
             ((!IsRegistered(cptr) && (currenttime - cptr->since) >= ping))) 
         {
	    if (!IsRegistered(cptr) && (DoingDNS(cptr) || DoingAuth(cptr))) 
            {
	       if (cptr->authfd >= 0) 
	       {
	          (void) close(cptr->authfd);
	          cptr->authfd = -1;
	          cptr->count = 0;
	          *cptr->buffer = '\0';
	       }
#ifdef SHOW_HEADERS
	       if (DoingDNS(cptr))
	          ssl_send(cptr, REPORT_FAIL_DNS, R_fail_dns, 0);
	       if (DoingAuth(cptr))
	          ssl_send(cptr, REPORT_FAIL_ID, R_fail_id, 0);
#endif
	       Debug((DEBUG_NOTICE, "DNS/AUTH timeout %s",
	 	      get_client_name(cptr, TRUE)));
	       del_queries((char *) cptr);
	       ClearAuth(cptr);
	       ClearDNS(cptr);
	       SetAccess(cptr);
	       cptr->since = currenttime;
	       continue;
	    }

	    if (IsServer(cptr) || IsConnecting(cptr) || IsHandshake(cptr)) 
	    {
	       ircsprintf(fbuf, "from %s: %s", me.name, errtxt);
	       sendto_gnotice(fbuf, get_client_name(cptr, HIDEME));
	       ircsprintf(fbuf, ":%s GNOTICE :%s", me.name, errtxt);                                
	       sendto_serv_butone(cptr, fbuf, get_client_name(cptr, HIDEME));
	    }

	    (void) exit_client(cptr, cptr, &me, "Ping timeout");
	    i--;			/* subtract out this fd so we check it again.. */			
	    continue;
         } /* don't send pings during a burst, as we send them already. */

         else if (!(cptr->flags & (FLAGS_PINGSENT|FLAGS_BURST))) {
	    /*
	     * if we havent PINGed the connection and we havent heard from
	     * it in a while, PING it to make sure it is still alive.
	     */
	    cptr->flags |= FLAGS_PINGSENT;
	    /*
	     * not nice but does the job 
	     */
	    cptr->lasttime = currenttime - ping;
	    sendto_one(cptr, "PING :%s", me.name);
         }
      }

      /* see EXPLANATION below
       *
       * timeout = cptr->lasttime + ping;
       * while (timeout <= currenttime)
       *  timeout += ping;
       * if (timeout < oldest || !oldest)
       *   oldest = timeout;
       */

      /*
       * Check UNKNOWN connections - if they have been in this state
       * for > 100s, close them.
       */
      if (IsUnknown(cptr))
	 if (cptr->firsttime ? ((timeofday - cptr->firsttime) > 100) : 0) 
	    (void) exit_client(cptr, cptr, &me, "Connection Timed Out");
   }

   rehashed = 0;
   zline_in_progress = 0;

   /* EXPLANATION
    * on a server with a large volume of clients, at any given point
    * there may be a client which needs to be pinged the next second,
    * or even right away (a second may have passed while running
    * check_pings). Preserving CPU time is more important than
    * pinging clients out at exact times, IMO. Therefore, I am going to make
    * check_pings always return currenttime + 9. This means that it may take
    * a user up to 9 seconds more than pingfreq to timeout. Oh well.
    * Plus, the number is 9 to 'stagger' our check_pings calls out over
    * time, to avoid doing it and the other tasks ircd does at the same time
    * all the time (which are usually done on intervals of 5 seconds or so). 
    * - lucas
    *
    *  if (!oldest || oldest < currenttime)
    *     oldest = currenttime + PINGFREQUENCY;
    */

   oldest = currenttime + 9;

   Debug((DEBUG_NOTICE, "Next check_ping() call at: %s, %d %d %d",
	  myctime(oldest), ping, oldest, currenttime));

   return oldest;
}
Beispiel #29
0
/*
 * m_nick 
 * parv[0] = sender prefix 
 * parv[1] = nickname 
 * parv[2] = hopcount when new user; TS when nick change 
 * parv[3] = TS
 * ---- new user only below ---- 
 * parv[4] = umode 
 * parv[5] = username 
 * parv[6] = hostname 
 * parv[7] = server 
 * parv[8] = serviceid
 * parv[9] = IP
 * parv[10] = ircname
 * -- endif
 */
int m_nick(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
    struct simBan *ban;
    aClient    *acptr, *uplink;
    Link       *lp, *lp2;
    char        nick[NICKLEN + 2];
    ts_val      newts = 0;
    int         sameuser = 0, samenick = 0;
  
    if (parc < 2)
    {
	sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN),
		   me.name, parv[0]);
	return 0;
    }
  
    if (!IsServer(sptr) && IsServer(cptr) && parc > 2)
	newts = atol(parv[2]);
    else if (IsServer(sptr) && parc > 3)
	newts = atol(parv[3]);
    else
	parc = 2;
    /*
     * parc == 2 on a normal client sign on (local) and a normal client 
     * nick change 
     * parc == 4 on a normal server-to-server client nick change
     * parc == 11 on a normal TS style server-to-server NICK introduction
     */
    if ((IsServer(sptr) || (parc > 4)) && (parc < 11))
    {
	/*
	 * We got the wrong number of params. Someone is trying to trick
	 * us. Kill it. -ThemBones As discussed with ThemBones, not much
	 * point to this code now sending a whack of global kills would
	 * also be more annoying then its worth, just note the problem,
	 * and continue -Dianora
	 */
	sendto_realops("IGNORING BAD NICK: %s[%s@%s] on %s (from %s)", parv[1],
		       (parc >= 6) ? parv[5] : "-",
		       (parc >= 7) ? parv[6] : "-",
		       (parc >= 8) ? parv[7] : "-", parv[0]);
	return 0;
     
    }
   
    strncpyzt(nick, parv[1], NICKLEN + 1);
    /*
     * if do_nick_name() returns a null name OR if the server sent a
     * nick name and do_nick_name() changed it in some way (due to rules
     * of nick creation) then reject it. If from a server and we reject
     * it, and KILL it. -avalon 4/4/92
     */
    if (do_nick_name(nick) == 0 || (IsServer(cptr) && strcmp(nick, parv[1])))
    {
	sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME),
		   me.name, parv[0], parv[1], "Erroneous Nickname");
	
	if (IsServer(cptr))
	{
	    ircstp->is_kill++;
        sendto_realops_lev(DEBUG_LEV, "Bad Nick: %s From: %s Via: %s",
			       parv[1], parv[0],
			       get_client_name(cptr, HIDEME));
	    sendto_one(cptr, ":%s KILL %s :%s (Bad Nick)",
		       me.name, parv[1], me.name);
	    if (sptr != cptr) { /* bad nick change */     
		sendto_serv_butone(cptr, ":%s KILL %s :%s (Bad Nick)", me.name,
				   parv[0], me.name);
		sptr->flags |= FLAGS_KILLED;
		return exit_client(cptr, sptr, &me, "BadNick");
	    }
	}
	return 0;
    }
    /*
     * Check against nick name collisions.
     * 
     * Put this 'if' here so that the nesting goes nicely on the screen
     * :) We check against server name list before determining if the
     * nickname is present in the nicklist (due to the way the below
     * for loop is constructed). -avalon
     */
    do
    {
	if ((acptr = find_server(nick, NULL)))
	    if (MyConnect(sptr))
	    {
		sendto_one(sptr, err_str(ERR_NICKNAMEINUSE), me.name,
			   BadPtr(parv[0]) ? "*" : parv[0], nick);
		return 0;
	    }
	
	/* 
	 * acptr already has result from find_server
	 * Well. unless we have a capricious server on the net, a nick can
	 * never be the same as a server name - Dianora
	 * That's not the only case; maybe someone broke do_nick_name
	 * or changed it so they could use "." in nicks on their network 
	 * - sedition
	 */
     
	if (acptr)
	{
	    /*
	     * We have a nickname trying to use the same name as a
	     * server. Send out a nick collision KILL to remove the
	     * nickname. As long as only a KILL is sent out, there is no
	     * danger of the server being disconnected.  Ultimate way to
	     * jupiter a nick ? >;-). -avalon
	     */
	    sendto_realops_lev(SKILL_LEV, "Nick collision on %s", sptr->name);
	    ircstp->is_kill++;
	    sendto_one(cptr, ":%s KILL %s :%s (Nick Collision)", me.name, 
		       sptr->name, me.name);
	    sptr->flags |= FLAGS_KILLED;
	    return exit_client(cptr, sptr, &me, "Nick/Server collision");
	}
	
	if (!(acptr = find_client(nick, NULL)))
	    break;
     
	/*
	 * If acptr == sptr, then we have a client doing a nick change
	 * between *equivalent* nicknames as far as server is concerned
	 * (user is changing the case of his/her nickname or somesuch)
	 */
	if (acptr == sptr)
	{
	    if (strcmp(acptr->name, nick) == 0) 
		return 0;
	    else
		break;
	} /* If user is changing nick to itself no point in propogating */
     
	/*
	 * Note: From this point forward it can be assumed that acptr !=
	 * sptr (point to different client structures).
	 *
	 * If the older one is "non-person", the new entry is just 
	 * allowed to overwrite it. Just silently drop non-person, and
	 * proceed with the nick. This should take care of the "dormant
	 * nick" way of generating collisions...
	 */
	if (IsUnknown(acptr))
	{
	    if (MyConnect(acptr))
	    {
		exit_client(NULL, acptr, &me, "Overridden");
		break;
	    }
	    else if (!(acptr->user))
	    {
		sendto_realops_lev(SKILL_LEV, "Nick Collision on %s", parv[1]);
		sendto_serv_butone(NULL, ":%s KILL %s :%s (Nick Collision)",
				   me.name, acptr->name, me.name);
		acptr->flags |= FLAGS_KILLED;
		/* Having no USER struct should be ok... */
		return exit_client(cptr, acptr, &me,
				   "Got TS NICK before Non-TS USER");
	    }
	}
     
	if (!IsServer(cptr))
	{
	    /*
	     * NICK is coming from local client connection. Just send
	     * error reply and ignore the command.
	     * parv[0] is empty on connecting clients
	     */
	    sendto_one(sptr, err_str(ERR_NICKNAMEINUSE),
		       me.name, BadPtr(parv[0]) ? "*" : parv[0], nick);
	    return 0;
	}
	/*
	 * NICK was coming from a server connection. Means that the same
	 * nick is registered for different users by different server.
	 * This is either a race condition (two users coming online about
	 * same time, or net reconnecting) or just two net fragments
	 * becoming joined and having same nicks in use. We cannot have
	 * TWO users with same nick--purge this NICK from the system with
	 * a KILL... >;)
	 *
	 * Changed to something reasonable like IsServer(sptr) (true if
	 * "NICK new", false if ":old NICK new") -orabidoo
	 */
     
	if (IsServer(sptr))
	{
	    /*
	     * A new NICK being introduced by a neighbouring server (e.g.
	     * message type "NICK new" received)
	     */
	    if (!newts || !acptr->tsinfo || (newts == acptr->tsinfo))
	    {
		sendto_realops_lev(SKILL_LEV, "Nick collision on %s", parv[1]);
		ircstp->is_kill++;
		sendto_one(acptr, err_str(ERR_NICKCOLLISION),
			   me.name, acptr->name, acptr->name);
		sendto_serv_butone(NULL, ":%s KILL %s :%s (Nick Collision)",
				   me.name, acptr->name, me.name);
		acptr->flags |= FLAGS_KILLED;
		return exit_client(cptr, acptr, &me, "Nick collision");
	    }
	    else
	    {
		/* XXX This looks messed up to me XXX - Raist */
		sameuser = (acptr->user) &&
		    mycmp(acptr->user->username, parv[5]) == 0 &&
		    mycmp(acptr->user->host, parv[6]) == 0;
		if ((sameuser && newts < acptr->tsinfo) || 
		    (!sameuser && newts > acptr->tsinfo))
		{
		    return 0;
		}
		else
		{
		    sendto_realops_lev(SKILL_LEV, "Nick collision on %s",parv[1]);
		    ircstp->is_kill++;
		    sendto_one(acptr, err_str(ERR_NICKCOLLISION),
			       me.name, acptr->name, acptr->name);
		    sendto_serv_butone(sptr, ":%s KILL %s :%s (Nick Collision)",
				       me.name, acptr->name, me.name);
		    acptr->flags |= FLAGS_KILLED;
		    (void) exit_client(cptr, acptr, &me, "Nick collision");
		    break;
		}
	    }
	}
	/*
	 * * A NICK change has collided (e.g. message type * ":old NICK
	 * new". This requires more complex cleanout. * Both clients must be
	 * purged from this server, the "new" * must be killed from the
	 * incoming connection, and "old" must * be purged from all outgoing
	 * connections.
	 */
	if (!newts || !acptr->tsinfo || (newts == acptr->tsinfo) ||
	    !sptr->user)
	{
	    sendto_realops_lev(SKILL_LEV, "Nick change collision: %s", parv[1]);
	    ircstp->is_kill++;
	    sendto_one(acptr, err_str(ERR_NICKCOLLISION),
		       me.name, acptr->name, acptr->name);
	    sendto_serv_butone(NULL, ":%s KILL %s :%s (Nick Collision)",me.name,
			       sptr->name, me.name);
	    ircstp->is_kill++;
	    sendto_serv_butone(NULL, ":%s KILL %s :%s (Nick Collision)",me.name,
			       acptr->name, me.name);
	    acptr->flags |= FLAGS_KILLED;
	    (void) exit_client(NULL, acptr, &me, "Nick collision(new)");
	    sptr->flags |= FLAGS_KILLED;
	    return exit_client(cptr, sptr, &me, "Nick collision(old)");
	}
	else
	{
	    /* XXX This looks messed up XXX */
	    sameuser = mycmp(acptr->user->username, sptr->user->username) == 0
		&& mycmp(acptr->user->host, sptr->user->host) == 0;
	    if ((sameuser && newts < acptr->tsinfo) ||
		(!sameuser && newts > acptr->tsinfo)) {
		if (sameuser)
		    sendto_realops_lev(SKILL_LEV, 
				   "Nick change collision from %s to %s",
				   sptr->name, acptr->name);
		ircstp->is_kill++;
		sendto_serv_butone(cptr, ":%s KILL %s :%s (Nick Collision)", me.name,
				   sptr->name, me.name);
		sptr->flags |= FLAGS_KILLED;
		if (sameuser)
		    return exit_client(cptr, sptr, &me, "Nick collision(old)");
		else
		    return exit_client(cptr, sptr, &me, "Nick collision(new)");
	    } 
	    else
	    {
		sendto_realops_lev(SKILL_LEV, "Nick collision on %s", acptr->name);
		
		ircstp->is_kill++;
		sendto_one(acptr, err_str(ERR_NICKCOLLISION),
			   me.name, acptr->name, acptr->name);
		sendto_serv_butone(sptr, ":%s KILL %s :%s (Nick Collision)",me.name,
				   acptr->name, me.name);
		acptr->flags |= FLAGS_KILLED;
		(void) exit_client(cptr, acptr, &me, "Nick collision");
	    }
	}
    } while (0);
    
    if (IsServer(sptr))
    {
	uplink = find_server(parv[7], NULL);
	if(!uplink)
	{
	    /* if we can't find the server this nick is on, 
	     * complain loudly and ignore it. - lucas */
	    sendto_realops("Remote nick %s on UNKNOWN server %s",
			   nick, parv[7]);
	    return 0;
	}
	sptr = make_client(cptr, uplink);
	
	/* If this is on a U: lined server, it's a U: lined client. */
	if(IsULine(uplink))
	    sptr->flags|=FLAGS_ULINE;
     
	add_client_to_list(sptr);
	if (parc > 2)
	    sptr->hopcount = atoi(parv[2]);
	if (newts)
	{
	    sptr->tsinfo = newts;
	}
	else
	{
	    newts = sptr->tsinfo = (ts_val) timeofday;
	    ts_warn("Remote nick %s introduced without a TS", nick);
	}
	/* copy the nick in place */
	(void) strcpy(sptr->name, nick);
	(void) add_to_client_hash_table(nick, sptr);
	if (parc >= 10)
	{
	    int *s, flag;
	    char *m;
       
	    /* parse the usermodes -orabidoo */
	    m = &parv[4][1];
	    while (*m)
	    {
		for (s = user_modes; (flag = *s); s += 2)
		    if (*m == *(s + 1))
		    {
			if ((flag == UMODE_o) || (flag == UMODE_O))
			    Count.oper++;
			sptr->umode |= flag & SEND_UMODES;
			break;
		    }
		m++;
	    }
	    if (parc==10)
	    {
		return do_user(nick, cptr, sptr, parv[5], parv[6],
			       parv[7], strtoul(parv[8], NULL, 0),
			       "0.0.0.0", parv[9]);
	    } else if (parc==11)
	    {
		return do_user(nick, cptr, sptr, parv[5], parv[6], parv[7],
			       strtoul(parv[8], NULL, 0),
			       parv[9], parv[10]);
	    }
	}
    }
    else if (sptr->name[0])
    {
#ifdef DONT_CHECK_QLINE_REMOTE
	if (MyConnect(sptr))
	{
#endif
	    if ((ban = check_mask_simbanned(nick, SBAN_NICK)))
	    {
#ifndef DONT_CHECK_QLINE_REMOTE
		if (!MyConnect(sptr))
		    sendto_realops("Restricted nick %s from %s on %s", nick,
				   (*sptr->name != 0 && !IsServer(sptr)) ?
				   sptr->name : "<unregistered>",
				   (sptr->user == NULL) ? ((IsServer(sptr)) ?
							   parv[6] : me.name) :
				   sptr->user->server);
#endif
		
		if (MyConnect(sptr) && (!IsServer(cptr)) && (!IsOper(cptr))
		    && (!IsULine(sptr)))
		{
		    sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME), me.name,
			       BadPtr(parv[0]) ? "*" : parv[0], nick,
			       BadPtr(ban->reason) ? "Erroneous Nickname" :
			       ban->reason);
                    if (call_hooks(CHOOK_FORBID, cptr, nick, ban) != FLUSH_BUFFER)
		        sendto_realops_lev(REJ_LEV,
			    	           "Forbidding restricted nick %s from %s",
				           nick, get_client_name(cptr, FALSE));
		    return 0;
		}
	    }
#ifdef DONT_CHECK_QLINE_REMOTE
	}
#endif
	if (MyConnect(sptr))
	{
	    if (IsRegisteredUser(sptr))
	    {
	 
		/* before we change their nick, make sure they're not banned
		 * on any channels, and!! make sure they're not changing to
		 * a banned nick -sed */
		/* a little cleaner - lucas */
	 
		for (lp = sptr->user->channel; lp; lp = lp->next)
		{
		    if (can_send(sptr, lp->value.chptr, NULL))
		    { 
			sendto_one(sptr, err_str(ERR_BANNICKCHANGE), me.name,
				   sptr->name, lp->value.chptr->chname);
			return 0;
		    }
		    if (nick_is_banned(lp->value.chptr, nick, sptr) != NULL)
		    {
			sendto_one(sptr, err_str(ERR_BANONCHAN), me.name,
				   sptr->name, nick, lp->value.chptr->chname);
			return 0;
		    }
		}
#ifdef ANTI_NICK_FLOOD
		if ((sptr->last_nick_change + MAX_NICK_TIME) < NOW)
		    sptr->number_of_nick_changes = 0;
		sptr->last_nick_change = NOW;
		sptr->number_of_nick_changes++;
	 
		if (sptr->number_of_nick_changes > MAX_NICK_CHANGES && 
		    !IsAnOper(sptr))
		{
		    sendto_one(sptr,
			       ":%s NOTICE %s :*** Notice -- Too many nick "
			       "changes. Wait %d seconds before trying again.",
			       me.name, sptr->name, MAX_NICK_TIME);
		    return 0;
		}
#endif
		/* If it changed nicks, -r it */
		if ((sptr->umode & UMODE_r) && (mycmp(parv[0], nick) != 0))
		{
		    unsigned int oldumode;
		    char mbuf[BUFSIZE];

		    oldumode = sptr->umode;
		    sptr->umode &= ~UMODE_r;
		    send_umode(sptr, sptr, oldumode, ALL_UMODES, mbuf);
		}

                /* LOCAL NICKHANGE */
                /*
                 * Client just changing his/her nick. If he/she is on a
                 * channel, send note of change to all clients on that channel.
                 * Propagate notice to other servers.
                 */
                /* if the nickname is different, set the TS */
                if (mycmp(parv[0], nick))
                {
                  sptr->tsinfo = newts ? newts : (ts_val) timeofday;
                }

		sendto_common_channels(sptr, ":%s NICK :%s", parv[0], 
				       nick);
		if (sptr->user)
		{
		    add_history(sptr, 1);
			
		    sendto_serv_butone(cptr, ":%s NICK %s :%ld",
				       parv[0], nick, sptr->tsinfo);
		}
	    }
	}
	else
	{
            /* REMOTE NICKCHANGE */
            /*
             * Client just changing his/her nick. If he/she is on a
             * channel, send note of change to all clients on that channel.
             * Propagate notice to other servers.
             */
            /* if the nickname is different, set the TS */
            if (mycmp(parv[0], nick))
            {
              sptr->tsinfo = newts ? newts : (ts_val) timeofday;
            }

	    sendto_common_channels(sptr, ":%s NICK :%s", parv[0], nick);
	    if (sptr->user)
	    {
		add_history(sptr, 1);
		
		sendto_serv_butone(cptr, ":%s NICK %s :%ld",
				   parv[0], nick, sptr->tsinfo);
	    }

	    /* If it changed nicks, -r it */
	    if (mycmp(parv[0], nick))
		sptr->umode &= ~UMODE_r;

	    /*
	     * Flush the banserial for the channels the user is in, since this
	     * could be a SVSNICK induced nick change, which overrides any ban
	     * checking on the originating server.
	     */
	    flush_user_banserial(sptr);
	}
        /* Remove dccallow entries for users who don't share common channel(s) unless they only change their nick capitalization -Kobi_S */
        if(sptr->user && mycmp(parv[0], nick))
        {
            for(lp = sptr->user->dccallow; lp; lp = lp2)
            {
                lp2 = lp->next;
                if(lp->flags == DCC_LINK_ME)
                    continue;
                if(!find_shared_chan(sptr, lp->value.cptr))
                {
                    sendto_one(lp->value.cptr, ":%s %d %s :%s has been removed from "
                               "your DCC allow list for signing off",
                               me.name, RPL_DCCINFO, lp->value.cptr->name, parv[0]);
                    del_dccallow(lp->value.cptr, sptr, 1);
                }
            }
        }
    } 
    else
    {
	/* Client setting NICK the first time */
	if (MyConnect(sptr))
	{
	    if ((ban = check_mask_simbanned(nick, SBAN_NICK)))
	    {
		if (MyConnect(sptr) && (!IsServer(cptr)) && (!IsOper(cptr))
		    && (!IsULine(sptr)))
		{
		    sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME), me.name,
			       BadPtr(parv[0]) ? "*" : parv[0], nick,
			       BadPtr(ban->reason) ? "Erroneous Nickname" :
			       ban->reason);
                    if (call_hooks(CHOOK_FORBID, cptr, nick, ban) != FLUSH_BUFFER)
		        sendto_realops_lev(REJ_LEV,
				           "Forbidding restricted nick %s from %s", nick,
				           get_client_name(cptr, FALSE));
		    return 0;
		}
	    }
	}
	
	strcpy(sptr->name, nick);
	sptr->tsinfo = timeofday;
	if (sptr->user)
	{
	    /* USER already received, now we have NICK */
       
	    if (register_user(cptr, sptr, nick, sptr->user->username, NULL)
		== FLUSH_BUFFER)
		return FLUSH_BUFFER;
	}
    }

    /* Finally set new nick name. */
    if (sptr->name[0])
    {
        del_from_client_hash_table(sptr->name, sptr);
        samenick = mycmp(sptr->name, nick) ? 0 : 1;
        if (IsPerson(sptr))
        {
            if (!samenick)
                hash_check_watch(sptr, RPL_LOGOFF);
#ifdef RWHO_PROBABILITY
            probability_change(sptr->name, nick);
#endif
        }
    }
    strcpy(sptr->name, nick);
    add_to_client_hash_table(nick, sptr);
    if (IsPerson(sptr) && !samenick)
	hash_check_watch(sptr, RPL_LOGON);
    return 0;
}
Beispiel #30
0
/*
 * Exit one client, local or remote. Assuming all dependants have
 * been already removed, and socket closed for local client.
 */
static void 
exit_one_client(aClient *cptr, aClient *sptr, aClient *from, char *comment)
{
    Link   *lp;
    
    /*
     * For a server or user quitting, propogate the information to
     * other servers (except to the one where is came from (cptr))
     */
    if (IsMe(sptr))
    {
        sendto_ops("ERROR: tried to exit me! : %s", comment);
        return;                 /* ...must *never* exit self!! */
    }
    else if (IsServer(sptr))
    {
#ifdef ALWAYS_SEND_DURING_SPLIT
        currently_processing_netsplit = YES;
#endif

        exit_server(cptr, sptr, from, comment);
        
#ifdef ALWAYS_SEND_DURING_SPLIT
        currently_processing_netsplit = NO;
#endif
        return;
    }
    else if (!(IsPerson(sptr)))
        /*
         * ...this test is *dubious*, would need * some thought.. but for
         * now it plugs a * nasty hole in the server... --msa
         */
        ;                               /* Nothing */
    else if (sptr->name[0])
    {   
        /* ...just clean all others with QUIT... */
        /*
         * If this exit is generated from "m_kill", then there is no
         * sense in sending the QUIT--KILL's have been sent instead.
         */
        if ((sptr->flags & FLAGS_KILLED) == 0) 
        {
            sendto_serv_butone(cptr, ":%s QUIT :%s",
                               sptr->name, comment);
        }
        /*
         * * If a person is on a channel, send a QUIT notice * to every
         * client (person) on the same channel (so * that the client can
         * show the "**signoff" message). * (Note: The notice is to the
         * local clients *only*)
         */
        if (sptr->user)
        {
            send_part_to_common_channels(sptr, comment);
            send_quit_to_common_channels(sptr, comment);
            while ((lp = sptr->user->channel))
                remove_user_from_channel(sptr, lp->value.chptr);

	    clones_remove(sptr);

#ifdef RWHO_PROBABILITY
            probability_remove(sptr);
#endif
            
            /* Clean up invitefield */
            while ((lp = sptr->user->invited))
                del_invite(sptr, lp->value.chptr);
            /* Clean up silences */
            while ((lp = sptr->user->silence)) 
                del_silence(sptr, lp->value.cp);
            remove_dcc_references(sptr);
            /* again, this is all that is needed */
        }
    }

    /* Remove sptr from the client list */
    if (del_from_client_hash_table(sptr->name, sptr) != 1) 
    {
        Debug((DEBUG_ERROR, "%#x !in tab %s[%s] %#x %#x %#x %d %d %#x",
               sptr, sptr->name,
               sptr->from ? sptr->from->sockhost : "??host",
               sptr->from, sptr->next, sptr->prev, sptr->fd,
               sptr->status, sptr->user));
    }
    /* remove user from watchlists */
    if(IsRegistered(sptr))
        hash_check_watch(sptr, RPL_LOGOFF);
    remove_client_from_list(sptr);
    return;
}