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=317a3e1a1bf99c8379cb20e83419684024c262af;hp=7dbaba86a6bc20bc70d0d59b6db9969653b234b0;hb=HEAD;hpb=48ea69d778279e7256a167e6f4147eb5766bbdda diff --git a/src/ngircd/irc-server.c b/src/ngircd/irc-server.c index 7dbaba86..6aa37574 100644 --- a/src/ngircd/irc-server.c +++ b/src/ngircd/irc-server.c @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2013 Alexander Barton (alex@barton.de) and Contributors. + * Copyright (c)2001-2024 Alexander Barton (alex@barton.de) and Contributors. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,31 +16,27 @@ * IRC commands for server links */ -#include "imp.h" #include #include #include #include #include -#include "defines.h" -#include "conn.h" #include "conn-func.h" #include "conn-zip.h" #include "conf.h" #include "channel.h" -#include "lists.h" #include "log.h" #include "messages.h" #include "parse.h" #include "numeric.h" #include "ngircd.h" +#include "irc.h" +#include "irc-channel.h" #include "irc-info.h" -#include "irc-macros.h" #include "irc-write.h" #include "op.h" -#include "exp.h" #include "irc-server.h" /** @@ -92,6 +88,19 @@ IRC_SERVER( CLIENT *Client, REQUEST *Req ) return DISCONNECTED; } +#ifdef SSL_SUPPORT + /* Does this server require an SSL connection? */ + if (Conf_Server[i].SSLConnect && + !(Conn_Options(Client_Conn(Client)) & CONN_SSL)) { + Log(LOG_ERR, + "Connection %d: Server \"%s\" requires a secure connection!", + Client_Conn(Client), Req->argv[0]); + Conn_Close(Client_Conn(Client), NULL, + "Secure connection required", true); + return DISCONNECTED; + } +#endif + /* Check server password */ if (strcmp(Conn_Password(Client_Conn(Client)), Conf_Server[i].pwd_in) != 0) { @@ -191,6 +200,15 @@ IRC_SERVER( CLIENT *Client, REQUEST *Req ) if (!Client_CheckID(Client, Req->argv[0])) return DISCONNECTED; + if (!Req->prefix) { + /* We definitely need a prefix here! */ + Log(LOG_ALERT, "Got SERVER command without prefix! (on connection %d)", + Client_Conn(Client)); + Conn_Close(Client_Conn(Client), NULL, + "SERVER command without prefix", true); + return DISCONNECTED; + } + from = Client_Search( Req->prefix ); if (! from) { /* Uh, Server, that introduced the new server is unknown?! */ @@ -251,66 +269,102 @@ IRC_NJOIN( CLIENT *Client, REQUEST *Req ) CHANNEL *chan; CLIENT *c; - assert( Client != NULL ); - assert( Req != NULL ); + assert(Client != NULL); + assert(Req != NULL); - strlcpy( nick_in, Req->argv[1], sizeof( nick_in )); - strcpy( nick_out, "" ); + strlcpy(nick_in, Req->argv[1], sizeof(nick_in)); + strcpy(nick_out, ""); channame = Req->argv[0]; - ptr = strtok( nick_in, "," ); - while( ptr ) - { + + ptr = strtok(nick_in, ","); + while (ptr) { is_owner = is_chanadmin = is_op = is_halfop = is_voiced = false; /* cut off prefixes */ - 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; + while ((*ptr == '~') || (*ptr == '&') || (*ptr == '@') || + (*ptr == '%') || (*ptr == '+')) { + if (*ptr == '~') + is_owner = true; + if (*ptr == '&') + is_chanadmin = true; + if (*ptr == '@') + is_op = true; + if (*ptr == '%') + is_halfop = true; + if (*ptr == '+') + is_voiced = true; ptr++; } - c = Client_Search( ptr ); - if( c ) - { - 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... */ - IRC_WriteStrChannelPrefix( Client, chan, c, false, "JOIN :%s", channame ); - - /* set Channel-User-Modes */ - strlcpy( modes, Channel_UserModes( chan, c ), sizeof( modes )); - if( modes[0] ) - { - /* send modes to channel */ - IRC_WriteStrChannelPrefix( Client, chan, Client, false, "MODE %s +%s %s", channame, modes, Client_ID( c )); - } + c = Client_Search(ptr); + if (!c) { + /* Client not found? */ + Log(LOG_ERR, + "Got NJOIN for unknown nick \"%s\" for channel \"%s\"!", + ptr, channame); + goto skip_njoin; + } - 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 )); + if (!Channel_Join(c, channame)) { + /* Failed to join channel. Ooops!? */ + Log(LOG_ALERT, + "Failed to join client \"%s\" to channel \"%s\" (NJOIN): killing it!", + ptr, channame); + IRC_KillClient(NULL, NULL, ptr, "Internal NJOIN error!"); + LogDebug("... done."); + goto skip_njoin; } - else Log( LOG_ERR, "Got NJOIN for unknown nick \"%s\" for channel \"%s\"!", ptr, channame ); - /* search for next Nick */ - ptr = strtok( NULL, "," ); + 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 client to the channel */ + IRC_WriteStrChannelPrefix(Client, chan, c, false, + "JOIN :%s", channame); + + /* If the client is connected to this server, it was remotely + * joined to the channel by another server/service: So send + * TOPIC and NAMES messages like on a regular JOIN command! */ + if(Client_Conn(c) != NONE) + IRC_Send_Channel_Info(c, chan); + + /* Announce "channel user modes" to the channel, if any */ + strlcpy(modes, Channel_UserModes(chan, c), sizeof(modes)); + if (modes[0]) + IRC_WriteStrChannelPrefix(Client, chan, Client, false, + "MODE %s +%s %s", channame, + modes, Client_ID(c)); + + /* Build nick list for forwarding command */ + 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)); + + skip_njoin: + /* Get next nick, if any ... */ + ptr = strtok(NULL, ","); } /* forward to other servers */ @@ -333,7 +387,7 @@ IRC_SQUIT(CLIENT * Client, REQUEST * Req) { char msg[COMMAND_LEN], logmsg[COMMAND_LEN]; CLIENT *from, *target; - CONN_ID con; + CONN_ID con, client_con; int loglevel; assert(Client != NULL); @@ -373,6 +427,7 @@ IRC_SQUIT(CLIENT * Client, REQUEST * Req) return CONNECTED; } + client_con = Client_Conn(Client); con = Client_Conn(target); if (Req->argv[1][0]) @@ -394,7 +449,7 @@ IRC_SQUIT(CLIENT * Client, REQUEST * Req) Req->argv[0], Client_ID(from), Req->argv[1][0] ? Req->argv[1] : "-"); Conn_Close(con, NULL, msg, true); - if (con == Client_Conn(Client)) + if (con == client_con) return DISCONNECTED; } else { /* This server is not directly connected, so the SQUIT must