X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=ngircd-alex.git;a=blobdiff_plain;f=src%2Fngircd%2Firc-server.c;h=0a9e930d816f696b5fc784fa6857c063fbf49744;hp=b75a34f9834abf6267d5ebb60faae753cff51a17;hb=d38d153f;hpb=bce16c2864309d5fc7da8d0591120466303aa966 diff --git a/src/ngircd/irc-server.c b/src/ngircd/irc-server.c index b75a34f9..0a9e930d 100644 --- a/src/ngircd/irc-server.c +++ b/src/ngircd/irc-server.c @@ -7,13 +7,15 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * Please read the file COPYING, README and AUTHORS for more information. - * - * IRC commands for server links */ - #include "portab.h" +/** + * @file + * IRC commands for server links + */ + #include "imp.h" #include #include @@ -22,12 +24,10 @@ #include #include "defines.h" -#include "resolve.h" #include "conn.h" #include "conn-func.h" #include "conn-zip.h" #include "conf.h" -#include "client.h" #include "channel.h" #include "irc-write.h" #include "lists.h" @@ -37,6 +37,7 @@ #include "numeric.h" #include "ngircd.h" #include "irc-info.h" +#include "op.h" #include "exp.h" #include "irc-server.h" @@ -52,8 +53,7 @@ IRC_SERVER( CLIENT *Client, REQUEST *Req ) char str[LINE_LEN]; CLIENT *from, *c; int i; - CONN_ID con; - + assert( Client != NULL ); assert( Req != NULL ); @@ -69,26 +69,44 @@ IRC_SERVER( CLIENT *Client, REQUEST *Req ) LogDebug("Connection %d: got SERVER command (new server link) ...", Client_Conn(Client)); - if(( Req->argc != 2 ) && ( Req->argc != 3 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command ); - - /* Ist this server configured on out side? */ - for( i = 0; i < MAX_SERVERS; i++ ) if( strcasecmp( Req->argv[0], Conf_Server[i].name ) == 0 ) break; - if( i >= MAX_SERVERS ) - { - Log( LOG_ERR, "Connection %d: Server \"%s\" not configured here!", Client_Conn( Client ), Req->argv[0] ); - Conn_Close( Client_Conn( Client ), NULL, "Server not configured here", true); + if (Req->argc != 2 && Req->argc != 3) + return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, + Client_ID(Client), + Req->command); + + /* Get configuration index of new remote server ... */ + for (i = 0; i < MAX_SERVERS; i++) + if (strcasecmp(Req->argv[0], Conf_Server[i].name) == 0) + break; + + /* Makre sure the remote server is configured here */ + if (i >= MAX_SERVERS) { + Log(LOG_ERR, + "Connection %d: Server \"%s\" not configured here!", + Client_Conn(Client), Req->argv[0]); + Conn_Close(Client_Conn(Client), NULL, + "Server not configured here", true); return DISCONNECTED; } - if( strcmp( Client_Password( Client ), Conf_Server[i].pwd_in ) != 0 ) - { - /* wrong password */ - Log( LOG_ERR, "Connection %d: Got bad password from server \"%s\"!", Client_Conn( Client ), Req->argv[0] ); - Conn_Close( Client_Conn( Client ), NULL, "Bad password", true); + + /* Check server password */ + if (strcmp(Conn_Password(Client_Conn(Client)), + Conf_Server[i].pwd_in) != 0) { + Log(LOG_ERR, + "Connection %d: Got bad password from server \"%s\"!", + Client_Conn(Client), Req->argv[0]); + Conn_Close(Client_Conn(Client), NULL, + "Bad password", true); return DISCONNECTED; } - + /* Is there a registered server with this ID? */ - if( ! Client_CheckID( Client, Req->argv[0] )) return DISCONNECTED; + if (!Client_CheckID(Client, Req->argv[0])) + return DISCONNECTED; + + /* Mark this connection as belonging to an configured server */ + if (!Conf_SetServer(i, Client_Conn(Client))) + return DISCONNECTED; Client_SetID( Client, Req->argv[0] ); Client_SetHops( Client, 1 ); @@ -96,7 +114,6 @@ IRC_SERVER( CLIENT *Client, REQUEST *Req ) /* Is this server registering on our side, or are we connecting to * a remote server? */ - con = Client_Conn(Client); if (Client_Token(Client) != TOKEN_OUTBOUND) { /* Incoming connection, send user/pass */ if (!IRC_WriteStrClient(Client, "PASS %s %s", @@ -105,7 +122,8 @@ IRC_SERVER( CLIENT *Client, REQUEST *Req ) || !IRC_WriteStrClient(Client, "SERVER %s 1 :%s", Conf_ServerName, Conf_ServerInfo)) { - Conn_Close(con, "Unexpected server behavior!", + Conn_Close(Client_Conn(Client), + "Unexpected server behavior!", NULL, false); return DISCONNECTED; } @@ -117,25 +135,25 @@ IRC_SERVER( CLIENT *Client, REQUEST *Req ) Client_SetToken(Client, atoi(Req->argv[1])); } - /* Mark this connection as belonging to an configured server */ - Conf_SetServer(i, con); - /* Check protocol level */ if (Client_Type(Client) == CLIENT_GOTPASS) { /* We got a "simple" PASS command, so the peer is * using the protocol as defined in RFC 1459. */ - if (! (Conn_Options(con) & CONN_RFC1459)) + if (! (Conn_Options(Client_Conn(Client)) & CONN_RFC1459)) Log(LOG_INFO, "Switching connection %d (\"%s\") to RFC 1459 compatibility mode.", - con, Client_ID(Client)); - Conn_SetOption(con, CONN_RFC1459); + Client_Conn(Client), Client_ID(Client)); + Conn_SetOption(Client_Conn(Client), CONN_RFC1459); } Client_SetType(Client, CLIENT_UNKNOWNSERVER); #ifdef ZLIB - if (strchr(Client_Flags(Client), 'Z') && !Zip_InitConn(con)) { - Conn_Close( con, "Can't inizialize compression (zlib)!", NULL, false ); + if (strchr(Client_Flags(Client), 'Z') + && !Zip_InitConn(Client_Conn(Client))) { + Conn_Close(Client_Conn(Client), + "Can't inizialize compression (zlib)!", + NULL, false ); return DISCONNECTED; } #endif @@ -201,10 +219,10 @@ GLOBAL bool IRC_NJOIN( CLIENT *Client, REQUEST *Req ) { char nick_in[COMMAND_LEN], nick_out[COMMAND_LEN], *channame, *ptr, modes[8]; - bool is_op, is_voiced; + bool is_owner, is_chanadmin, is_op, is_halfop, is_voiced; CHANNEL *chan; CLIENT *c; - + assert( Client != NULL ); assert( Req != NULL ); @@ -217,12 +235,16 @@ IRC_NJOIN( CLIENT *Client, REQUEST *Req ) ptr = strtok( nick_in, "," ); while( ptr ) { - is_op = is_voiced = false; - + is_owner = is_chanadmin = is_op = is_halfop = is_voiced = false; + /* cut off prefixes */ - while(( *ptr == '@' ) || ( *ptr == '+' )) + while(( *ptr == '~') || ( *ptr == '&' ) || ( *ptr == '@' ) || + ( *ptr == '%') || ( *ptr == '+' )) { + if( *ptr == '~' ) is_owner = true; + if( *ptr == '&' ) is_chanadmin = true; if( *ptr == '@' ) is_op = true; + if( *ptr == 'h' ) is_halfop = true; if( *ptr == '+' ) is_voiced = true; ptr++; } @@ -233,8 +255,11 @@ IRC_NJOIN( CLIENT *Client, REQUEST *Req ) Channel_Join( c, channame ); chan = Channel_Search( channame ); assert( chan != NULL ); - + + if( is_owner ) Channel_UserModeAdd( chan, c, 'q' ); + if( is_chanadmin ) Channel_UserModeAdd( chan, c, 'a' ); if( is_op ) Channel_UserModeAdd( chan, c, 'o' ); + if( is_halfop ) Channel_UserModeAdd( chan, c, 'h' ); if( is_voiced ) Channel_UserModeAdd( chan, c, 'v' ); /* announce to channel... */ @@ -249,12 +274,15 @@ IRC_NJOIN( CLIENT *Client, REQUEST *Req ) } if( nick_out[0] != '\0' ) strlcat( nick_out, ",", sizeof( nick_out )); + if( is_owner ) strlcat( nick_out, "~", sizeof( nick_out )); + if( is_chanadmin ) strlcat( nick_out, "&", sizeof( nick_out )); if( is_op ) strlcat( nick_out, "@", sizeof( nick_out )); + if( is_halfop ) strlcat( nick_out, "%", sizeof( nick_out )); if( is_voiced ) strlcat( nick_out, "+", sizeof( nick_out )); strlcat( nick_out, ptr, sizeof( nick_out )); } else Log( LOG_ERR, "Got NJOIN for unknown nick \"%s\" for channel \"%s\"!", ptr, channame ); - + /* search for next Nick */ ptr = strtok( NULL, "," ); } @@ -273,21 +301,45 @@ IRC_NJOIN( CLIENT *Client, REQUEST *Req ) GLOBAL bool IRC_SQUIT(CLIENT * Client, REQUEST * Req) { - CLIENT *target; - char msg[LINE_LEN + 64]; + char msg[COMMAND_LEN], logmsg[COMMAND_LEN]; + CLIENT *from, *target; + CONN_ID con; + int loglevel; assert(Client != NULL); assert(Req != NULL); + if (Client_Type(Client) != CLIENT_SERVER + && !Client_HasMode(Client, 'o')) + return Op_NoPrivileges(Client, Req); + /* Bad number of arguments? */ if (Req->argc != 2) return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, Client_ID(Client), Req->command); - Log(LOG_DEBUG, "Got SQUIT from %s for \"%s\": \"%s\" ...", - Client_ID(Client), Req->argv[0], Req->argv[1]); + if (Client_Type(Client) == CLIENT_SERVER && Req->prefix) { + from = Client_Search(Req->prefix); + if (Client_Type(from) != CLIENT_SERVER + && !Op_Check(Client, Req)) + return Op_NoPrivileges(Client, Req); + } else + from = Client; + if (!from) + return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG, + Client_ID(Client), Req->prefix); + + if (Client_Type(Client) == CLIENT_USER) + loglevel = LOG_NOTICE | LOG_snotice; + else + loglevel = LOG_DEBUG; + Log(loglevel, "Got SQUIT from %s for \"%s\": \"%s\" ...", + Client_ID(from), Req->argv[0], Req->argv[1]); target = Client_Search(Req->argv[0]); + if (Client_Type(Client) != CLIENT_SERVER && + target == Client_ThisServer()) + return Op_NoPrivileges(Client, Req); if (!target) { /* The server is (already) unknown */ Log(LOG_WARNING, @@ -296,27 +348,50 @@ IRC_SQUIT(CLIENT * Client, REQUEST * Req) return CONNECTED; } - if (Req->argv[1][0]) { - if (strlen(Req->argv[1]) > LINE_LEN) - Req->argv[1][LINE_LEN] = '\0'; - snprintf(msg, sizeof(msg), "%s (SQUIT from %s).", Req->argv[1], - Client_ID(Client)); - } else - snprintf(msg, sizeof(msg), "Got SQUIT from %s.", - Client_ID(Client)); - - if (Client_Conn(target) > NONE) { - /* We are directly connected to this server */ - if (Req->argv[1][0]) - Conn_Close(Client_Conn(target), msg, Req->argv[1], - true); + con = Client_Conn(target); + + if (Req->argv[1][0]) + if (Client_NextHop(from) != Client || con > NONE) + snprintf(msg, sizeof(msg), "\"%s\" (SQUIT from %s)", + Req->argv[1], Client_ID(from)); else - Conn_Close(Client_Conn(target), msg, NULL, true); - return DISCONNECTED; + strlcpy(msg, Req->argv[1], sizeof(msg)); + else + snprintf(msg, sizeof(msg), "Got SQUIT from %s", + Client_ID(from)); + + if (con > NONE) { + /* We are directly connected to the target server, so we + * have to tear down the connection and to inform all the + * other remaining servers in the network */ + IRC_SendWallops(Client_ThisServer(), Client_ThisServer(), + "Received SQUIT %s from %s: %s", + Req->argv[0], Client_ID(from), + Req->argv[1][0] ? Req->argv[1] : "-"); + Conn_Close(con, NULL, msg, true); + if (con == Client_Conn(Client)) + return DISCONNECTED; } else { - Client_Destroy(target, msg, Req->argv[1], false); - return CONNECTED; + /* This server is not directly connected, so the SQUIT must + * be forwarded ... */ + if (Client_Type(from) != CLIENT_SERVER) { + /* The origin is not an IRC server, so don't evaluate + * this SQUIT but simply forward it */ + IRC_WriteStrClientPrefix(Client_NextHop(target), + from, "SQUIT %s :%s", Req->argv[0], Req->argv[1]); + } else { + /* SQUIT has been generated by another server, so + * remove the target server from the network! */ + logmsg[0] = '\0'; + if (!strchr(msg, '(')) + snprintf(logmsg, sizeof(logmsg), + "\"%s\" (SQUIT from %s)", Req->argv[1], + Client_ID(from)); + Client_Destroy(target, logmsg[0] ? logmsg : msg, + msg, false); + } } + return CONNECTED; } /* IRC_SQUIT */ /* -eof- */