/*
 * m_quit
 *      parv[0] = sender prefix
 *      parv[1] = comment
 */
int     m_quit(struct Client *cptr,
               struct Client *sptr,
               int parc,
               char *parv[])
#ifdef TIDY_QUIT
{
  buf[0] = '\0';
  if ((parc > 1) && parv[1])
    {
      if (strlen(parv[1]) > (MAX_QUIT_LENGTH - 2))
	parv[1][MAX_QUIT_LENGTH - 2] = '\0';
      /* Don't add quotes to a null message */
      if (MyConnect(sptr) && *parv[1])
	{
	  strncpy_irc(buf, "\"", 2);
	  strncat(buf, strip_colour(parv[1]), MAX_QUIT_LENGTH - 2);
	  strncat(buf, "\"", 1);
	}
      else
	strncpy_irc(buf, parv[1], BUFSIZE);
    }
  sptr->flags |= FLAGS_NORMALEX;


#ifdef ANTI_SPAM_EXIT_MESSAGE
  /* Your quit message is suppressed if:
   *
   * You haven't been connected to the server for long enough
   */
  if( !IsServer(sptr) && MyConnect(sptr) &&
     (sptr->firsttime + ANTI_SPAM_EXIT_MESSAGE_TIME) > CurrentTime)
    strcpy(buf, "Client Quit");
  else if (MyConnect(sptr) && IsPerson(sptr))
    {
      /* Or you are in a channel to which you cannot send */
      struct SLink *chptr;
      for (chptr = sptr->user->channel; chptr; chptr = chptr->next)
        {
          if (can_send(sptr, chptr->value.chptr) != 0)
            {
              strcpy(buf, "Client Quit");
              break;
            }
        }
    }
#endif
  if (IsPerson(sptr))
    {
      sendto_local_ops_flag(UMODE_CCONN,
			    "Client exiting: %s (%s@%s) [%s] [%s] [%s]",
			    sptr->name, sptr->username, sptr->host,
#ifdef WINTRHAWK
			    buf,
#else
			    (sptr->flags & FLAGS_NORMALEX) ?  "Client Quit" : comment,
#endif /* WINTRHAWK */
			    sptr->sockhost, sptr->servptr ? sptr->servptr->name : "<null>");
    }
  return IsServer(sptr) ? 0 : exit_client(cptr, sptr, sptr, buf);
}
Exemple #2
0
void
TreeAddKline(struct ServerBan *kptr)

{
  char **hostv;
  char hostname[HOSTLEN + 1];
  int hostpieces;

  assert(kptr != NULL);

  /*
   * So we don't destroy kptr->hostname, use another buffer
   */
  memset(hostname, 0, sizeof(hostname));
  strncpy_irc(hostname, kptr->hostname, HOSTLEN);

  hostpieces = BreakupHost(hostname, &hostv);

  if (IsSortable(hostpieces, hostv))
    CreateSubTree(&KlineTree, NULL, kptr, hostpieces, hostv);
  else
  {
    fprintf(stderr, "HOSTNAME [%s] IS NOT SORTABLE\n",
      kptr->hostname);
    AddUnsortableKline(kptr);
  }

  MyFree(hostv);
} /* TreeAddKline() */
Exemple #3
0
/*
 * m_pass() - Added Sat, 4 March 1989
 *
 *
 * m_pass - PASS message handler
 *      parv[0] = sender prefix
 *      parv[1] = password
 *      parv[2] = optional extra version information
 */
int m_pass(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
{
  char* password = parc > 1 ? parv[1] : NULL;

  if (EmptyString(password))
    {
      sendto_one(cptr, form_str(ERR_NEEDMOREPARAMS),
                 me.name, parv[0], "PASS");
      return 0;
    }
  if (!MyConnect(sptr) || (!IsUnknown(cptr) && !IsHandshake(cptr)))
    {
      sendto_one(cptr, form_str(ERR_ALREADYREGISTRED),
                 me.name, parv[0]);
      return 0;
    }
  strncpy_irc(cptr->passwd, password, PASSWDLEN);
  if (parc > 2)
    {
      /* 
       * It looks to me as if orabidoo wanted to have more
       * than one set of option strings possible here...
       * i.e. ":AABBTS" as long as TS was the last two chars
       * however, as we are now using CAPAB, I think we can
       * safely assume if there is a ":TS" then its a TS server
       * -Dianora
       */
      if ((0 == irccmp(parv[2], "TS")) && (cptr->tsinfo == 0))
        cptr->tsinfo = TS_DOESTS;
    }
  return 0;
}
/*
 * Whats happening in this next loop ? Well, it takes a name like
 * foo.bar.edu and proceeds to earch for *.edu and then *.bar.edu.
 * This is for checking full server names against masks although
 * it isnt often done this way in lieu of using matches().
 *
 * Rewrote to do *.bar.edu first, which is the most likely case,
 * also made const correct
 * --Bleep
 */
static struct Client* hash_find_masked_server(const char* name)
{
  char           buf[HOSTLEN + 1];
  char*          p = buf;
  char*          s;
  struct Client* server;

  if ('*' == *name || '.' == *name)
    return 0;

  /*
   * copy the damn thing and be done with it
   */
  strncpy_irc(buf, name, HOSTLEN + 1);
  buf[HOSTLEN] = '\0';

  while ((s = strchr(p, '.')) != 0)
    {
       *--s = '*';
      /*
       * Dont need to check IsServer() here since nicknames cant
       * have *'s in them anyway.
       */
      if ((server = hash_find_client(s, NULL)))
        return server;
      p = s + 2;
    }
  return 0;
}
Exemple #5
0
struct ServerBan *
SearchKlineTree(char *username, char *hostname)

{
  char host[HOSTLEN + 1];
  char **hostv;
  int hostc,
      ii;
  struct Level *ret;
  struct ServerBan *tmp;

  memset(host, 0, sizeof(host));
  strncpy_irc(host, hostname, HOSTLEN);

  hostc = BreakupHost(host, &hostv);

  if (!(++SerialNumber))
  {
    ++SerialNumber;
    ResetTree(&IlineTree);
    ResetTree(&KlineTree);
  }

  while ((ret = SearchSubTree(&KlineTree, hostc, hostv)))
  {
    if (!ret->numptrs)
    {
      log(L_ERROR,
        "SearchKlineTree(): search result has 0 Kline pointers");
      MyFree(hostv);
      /*ResetTree(&KlineTree);*/
      return (NULL);
    }

    /*
     * Check the username
     */
    for (ii = 0; ii < ret->numptrs; ++ii)
    {
      tmp = (struct ServerBan *) ret->typeptrs[ii];
      if (match(tmp->username, username))
      {
        MyFree(hostv);
        /*ResetTree(&KlineTree);*/
        return (tmp);
      }
    }
  }

  /*ResetTree(&KlineTree);*/

  /*
   * We failed to locate the Kline in our tree - search
   * the unsortable list
   */
  tmp = FindUnsortableKline(username, hostname);
  MyFree(hostv);
  return (tmp);
} /* SearchKlineTree() */
void cr_sendresponse(struct Client * cptr, struct ConfItem * c_conf, char * chall, char* salt) {
  struct ConfItem* n_conf = find_conf_by_name(cptr->name, CONF_NOCONNECT_SERVER);
  char work[PASSWDLEN*2], hash[40];
  strncpy_irc(work, chall, PASSWDLEN + 1);
  strncpy_irc(work + strlen(work), c_conf->passwd ? libshadow_md5_crypt(c_conf->passwd, salt) : "", PASSWDLEN + 1);
  cr_hashstring(work, hash);
  if (!IsUnknown(cptr) || (strcmp(cptr->passwd, n_conf->passwd) == 0))
    {
      sendto_one(cptr, "RESP %s", hash);
      SetResponded(cptr);
      sendto_ops_flag(UMODE_EXTERNAL, "Sent password response to %s", cptr->name);
    }
  else
    {
      strncpy_irc(cptr->response, hash, 40);
    }
}
Exemple #7
0
/*
 * All command line parameters have the syntax "-f string" or "-fstring"
 * OPTIONS:
 * -d filename - specify d:line file
 * -f filename - specify config file
 * -h hostname - specify server name
 * -k filename - specify k:line file
 * -l filename - specify log file
 * -n          - do not fork, run in foreground
 * -v          - print daemon version and exit
 * -x          - set debug level, if compiled for debug logging
 */
static void parse_command_line(int argc, char* argv[])
{
  const char* options = "d:f:h:k:l:nvx:"; 
  int         opt;

  while ((opt = getopt(argc, argv, options)) != EOF) {
    switch (opt) {
    case 'd': 
      if (optarg)
        ConfigFileEntry.dpath = optarg;
      break;
    case 'f':
#ifdef CMDLINE_CONFIG
      if (optarg)
        ConfigFileEntry.configfile = optarg;
#endif
      break;
    case 'k':
#ifdef KPATH
      if (optarg)
        ConfigFileEntry.klinefile = optarg;
#endif
      break;
    case 'h':
      if (optarg)
        strncpy_irc(me.name, optarg, HOSTLEN);
      break;
    case 'l':
      if (optarg)
        logFileName = optarg;
      break;
    case 'n':
      bootDaemon = 0; 
      break;
    case 'v':
      printf("ircd %s\n\tzlib %s\n\tircd_dir: %s\n", ircd_version,
#ifndef ZIP_LINKS
             "not used",
#else
              zlibVersion(),
#endif
              ConfigFileEntry.dpath);
      exit(0);
      break;   /* NOT REACHED */
    case 'x':
#ifdef  DEBUGMODE
      if (optarg) {
        debuglevel = atoi(optarg);
        debugmode = optarg;
      }
#endif
      break;
    default:
      bad_command();
      break;
    }
  }
}
void cr_sendchallenge(struct Client * cptr, struct ConfItem * n_conf) {
  /* Create a challenge using random data and sending it as a hex value.
   * Store this hex value in cptr->passwd, don't want more fields in cptr.
   * As this is sent before anything else, we pass the server name too so
   * the receiving end can look up our C/N lines.
   */
  char chall[17]="";
  unsigned int c;
  int i;
  for (i=0; i<16; i++) {
    c = (unsigned int) (16.0 * (random() / (RAND_MAX + 1.0)));
    chall[i] = (c>=10) ? (c - 10 + 'A' ) : (c + '0');
  }
  chall[16]=0;
  strncpy_irc(cptr->name, n_conf->name, HOSTLEN + 1);
  strncpy_irc(cptr->passwd, chall, PASSWDLEN + 1);
  sendto_one(cptr, "CHALL %s %s %s %s :TS", me.name, cptr->name, chall, get_salt(n_conf->passwd));
  SetChallenged(cptr);
  sendto_ops_flag(UMODE_EXTERNAL, "Sent password challenge to %s", cptr->name);
}
void cr_gotresponse(struct Client * cptr, char * resp) {
  struct ConfItem * n_conf;
  char work[PASSWDLEN*2], hash[36];
  n_conf = find_conf_by_name(cptr->name, CONF_NOCONNECT_SERVER);
  if (n_conf && cptr->passwd[0]) {
    strncpy_irc(work, cptr->passwd, PASSWDLEN + 1);
    strncpy_irc(work + strlen(work), n_conf->passwd ? n_conf->passwd : "", PASSWDLEN + 1);
    cr_hashstring(work, hash);
    if (!strcmp(resp, hash)) {
      strncpy_irc(cptr->passwd, n_conf->passwd, PASSWDLEN + 1);
      sendto_ops_flag(UMODE_SEEROUTING, "Got a good password response from %s", cptr->name);
      /* OK, do we have a response pending ourself? */
      if (cptr->response[0] && !Responded(cptr))
	{
	  sendto_one(cptr, "RESP %s", cptr->response);
	  cptr->response[0] = '\0';
	  SetResponded(cptr);
	  sendto_ops_flag(UMODE_EXTERNAL, "Sent password response to %s", cptr->name);
	}
    } else {
      sendto_ops_flag(UMODE_SEEROUTING, "Failed password response from %s", cptr->name);
    }
  }
}
Exemple #10
0
void add_history(aClient* cptr, int online)
{
  aWhowas* who = &WHOWAS[whowas_next];

  assert(0 != cptr);

  if (who->hashv != -1)
    {
      if (who->online)
        del_whowas_from_clist(&(who->online->whowas),who);
      del_whowas_from_list(&WHOWASHASH[who->hashv], who);
    }
  who->hashv = hash_whowas_name(cptr->name);
  who->logoff = CurrentTime;
  /*
   * NOTE: strcpy ok here, the sizes in the client struct MUST
   * match the sizes in the whowas struct
   */
  strncpy_irc(who->name, cptr->name, NICKLEN);
  who->name[NICKLEN] = '\0';
  strcpy(who->username, cptr->username);
  strcpy(who->hostname, cptr->host);
  strcpy(who->realname, cptr->info);

  /* Its not string copied, a pointer to the scache hash is copied
     -Dianora
   */
  /*  strncpy_irc(who->servername, cptr->user->server, HOSTLEN); */
  who->servername = cptr->user->server;

  if (online)
    {
      who->online = cptr;
      add_whowas_to_clist(&(cptr->whowas), who);
    }
  else
    who->online = NULL;
  add_whowas_to_list(&WHOWASHASH[who->hashv], who);
  whowas_next++;
  if (whowas_next == NICKNAMEHISTORYLENGTH)
    whowas_next = 0;
}
Exemple #11
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;
    }
}
Exemple #12
0
/*
 * m_server - SERVER message handler
 *      parv[0] = sender prefix
 *      parv[1] = servername
 *      parv[2] = hopcount
 *		parv[3]	= version
 *      parv[4] = serverinfo
 */
int m_server(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
{
  int              i;
  char             info[REALLEN + 1];
  char*            host;
  struct Client*   acptr;
  struct Client*   bcptr;
  struct ConfItem* aconf;
  int              hop;
  char	*remversion = NULL;

  info[0] = '\0';
  /*  inpath = get_client_name(cptr,FALSE); */
  if (parc < 2 || *parv[1] == '\0')
    {
      sendto_one(cptr,"ERROR :No servername");
      return 0;
    }
  hop = 0;
  host = parv[1];
  if (parc > 4 && atoi(parv[2]))
    {
      hop = atoi(parv[2]);
      strncpy_irc(info, parv[4], REALLEN);
      info[REALLEN] = '\0';
	  remversion = parv[3];
    }
  else if (parc > 3 && atoi(parv[2]))
    {
      hop = atoi(parv[2]);
      strncpy_irc(info, parv[3], REALLEN);
      info[REALLEN] = '\0';
    }
  else if (parc > 2)
    {
      /*
       * XXX - hmmmm
       */
      strncpy_irc(info, parv[2], REALLEN);
      info[REALLEN] = '\0';
      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(sptr))
    {
      /*
       * a USER tries something fishy... ;-)
       */
      if (IsServer(cptr))
        {
		  /* heh, obviously we've never encountered this condition ..
		   * get_client_name returns a little sumpin-sumpin static, we
		   * can't use it twice here. -gnp */
        char nbuf[HOSTLEN * 2 + USERLEN + 5]; /* same size as in s_misc.c */

#ifdef HIDE_SERVERS_IPS
		strcpy(nbuf, get_client_name(sptr,MASK_IP));
#else
		strcpy(nbuf, get_client_name(sptr,SHOW_IP));
#endif
        
          sendto_realops("SERVER command from remote user %s -- %s is a hacked server",
	                 nbuf, 
#ifdef HIDE_SERVERS_IPS
	                 get_client_name(cptr,MASK_IP));
#else							      
                     get_client_name(cptr,SHOW_IP));
#endif			  
        }
      else
        {
          sendto_one(sptr, form_str(ERR_UNKNOWNCOMMAND),
                     me.name, parv[0], "SERVER");
        }
      return 0;
    }
Exemple #13
0
struct Iline *
SearchIlineTree(char *username, char *hostname)

{
  char host[HOSTLEN + 1];
  char **hostv;
  int hostc,
      ii;
  struct Level *ret;
  struct Iline *tmp;

  memset(host, 0, sizeof(host));
  strncpy_irc(host, hostname, HOSTLEN);

  hostc = BreakupHost(host, &hostv);

  /*
   * A loop is needed to continually search the IlineTree
   * because of the username problem. Suppose we have 2
   * Ilines:
   *    (a) foo@*.net
   *    (b)   *@*.underworld.net
   * and suppose the client comes from [email protected].
   * SearchSubTree() may return (a) since the hostname part
   * actually does match, but this routine will return NULL
   * because it cannot find a username match, even though
   * there is another I: line that matches. Therefore, this
   * loop will continue searching the tree until absolutely
   * no more hostname matches are found.
   *
   * We can be sure it will not return the same I: line twice
   * because the variable SerialNumber gets continually
   * incremented. When a node has been searched, it's
   * serial is set to the current SerialNumber variable, so
   * we know it has been searched if it's serial matches
   * SerialNumber.
   */

  if (!(++SerialNumber))
  {
    /*
     * SerialNumber will eventually roll over to 0 when it
     * reaches it's 32 bit limit - reset both trees and
     * increment SerialNumber to 1.
     */
    ++SerialNumber;
    ResetTree(&IlineTree);
    ResetTree(&KlineTree);
  }

  while ((ret = SearchSubTree(&IlineTree, hostc, hostv)))
  {
    if (!ret->numptrs)
    {
      log(L_ERROR,
        "SearchIlineTree(): search result has 0 Iline pointers");
      MyFree(hostv);
      /*ResetTree(&IlineTree);*/
      return (NULL);
    }

    /*
     * Now for the username check
     */
    for (ii = 0; ii < ret->numptrs; ++ii)
    {
      tmp = (struct Iline *) ret->typeptrs[ii];
      if (match(tmp->username, username))
      {
        MyFree(hostv);
        /*ResetTree(&IlineTree);*/
        return (tmp);
      }
    }
  }

  /*ResetTree(&IlineTree);*/

  /*
   * We failed to locate the Iline in our tree - search
   * the unsortable list
   */
  tmp = FindUnsortableIline(username, hostname);
  MyFree(hostv);
  return (tmp);
} /* SearchIlineTree() */
Exemple #14
0
static int inetport(struct Listener* listener)
{
  struct SOCKADDR_IN port_sin;
  int                fd;
  int                opt = 1;

  /*
   * At first, open a new socket
   */
  fd = socket(AFINET, SOCK_STREAM, 0);

  if (-1 == fd) {
    report_error("opening listener socket %s:%s", 
                 get_listener_name(listener), errno);
    return 0;
  }
  else if ((HARD_FDLIMIT - 10) < fd) {
    report_error("no more connections left for listener %s:%s", 
                 get_listener_name(listener), errno);
    CLOSE(fd);
    return 0;
  }
  /* 
   * XXX - we don't want to do all this crap for a listener
   * set_sock_opts(listener);
   */ 
  if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*) &opt, sizeof(opt))) {
    report_error("setting SO_REUSEADDR for listener %s:%s", 
                 get_listener_name(listener), errno);
    CLOSE(fd);
    return 0;
  }

  /*
   * Bind a port to listen for new connections if port is non-null,
   * else assume it is already open and try get something from it.
   */
  memset(&port_sin, 0, sizeof(port_sin));
  port_sin.SIN_FAMILY = AFINET;
  port_sin.SIN_PORT   = htons(listener->port);
#ifdef __CYGWIN__
  port_sin.sin_addr   = listener->addr;
  
  if (INADDR_ANY != listener->addr.S_ADDR) {
    strncpy_irc(listener->vhost, inetntoa((char *)&listener->addr), HOSTLEN);
    listener->name = listener->vhost;
  }
  
#else
#ifdef IPV6
  bcopy((const char*)listener->addr.S_ADDR, (char*)port_sin.SIN_ADDR.S_ADDR, sizeof(struct IN_ADDR));
  if ( bcmp((char*)listener->addr.S_ADDR, &INADDRANY, sizeof(struct IN_ADDR)) == 0 ) 
#else
  port_sin.sin_addr   = listener->addr;
  if (INADDRANY != listener->addr.s_addr) 
#endif      
  {
 	struct addrinfo *ans;
	int ret;
        char port[5];
	char tmp[HOSTLEN];
      	/*
     	 * XXX - blocking call to getaddrinfo
         */
	sprintf( port, "%d", listener->port);
#ifdef IPV6
	inetntop(AFINET, &listener->addr, tmp, HOSTLEN);
#else
	inet_ntop(AF_INET, &listener->addr, tmp, HOSTLEN);
#endif
	ret = getaddrinfo(tmp, port, NULL, &ans );
	if( ret == 0  && ans->ai_canonname)
	  strncpy_irc(listener->vhost, ans->ai_canonname, HOSTLEN);
    }

#endif
                 
  if (bind(fd, (struct sockaddr*) &port_sin, sizeof(port_sin))) {
    report_error("binding listener socket %s:%s", 
                 get_listener_name(listener), errno);
    CLOSE(fd);
    return 0;
  }

  if (listen(fd, HYBRID_SOMAXCONN)) {
    report_error("listen failed for %s:%s", 
                 get_listener_name(listener), errno);
    CLOSE(fd);
    return 0;
  }

  /*
   * XXX - this should always work, performance will suck if it doesn't
   */
  if (!set_non_blocking(fd))
    report_error(NONB_ERROR_MSG, get_listener_name(listener), errno);

  listener->fd = fd;

  return 1;
}
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;
}
Exemple #16
0
int main(int argc, char *argv[])
{
  time_t      delay = 0;
  aConfItem*  aconf;
  
  if(geteuid() == 0)
  {
  	fprintf(stderr, "ERROR: Don't run ircd as root!\n");
  	return -1;
  }

  /*
   * save server boot time right away, so getrusage works correctly
   */
  if ((CurrentTime = time(0)) == -1)
    {
      fprintf(stderr, "ERROR: Clock Failure: %s\n", strerror(errno));
      exit(errno);
    }

  /*
   * Setup corefile size immediately after boot
   */
  setup_corefile();

  /* 
   * set initialVMTop before we allocate any memory
   */
  initialVMTop = get_vm_top();

  /*
   * Initialize the Blockheap allocator
   */
  initBlockHeap();

  ServerRunning = 0;
  memset(&me, 0, sizeof(me));
  GlobalClientList = &me;       /* Pointer to beginning of Client list */
  cold_start = YES;             /* set when server first starts up */

  memset(&Count, 0, sizeof(Count));
  Count.server = 1;     /* us */

  initialize_global_set_options();

#ifdef REJECT_HOLD
  reject_held_fds = 0;
#endif

  ConfigFileEntry.dpath = DPATH;

  ConfigFileEntry.configfile = CPATH;   /* Server configuration file */

#ifdef KPATH
  ConfigFileEntry.klinefile = KPATH;         /* Server kline file */
#else
  ConfigFileEntry.klinefile = CPATH;
#endif /* KPATH */

#ifdef DLPATH
  ConfigFileEntry.dlinefile = DLPATH;
#else
  ConfigFileEntry.dlinefile = CPATH;
#endif /* DLPATH */

#ifdef GLINES
  ConfigFileEntry.glinefile = GLINEFILE;
#endif

#ifdef  ZIP_LINKS
  /* Make sure the include files match the library version number. */
  /* configure takes care of looking for zlib and zlibVersion(). */
  if (strcmp(zlibVersion(), ZLIB_VERSION) != 0)
  {
    fprintf(stderr, "WARNING: zlib include files differ from library.\n");
    fprintf(stderr, "WARNING: ZIPLINKS may fail!\n");
    fprintf(stderr, "WARNING: library %s, include files %s\n",
            zlibVersion(), ZLIB_VERSION);
  }
#endif

  myargv = argv;
  umask(077);                /* better safe than sorry --SRB */

  parse_command_line(argc, argv); 

  if (chdir(ConfigFileEntry.dpath))
    {
      perror("chdir");
      exit(-1);
    }

  /*
   * Check if daemon is already running
   */
  check_pidfile();

  init_sys(bootDaemon);
  init_log(logFileName);

  setup_signals();
  initialize_message_files();

  isupport = make_isupport();

  dbuf_init();  /* set up some dbuf stuff to control paging */
  init_hash();

  clear_scache_hash_table();    /* server cache name table */
  clear_ip_hash_table();        /* client host ip hash table */
  clear_Dline_table();          /* d line tree */
  initlists();
  initclass();
  initwhowas();
  init_stats();
  init_tree_parse(msgtab);      /* tree parse code (orabidoo) */

  fdlist_init();
  init_netio();

  read_conf_files(YES);         /* cold start init conf files */

  aconf = find_me();
  if (EmptyString(me.name))
    strncpy_irc(me.name, aconf->host, HOSTLEN);
  strncpy_irc(me.host, aconf->host, HOSTLEN);

  me.fd = -1;
  me.from = &me;
  me.servptr = &me;
  SetMe(&me);
  make_server(&me);

  me.serv->up = me.name;
  me.lasttime = me.since = me.firsttime = CurrentTime;
  add_to_client_hash_table(me.name, &me);
  
  check_class();
  write_pidfile();

  log(L_NOTICE, "Server Ready");

  ServerRunning = 1;
  while (ServerRunning) {
    usleep(100000);
    do_adns_io();
    delay = io_loop(delay);
    do_adns_io();

  }
  return 0;
}
static  int     m_message(struct Client *cptr,
                          struct Client *sptr,
                          int parc,
                          char *parv[],
                          int notice)
{
  struct Client       *acptr;
#ifdef NEED_TLD_FOR_MASS_NOTICE
  char  *s;
#endif
  struct Channel *chptr;
  char  *nick, *server, *host;
  char  errbuf[BUFSIZE];
  const char *cmd;
  int type=0, msgs=0;
#ifdef FLUD
  int flud;
#endif

  cmd = notice ? MSG_NOTICE : MSG_PRIVATE;

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

      msgs++;
      continue;
    }

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

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

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

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

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

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

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

      *server = '\0';

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

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