]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/inspircd.cpp
Fixed quit-bouncing issue when a user is g-lined
[user/henk/code/inspircd.git] / src / inspircd.cpp
index c31464733f62b5cb31fb1cc4e9b555d73e5cb330..8f095889090c5a7e28d7c669319eca7092b32338 100644 (file)
@@ -54,6 +54,7 @@ using namespace std;
 #include "message.h"
 #include "mode.h"
 #include "commands.h"
+#include "xline.h"
 
 #ifdef GCC3
 #define nspace __gnu_cxx
@@ -266,184 +267,189 @@ void log(int level,char *text, ...)
 
 void readfile(file_cache &F, const char* fname)
 {
-  FILE* file;
-  char linebuf[MAXBUF];
-
-  log(DEBUG,"readfile: loading %s",fname);
-  F.clear();
-  file =  fopen(fname,"r");
-  if (file)
-  {
-       while (!feof(file))
-       {
-               fgets(linebuf,sizeof(linebuf),file);
-               linebuf[strlen(linebuf)-1]='\0';
-               if (!strcmp(linebuf,""))
-               {
-                       strcpy(linebuf,"  ");
-               }
-               if (!feof(file))
-               {
-                       F.push_back(linebuf);
-               }
-       }
-       fclose(file);
-  }
-  else
-  {
-         log(DEBUG,"readfile: failed to load file: %s",fname);
-  }
-  log(DEBUG,"readfile: loaded %s, %d lines",fname,F.size());
+       FILE* file;
+       char linebuf[MAXBUF];
+       
+       log(DEBUG,"readfile: loading %s",fname);
+       F.clear();
+       file =  fopen(fname,"r");
+       if (file)
+       {
+               while (!feof(file))
+               {
+                       fgets(linebuf,sizeof(linebuf),file);
+                       linebuf[strlen(linebuf)-1]='\0';
+                       if (!strcmp(linebuf,""))
+                       {
+                               strcpy(linebuf,"  ");
+                       }
+                       if (!feof(file))
+                       {
+                               F.push_back(linebuf);
+                       }
+               }
+               fclose(file);
+       }
+       else
+       {
+               log(DEBUG,"readfile: failed to load file: %s",fname);
+       }
+       log(DEBUG,"readfile: loaded %s, %d lines",fname,F.size());
 }
 
 void ReadConfig(void)
 {
-  char dbg[MAXBUF],pauseval[MAXBUF],Value[MAXBUF],timeout[MAXBUF],NB[MAXBUF],flood[MAXBUF];
-  ConnectClass c;
-
-  LoadConf(CONFIG_FILE,&config_f);
-  
-  ConfValue("server","name",0,ServerName,&config_f);
-  ConfValue("server","description",0,ServerDesc,&config_f);
-  ConfValue("server","network",0,Network,&config_f);
-  ConfValue("admin","name",0,AdminName,&config_f);
-  ConfValue("admin","email",0,AdminEmail,&config_f);
-  ConfValue("admin","nick",0,AdminNick,&config_f);
-  ConfValue("files","motd",0,motd,&config_f);
-  ConfValue("files","rules",0,rules,&config_f);
-  ConfValue("power","diepass",0,diepass,&config_f);
-  ConfValue("power","pause",0,pauseval,&config_f);
-  ConfValue("power","restartpass",0,restartpass,&config_f);
-  ConfValue("options","prefixquit",0,PrefixQuit,&config_f);
-  ConfValue("die","value",0,DieValue,&config_f);
-  ConfValue("options","loglevel",0,dbg,&config_f);
-  ConfValue("options","netbuffersize",0,NB,&config_f);
-  NetBufferSize = atoi(NB);
-  if ((!NetBufferSize) || (NetBufferSize > 65535) || (NetBufferSize < 1024))
-  {
-       log(DEFAULT,"No NetBufferSize specified or size out of range, setting to default of 10240.");
-       NetBufferSize = 10240;
-  }
-  if (!strcmp(dbg,"debug"))
-       LogLevel = DEBUG;
-  if (!strcmp(dbg,"verbose"))
-       LogLevel = VERBOSE;
-  if (!strcmp(dbg,"default"))
-       LogLevel = DEFAULT;
-  if (!strcmp(dbg,"sparse"))
-       LogLevel = SPARSE;
-  if (!strcmp(dbg,"none"))
-       LogLevel = NONE;
-  readfile(MOTD,motd);
-  log(DEBUG,"Reading message of the day");
-  readfile(RULES,rules);
-  log(DEBUG,"Reading connect classes");
-  Classes.clear();
-  for (int i = 0; i < ConfValueEnum("connect",&config_f); i++)
-  {
-       strcpy(Value,"");
-       ConfValue("connect","allow",i,Value,&config_f);
-       ConfValue("connect","timeout",i,timeout,&config_f);
-       ConfValue("connect","flood",i,flood,&config_f);
-       if (strcmp(Value,""))
-       {
-               strcpy(c.host,Value);
-               c.type = CC_ALLOW;
+       char dbg[MAXBUF],pauseval[MAXBUF],Value[MAXBUF],timeout[MAXBUF],NB[MAXBUF],flood[MAXBUF];
+       ConnectClass c;
+       
+       LoadConf(CONFIG_FILE,&config_f);
+         
+       ConfValue("server","name",0,ServerName,&config_f);
+       ConfValue("server","description",0,ServerDesc,&config_f);
+       ConfValue("server","network",0,Network,&config_f);
+       ConfValue("admin","name",0,AdminName,&config_f);
+       ConfValue("admin","email",0,AdminEmail,&config_f);
+       ConfValue("admin","nick",0,AdminNick,&config_f);
+       ConfValue("files","motd",0,motd,&config_f);
+       ConfValue("files","rules",0,rules,&config_f);
+       ConfValue("power","diepass",0,diepass,&config_f);
+       ConfValue("power","pause",0,pauseval,&config_f);
+       ConfValue("power","restartpass",0,restartpass,&config_f);
+       ConfValue("options","prefixquit",0,PrefixQuit,&config_f);
+       ConfValue("die","value",0,DieValue,&config_f);
+       ConfValue("options","loglevel",0,dbg,&config_f);
+       ConfValue("options","netbuffersize",0,NB,&config_f);
+       NetBufferSize = atoi(NB);
+       if ((!NetBufferSize) || (NetBufferSize > 65535) || (NetBufferSize < 1024))
+       {
+               log(DEFAULT,"No NetBufferSize specified or size out of range, setting to default of 10240.");
+               NetBufferSize = 10240;
+       }
+       if (!strcmp(dbg,"debug"))
+               LogLevel = DEBUG;
+       if (!strcmp(dbg,"verbose"))
+               LogLevel = VERBOSE;
+       if (!strcmp(dbg,"default"))
+               LogLevel = DEFAULT;
+       if (!strcmp(dbg,"sparse"))
+               LogLevel = SPARSE;
+       if (!strcmp(dbg,"none"))
+               LogLevel = NONE;
+       readfile(MOTD,motd);
+       log(DEFAULT,"Reading message of the day...");
+       readfile(RULES,rules);
+       log(DEFAULT,"Reading connect classes...");
+       Classes.clear();
+       for (int i = 0; i < ConfValueEnum("connect",&config_f); i++)
+       {
                strcpy(Value,"");
-               ConfValue("connect","password",i,Value,&config_f);
-               strcpy(c.pass,Value);
-               c.registration_timeout = 90; // default is 2 minutes
-               c.flood = atoi(flood);
-               if (atoi(timeout)>0)
+               ConfValue("connect","allow",i,Value,&config_f);
+               ConfValue("connect","timeout",i,timeout,&config_f);
+               ConfValue("connect","flood",i,flood,&config_f);
+               if (strcmp(Value,""))
+               {
+                       strcpy(c.host,Value);
+                       c.type = CC_ALLOW;
+                       strcpy(Value,"");
+                       ConfValue("connect","password",i,Value,&config_f);
+                       strcpy(c.pass,Value);
+                       c.registration_timeout = 90; // default is 2 minutes
+                       c.flood = atoi(flood);
+                       if (atoi(timeout)>0)
+                       {
+                               c.registration_timeout = atoi(timeout);
+                       }
+                       Classes.push_back(c);
+                       log(DEBUG,"Read connect class type ALLOW, host=%s password=%s timeout=%d flood=%d",c.host,c.pass,c.registration_timeout,c.flood);
+               }
+               else
                {
-                       c.registration_timeout = atoi(timeout);
+                       ConfValue("connect","deny",i,Value,&config_f);
+                       strcpy(c.host,Value);
+                       c.type = CC_DENY;
+                       Classes.push_back(c);
+                       log(DEBUG,"Read connect class type DENY, host=%s",c.host);
                }
-               Classes.push_back(c);
-               log(DEBUG,"Read connect class type ALLOW, host=%s password=%s timeout=%d flood=%d",c.host,c.pass,c.registration_timeout,c.flood);
-       }
-       else
-       {
-               ConfValue("connect","deny",i,Value,&config_f);
-                strcpy(c.host,Value);
-                c.type = CC_DENY;
-               Classes.push_back(c);
-               log(DEBUG,"Read connect class type DENY, host=%s",c.host);
-       }
        
-  }
+       }
+       log(DEFAULT,"Reading K lines,Q lines and Z lines from config...");
+       read_xline_defaults();
+       log(DEFAULT,"Applying K lines, Q lines and Z lines...");
+       apply_lines();
+       log(DEFAULT,"Done reading configuration file, InspIRCd is now running.");
 }
 
 /* write formatted text to a socket, in same format as printf */
 
 void Write(int sock,char *text, ...)
 {
-  if (!text)
-  {
-       log(DEFAULT,"*** BUG *** Write was given an invalid parameter");
-       return;
-  }
-  char textbuffer[MAXBUF];
-  va_list argsPtr;
-  char tb[MAXBUF];
-
-  va_start (argsPtr, text);
-  vsnprintf(textbuffer, MAXBUF, text, argsPtr);
-  va_end(argsPtr);
-  sprintf(tb,"%s\r\n",textbuffer);
-  chop(tb);
-  if (sock != -1)
-  {
-       write(sock,tb,strlen(tb));
-       update_stats_l(sock,strlen(tb)); /* add one line-out to stats L for this fd */
-  }
+       if (!text)
+       {
+               log(DEFAULT,"*** BUG *** Write was given an invalid parameter");
+               return;
+       }
+       char textbuffer[MAXBUF];
+       va_list argsPtr;
+       char tb[MAXBUF];
+       
+       va_start (argsPtr, text);
+       vsnprintf(textbuffer, MAXBUF, text, argsPtr);
+       va_end(argsPtr);
+       sprintf(tb,"%s\r\n",textbuffer);
+       chop(tb);
+       if (sock != -1)
+       {
+               write(sock,tb,strlen(tb));
+               update_stats_l(sock,strlen(tb)); /* add one line-out to stats L for this fd */
+       }
 }
 
 /* write a server formatted numeric response to a single socket */
 
 void WriteServ(int sock, char* text, ...)
 {
-  if (!text)
-  {
-       log(DEFAULT,"*** BUG *** WriteServ was given an invalid parameter");
-       return;
-  }
-  char textbuffer[MAXBUF],tb[MAXBUF];
-  va_list argsPtr;
-  va_start (argsPtr, text);
-
-  vsnprintf(textbuffer, MAXBUF, text, argsPtr);
-  va_end(argsPtr);
-  sprintf(tb,":%s %s\r\n",ServerName,textbuffer);
-  chop(tb);
-  if (sock != -1)
-  {
-       write(sock,tb,strlen(tb));
-       update_stats_l(sock,strlen(tb)); /* add one line-out to stats L for this fd */
-  }
+       if (!text)
+       {
+               log(DEFAULT,"*** BUG *** WriteServ was given an invalid parameter");
+               return;
+       }
+       char textbuffer[MAXBUF],tb[MAXBUF];
+       va_list argsPtr;
+       va_start (argsPtr, text);
+       
+       vsnprintf(textbuffer, MAXBUF, text, argsPtr);
+       va_end(argsPtr);
+       sprintf(tb,":%s %s\r\n",ServerName,textbuffer);
+       chop(tb);
+       if (sock != -1)
+       {
+               write(sock,tb,strlen(tb));
+               update_stats_l(sock,strlen(tb)); /* add one line-out to stats L for this fd */
+       }
 }
 
 /* write text from an originating user to originating user */
 
 void WriteFrom(int sock, userrec *user,char* text, ...)
 {
-  if ((!text) || (!user))
-  {
-       log(DEFAULT,"*** BUG *** WriteFrom was given an invalid parameter");
-       return;
-  }
-  char textbuffer[MAXBUF],tb[MAXBUF];
-  va_list argsPtr;
-  va_start (argsPtr, text);
-
-  vsnprintf(textbuffer, MAXBUF, text, argsPtr);
-  va_end(argsPtr);
-  sprintf(tb,":%s!%s@%s %s\r\n",user->nick,user->ident,user->dhost,textbuffer);
-  chop(tb);
-  if (sock != -1)
-  {
-       write(sock,tb,strlen(tb));
-       update_stats_l(sock,strlen(tb)); /* add one line-out to stats L for this fd */
-  }
+       if ((!text) || (!user))
+       {
+               log(DEFAULT,"*** BUG *** WriteFrom was given an invalid parameter");
+               return;
+       }
+       char textbuffer[MAXBUF],tb[MAXBUF];
+       va_list argsPtr;
+       va_start (argsPtr, text);
+       
+       vsnprintf(textbuffer, MAXBUF, text, argsPtr);
+       va_end(argsPtr);
+       sprintf(tb,":%s!%s@%s %s\r\n",user->nick,user->ident,user->dhost,textbuffer);
+       chop(tb);
+       if (sock != -1)
+       {
+               write(sock,tb,strlen(tb));
+               update_stats_l(sock,strlen(tb)); /* add one line-out to stats L for this fd */
+       }
 }
 
 /* write text to an destination user from a source user (e.g. user privmsg) */
@@ -1437,7 +1443,7 @@ chanrec* add_channel(userrec *user, const char* cn, const char* key, bool overri
                        {
                                // use the stamdard J token with no privilages.
                                char buffer[MAXBUF];
-                               snprintf(buffer,MAXBUF,"J %s :%s",user->nick,Ptr->name);
+                               snprintf(buffer,MAXBUF,"J %s %s",user->nick,Ptr->name);
                                NetSendToAll(buffer);
                        }
 
@@ -1567,7 +1573,7 @@ void kick_channel(userrec *src,userrec *user, chanrec *Ptr, char* reason)
                WriteServ(src->fd,"441 %s %s %s :They are not on that channel",src->nick, user->nick, Ptr->name);
                return;
        }
-       if ((cstatus(src,Ptr) < STATUS_HOP) || (cstatus(src,Ptr) < cstatus(user,Ptr)))
+       if (((cstatus(src,Ptr) < STATUS_HOP) || (cstatus(src,Ptr) < cstatus(user,Ptr))) && (!is_uline(src->server)))
        {
                if (cstatus(src,Ptr) == STATUS_HOP)
                {
@@ -1834,6 +1840,56 @@ void kill_link(userrec *user,const char* r)
        }
 }
 
+void kill_link_silent(userrec *user,const char* r)
+{
+       user_hash::iterator iter = clientlist.find(user->nick);
+       
+       char reason[MAXBUF];
+       
+       strncpy(reason,r,MAXBUF);
+
+       if (strlen(reason)>MAXQUIT)
+       {
+               reason[MAXQUIT-1] = '\0';
+       }
+
+       log(DEBUG,"kill_link: %s '%s'",user->nick,reason);
+       Write(user->fd,"ERROR :Closing link (%s@%s) [%s]",user->ident,user->host,reason);
+       log(DEBUG,"closing fd %d",user->fd);
+
+       /* bugfix, cant close() a nonblocking socket (sux!) */
+       if (user->registered == 7) {
+               FOREACH_MOD OnUserQuit(user);
+               WriteCommonExcept(user,"QUIT :%s",reason);
+
+               // Q token must go to ALL servers!!!
+               char buffer[MAXBUF];
+               snprintf(buffer,MAXBUF,"Q %s :%s",user->nick,reason);
+               NetSendToAll(buffer);
+       }
+
+       /* push the socket on a stack of sockets due to be closed at the next opportunity
+        * 'Client exited' is an exception to this as it means the client side has already
+        * closed the socket, we don't need to do it.
+        */
+       fd_reap.push_back(user->fd);
+       
+       bool do_purge = false;
+       
+       if (iter != clientlist.end())
+       {
+               log(DEBUG,"deleting user hash value %d",iter->second);
+               if ((iter->second) && (user->registered == 7)) {
+                       delete iter->second;
+               }
+               clientlist.erase(iter);
+       }
+
+       if (user->registered == 7) {
+               purge_empty_chans();
+       }
+}
+
 
 
 // looks up a users password for their connection class (<ALLOW>/<DENY> tags)
@@ -2014,7 +2070,7 @@ void AddWhoWas(userrec* u)
 
 
 /* add a client connection to the sockets list */
-void AddClient(int socket, char* host, int port, bool iscached)
+void AddClient(int socket, char* host, int port, bool iscached, char* ip)
 {
        int i;
        int blocking = 1;
@@ -2053,6 +2109,7 @@ void AddClient(int socket, char* host, int port, bool iscached)
        clientlist[tempnick]->nping = time(NULL)+240;
        clientlist[tempnick]->lastping = 1;
        clientlist[tempnick]->port = port;
+       strncpy(clientlist[tempnick]->ip,ip,32);
 
        if (iscached)
        {
@@ -2095,6 +2152,14 @@ void AddClient(int socket, char* host, int port, bool iscached)
 
        if (clientlist.size() == MAXCLIENTS)
                kill_link(clientlist[tempnick],"No more connections allowed in this class");
+               
+       char* r = matches_zline(ip);
+       if (r)
+       {
+               char reason[MAXBUF];
+               snprintf(reason,MAXBUF,"Z-Lined: %s",r);
+               kill_link(clientlist[tempnick],reason);
+       }
 }
 
 
@@ -2218,13 +2283,33 @@ void ConnectUser(userrec *user)
                return;
        }
 
+       char match_against[MAXBUF];
+       snprintf(match_against,MAXBUF,"%s@%s",user->ident,user->host);
+       char* r = matches_gline(match_against);
+       if (r)
+       {
+               char reason[MAXBUF];
+               snprintf(reason,MAXBUF,"G-Lined: %s",r);
+               kill_link_silent(user,reason);
+               return;
+       }
+
+       r = matches_kline(user->host);
+       if (r)
+       {
+               char reason[MAXBUF];
+               snprintf(reason,MAXBUF,"K-Lined: %s",r);
+               kill_link_silent(user,reason);
+               return;
+       }
+
        WriteServ(user->fd,"NOTICE Auth :Welcome to \002%s\002!",Network);
        WriteServ(user->fd,"001 %s :Welcome to the %s IRC Network %s!%s@%s",user->nick,Network,user->nick,user->ident,user->host);
        WriteServ(user->fd,"002 %s :Your host is %s, running version %s",user->nick,ServerName,VERSION);
        WriteServ(user->fd,"003 %s :This server was created %s %s",user->nick,__TIME__,__DATE__);
-       WriteServ(user->fd,"004 %s :%s %s iowghraAsORVSxNCWqBzvdHtGI lvhopsmntikrRcaqOALQbSeKVfHGCuzN",user->nick,ServerName,VERSION);
-       WriteServ(user->fd,"005 %s :MAP KNOCK SAFELIST HCN MAXCHANNELS=20 MAXBANS=60 NICKLEN=30 TOPICLEN=307 KICKLEN=307 MAXTARGETS=20 AWAYLEN=307 :are supported by this server",user->nick);
-       WriteServ(user->fd,"005 %s :WALLCHOPS WATCH=128 SILENCE=5 MODES=13 CHANTYPES=# PREFIX=(ohv)@%c+ CHANMODES=ohvbeqa,kfL,l,psmntirRcOAQKVHGCuzN NETWORK=%s :are supported by this server",user->nick,'%',Network);
+       WriteServ(user->fd,"004 %s %s %s iowghraAsORVSxNCWqBzvdHtGI lvhopsmntikrRcaqOALQbSeKVfHGCuzN",user->nick,ServerName,VERSION);
+       WriteServ(user->fd,"005 %s MAP KNOCK SAFELIST HCN MAXCHANNELS=20 MAXBANS=60 NICKLEN=30 TOPICLEN=307 KICKLEN=307 MAXTARGETS=20 AWAYLEN=307 :are supported by this server",user->nick);
+       WriteServ(user->fd,"005 %s WALLCHOPS WATCH=128 SILENCE=5 MODES=13 CHANTYPES=# PREFIX=(ohv)@%c+ CHANMODES=ohvbeqa,kfL,l,psmntirRcOAQKVHGCuzN NETWORK=%s :are supported by this server",user->nick,'%',Network);
        ShowMOTD(user);
        FOREACH_MOD OnUserConnect(user);
        WriteOpers("*** Client connecting on port %d: %s!%s@%s",user->port,user->nick,user->ident,user->host);
@@ -2356,7 +2441,20 @@ long map_count(const char* s)
 void force_nickchange(userrec* user,const char* newnick)
 {
        char nick[MAXBUF];
+       int MOD_RESULT = 0;
+       
        strcpy(nick,"");
+
+       FOREACH_RESULT(OnUserPreNick(user,newnick));
+       if (MOD_RESULT) {
+               kill_link(user,"Nickname collision");
+               return;
+       }
+       if (matches_qline(newnick))
+       {
+               kill_link(user,"Nickname collision");
+               return;
+       }
        
        if (user)
        {
@@ -2729,6 +2827,10 @@ void SetupCommandTable(void)
        createcommand("MODULES",handle_modules,'o',0);
        createcommand("LINKS",handle_links,0,0);
        createcommand("MAP",handle_map,0,0);
+       createcommand("KLINE",handle_kline,'o',1);
+       createcommand("GLINE",handle_gline,'o',1);
+       createcommand("ZLINE",handle_zline,'o',1);
+       createcommand("QLINE",handle_qline,'o',1);
 }
 
 void process_buffer(const char* cmdbuf,userrec *user)
@@ -3118,6 +3220,8 @@ int InspIRCd(void)
 #ifdef _POSIX_PRIORITY_SCHEDULING
                sched_yield();
 #endif
+               // update the status of klines, etc
+               expire_lines();
 
                fd_set sfd;
                timeval tval;
@@ -3193,9 +3297,17 @@ int InspIRCd(void)
                                                break;
                                        }
                                        // during a netburst, send all data to all other linked servers
-                                       if ((nb_start>0) && (udp_msg[0] != 'Y') && (udp_msg[0] != 'X') && (udp_msg[0] != 'F'))
+                                       if ((((nb_start>0) && (udp_msg[0] != 'Y') && (udp_msg[0] != 'X') && (udp_msg[0] != 'F'))) || (is_uline(tcp_host)))
                                        {
-                                               NetSendToAllExcept(tcp_host,udp_msg);
+                                               if (is_uline(tcp_host))
+                                               {
+                                                       if ((udp_msg[0] != 'Y') && (udp_msg[0] != 'X') && (udp_msg[0] != 'F'))
+                                                       {
+                                                               NetSendToAllExcept(tcp_host,udp_msg);
+                                                       }
+                                               }
+                                               else
+                                                       NetSendToAllExcept(tcp_host,udp_msg);
                                        }
                                        FOREACH_MOD OnPacketReceive(udp_msg);
                                        handle_link_packet(udp_msg, tcp_host, me[x]);
@@ -3431,7 +3543,7 @@ int InspIRCd(void)
                                }
                                else
                                {
-                                       AddClient(incomingSockfd, resolved, ports[count], iscached);
+                                       AddClient(incomingSockfd, resolved, ports[count], iscached, target);
                                        log(DEBUG,"InspIRCd: adding client on port %d fd=%d",ports[count],incomingSockfd);
                                }
                                goto label;