ChangeLog | 26 +++ NEWS | 17 ++- README | 4 +- configure.in | 9 +- contrib/Debian/changelog | 6 + contrib/MacOSX/config.h | 2 + contrib/MacOSX/ngIRCd.xcodeproj/project.pbxproj | 2 +- contrib/ngircd.spec | 2 +- contrib/platformtest.sh | 2 +- doc/Platforms.txt | 2 + doc/README-Interix.txt | 37 ++++ doc/sample-ngircd.conf | 10 +- man/ngircd.conf.5.tmpl | 9 + src/ngircd/client.c | 41 +++-- src/ngircd/conf.c | 131 ++++++++----- src/ngircd/conf.h | 15 +- src/ngircd/conn.c | 236 +++++++++++++++------- src/ngircd/conn.h | 2 +- src/ngircd/defines.h | 10 +- src/ngircd/irc-channel.c | 84 ++++++--- src/ngircd/irc-info.c | 131 ++++++++------ src/ngircd/irc-login.c | 27 +++- src/ngircd/irc-login.h | 3 +- src/ngircd/irc-mode.c | 3 +- src/ngircd/irc-oper.c | 21 +- src/ngircd/irc.c | 8 +- src/ngircd/messages.h | 5 +- src/ngircd/parse.c | 3 +- src/ngircd/resolve.c | 2 +- 29 files changed, 579 insertions(+), 271 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9b38170..878eb25 100644 --- a/ChangeLog +++ b/ChangeLog @@ -10,6 +10,32 @@ -- ChangeLog -- +ngIRCd Release 16 + + ngIRCd 16~rc1 (2010-03-25) + - Various fixes to the build system and code cleanups. + - contrib/platformtest.sh: Only show latest commit. + - Updatet doc/Platforms.txt, added new README-Interix.txt documenting + how to tun ngIRCd on Microsoft Services for UNIX (MS SFU, MS SUA). + - Updated links to the ngIRCd homepage (bug tracker, mailing list). + - Added missing modes to USERMODES #define + - Show our name (IRCD=ngIRCd) in ISUPPORT (005) numeric + - Quote received messages of ERROR commands in log output. + - ngircd.conf manual page: document missing "Password" variable. + - Implement WEBIRC command used by some Web-IRC frontends. The password + required to secure this command must be configured using the new + "WebircPassword" variable in the ngircd.conf file. + - Don't use port 6668 as example for both "Ports" and "SSLPorts". + - Remove limit on max number of configured irc operators. + - Only link "nsl" library when really needed. + - A new channel mode "secure connections only" (+z) has been implemented: + Only clients using a SSL encrypted connection to the server are allowed + to join such a channel. + But please note three things: a) already joined clients are not checked + when setting this mode, b) IRC operators are always allowed to join + every channel, and c) remote clients using a server not supporting this + mode are not checked either and therefore always allowed to join. + ngIRCd Release 15 (2009-11-07) - "ngircd --configtest": print SSL configuration options even when unset. diff --git a/NEWS b/NEWS index 5a0a9dd..7c6f948 100644 --- a/NEWS +++ b/NEWS @@ -1,7 +1,7 @@ ngIRCd - Next Generation IRC Server - (c)2001-2009 Alexander Barton, + (c)2001-2010 Alexander Barton, alex@barton.de, http://www.barton.de/ ngIRCd is free software and published under the @@ -10,6 +10,21 @@ -- NEWS -- +ngIRCd Release 16 + + ngIRCd 16~rc1 (2010-03-25) + - Implement WEBIRC command used by some Web-IRC frontends. The password + required to secure this command must be configured using the new + "WebircPassword" variable in the ngircd.conf file. + - Remove limit on max number of configured irc operators. + - A new channel mode "secure connections only" (+z) has been implemented: + Only clients using a SSL encrypted connection to the server are allowed + to join such a channel. + But please note three things: a) already joined clients are not checked + when setting this mode, b) IRC operators are always allowed to join + every channel, and c) remote clients using a server not supporting this + mode are not checked either and therefore always allowed to join. + ngIRCd Release 15 (2009-11-07) ngIRCd 15~rc1 (2009-10-15) diff --git a/README b/README index 2eff7bc..dc11a9f 100644 --- a/README +++ b/README @@ -78,10 +78,10 @@ VI. Bugs If you find bugs in the ngIRCd (which might be there :-), please report them at the following URL: - + There you can read about known bugs and limitations, too. If you have critics, patches or something else, please feel free to post a mail to the ngIRCd mailing list: (please see - for details). + for details). diff --git a/configure.in b/configure.in index 3d4c640..153ec57 100644 --- a/configure.in +++ b/configure.in @@ -12,7 +12,7 @@ # -- Initialisation -- AC_PREREQ(2.50) -AC_INIT(ngircd, 15) +AC_INIT(ngircd, 16~rc1) AC_CONFIG_SRCDIR(src/ngircd/ngircd.c) AC_CANONICAL_TARGET AM_INIT_AUTOMAKE(1.6) @@ -105,7 +105,8 @@ AC_CHECK_HEADERS([ \ strings.h sys/socket.h sys/time.h unistd.h \ ],,AC_MSG_ERROR([required C header missing!])) -AC_CHECK_HEADERS([arpa/inet.h ctype.h malloc.h stdbool.h stddef.h varargs.h]) +AC_CHECK_HEADERS([ \ + arpa/inet.h ctype.h malloc.h netinet/ip.h stdbool.h stddef.h varargs.h]) # -- Datatypes -- @@ -130,9 +131,11 @@ AC_CHECK_MEMBER([struct sockaddr_in.sin_len], AC_DEFINE(HAVE_sockaddr_in_len),, # -- Libraries -- +# A/UX needs this. AC_CHECK_LIB(UTIL,memmove) +# needed on solaris. GNU libc also has a libnsl, but we do not need it. +AC_SEARCH_LIBS(gethostbyname,nsl) AC_CHECK_LIB(socket,bind) -AC_CHECK_LIB(nsl,gethostent) # -- Functions -- diff --git a/contrib/Debian/changelog b/contrib/Debian/changelog index 0f76b3d..4bab648 100644 --- a/contrib/Debian/changelog +++ b/contrib/Debian/changelog @@ -1,3 +1,9 @@ +ngircd (16~rc1-0ab1) unstable; urgency=low + + * New "upstream" release candidate 1 for ngIRCd Release 16. + + -- Alexander Barton Thu, 25 Mar 2010 15:56:03 +0100 + ngircd (15-0ab1) unstable; urgency=low * New "upstream" release: ngIRCd 15. diff --git a/contrib/MacOSX/config.h b/contrib/MacOSX/config.h index 60b0618..66465e2 100644 --- a/contrib/MacOSX/config.h +++ b/contrib/MacOSX/config.h @@ -71,6 +71,8 @@ #define HAVE_STDBOOL_H 1 /* Define to 1 if you have the header file. */ #define HAVE_ARPA_INET_H 1 +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_IP_H 1 /* Define to 1 if you have the `kqueue' function. */ #define HAVE_KQUEUE 1 diff --git a/contrib/MacOSX/ngIRCd.xcodeproj/project.pbxproj b/contrib/MacOSX/ngIRCd.xcodeproj/project.pbxproj index a7cc74f..3d9dfe7 100644 --- a/contrib/MacOSX/ngIRCd.xcodeproj/project.pbxproj +++ b/contrib/MacOSX/ngIRCd.xcodeproj/project.pbxproj @@ -758,7 +758,7 @@ GCC_WARN_SHADOW = YES; GCC_WARN_SIGN_COMPARE = YES; GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNINITIALIZED_AUTOS = NO; GCC_WARN_UNKNOWN_PRAGMAS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_LABEL = YES; diff --git a/contrib/ngircd.spec b/contrib/ngircd.spec index bce620a..d83ff70 100644 --- a/contrib/ngircd.spec +++ b/contrib/ngircd.spec @@ -1,5 +1,5 @@ %define name ngircd -%define version 15 +%define version 16~rc1 %define release 1 %define prefix %{_prefix} diff --git a/contrib/platformtest.sh b/contrib/platformtest.sh index aee7f29..0a518b8 100755 --- a/contrib/platformtest.sh +++ b/contrib/platformtest.sh @@ -105,7 +105,7 @@ fi # Get ngIRCd version information if [ -d ".git" ]; then VERSION=`git log --abbrev-commit --pretty=oneline HEAD~1.. \ - | cut -d' ' -f1 | tr -d '.'` + | head -1 | cut -d' ' -f1 | tr -d '.'` elif [ -r "Makefile" ]; then eval $(grep "^VERSION = " Makefile | sed -e 's/ //g') fi diff --git a/doc/Platforms.txt b/doc/Platforms.txt index 8a1282e..8629252 100644 --- a/doc/Platforms.txt +++ b/doc/Platforms.txt @@ -43,11 +43,13 @@ i386/unknown/freebsd7.0 gcc 4.2.1 14.1 09-07-28 alex Y Y Y Y (3) i386/unknown/freebsd7.2 gcc 4.2.1 14.1 09-08-03 alex Y Y Y Y (3) i386/unknown/gnu0.3 gcc 3.3.3 0.8.0 04-05-30 alex Y Y n Y i686/unknown/gnu0.3 gcc 4.3.1 14.1 09-07-28 alex Y Y Y Y +i686/unkn./kfreebsd7.2-gnu gcc 4.3.4 15 09-12-02 alex Y Y Y Y (3) i386/unknown/netbsdelf1.6.1 gcc 2.95.3 CVSHEAD 04-02-24 alex Y Y Y Y i386/unknown/netbsdelf3.0.1 gcc 3.3.3 0.10.0-p1 06-08-30 alex Y Y Y Y (3) i386/unknown/netbsdelf4.0 gcc 4.1.2 14.1 09-07-28 alex Y Y Y Y (3) i386/unknown/openbsd3.9 gcc 3.3.5 0.10.0-p1 06-08-30 alex Y Y Y Y (3) i386/unknown/openbsd4.1 gcc 3.3.5 14.1 09-07-28 alex Y Y Y Y (3) +i586/pc/interix3.5 gcc 3.3 15 10-01-22 alex Y Y N Y i686/pc/cygwin gcc 3.3.1 0.8.0 04-05-30 alex Y Y n Y i686/pc/linux-gnu gcc 2.95.4 0.8.0 04-05-30 alex Y Y Y Y (1) i686/pc/linux-gnu gcc 3.3.5 14.1 09-08-04 alex Y Y Y Y (1) diff --git a/doc/README-Interix.txt b/doc/README-Interix.txt new file mode 100644 index 0000000..8f5451f --- /dev/null +++ b/doc/README-Interix.txt @@ -0,0 +1,37 @@ + + ngIRCd - Next Generation IRC Server + + (c)2001-2010 Alexander Barton, + alex@barton.de, http://www.barton.de/ + + ngIRCd is free software and published under the + terms of the GNU General Public License. + + + -- README-Interix.txt -- + + +ngIRCd release 15 has successfully been tested on Microsoft Windows XP +Professional using the Services for UNIX (SFU) version 3.5 and Microsoft +Windows 7 with the bundled Subsystem for UNIX Applications (SUA). + +SFU are supported on Windows 2000, Windows 2000 Server, Windows XP, and +Windows Server 2003. SUA is supported on Windows Server 2003 R2, Windows +Server 2008 & 2008 R2, Windows Vista, and Windows 7 -- so ngIRCd should be +able to run on all of these platforms. + +But please note that the poll() API function is not fully implemented by +SFU/SUA and therefore can't be used by ngIRCd -- which normally would be +the default. Please see section +4.25 for details: + + "If you do try to use the poll() API your program will block on the + API call forever. You must direct your program to build using the + select() API." + +So when running the ./configure script, you HAVE TO DISABLE poll() support: + + ./configure --without-poll + +ngIRCd then defaults to using the select() API function which works fine. + diff --git a/doc/sample-ngircd.conf b/doc/sample-ngircd.conf index b945224..daa0801 100644 --- a/doc/sample-ngircd.conf +++ b/doc/sample-ngircd.conf @@ -28,9 +28,15 @@ # LINKS requests for example. Info = Server Info Text - # Global password for all users needed to connect to the server + # Global password for all users needed to connect to the server. + # (Default: not set) ;Password = abc + # Password required for using the WEBIRC command used by some + # Web-to-IRC gateways. If not set/empty, the WEBIRC command can't + # be used. (Default: not set) + ;WebircPassword = xyz + # Information about the server and the administrator, used by the # ADMIN command. Not required by server but by RFC! ;AdminInfo1 = Description @@ -42,7 +48,7 @@ ;Ports = 6667, 6668, 6669 # Additional Listen Ports that expect SSL/TLS encrypted connections - ;SSLPorts = 9999,6668 + ;SSLPorts = 6697, 9999 # SSL Server Key ;SSLKeyFile = /usr/local/etc/ngircd/ssl/server-key.pem diff --git a/man/ngircd.conf.5.tmpl b/man/ngircd.conf.5.tmpl index d9e6f46..46e0308 100644 --- a/man/ngircd.conf.5.tmpl +++ b/man/ngircd.conf.5.tmpl @@ -69,6 +69,15 @@ IRC network and must contain at least one dot (".") character. Info text of the server. This will be shown by WHOIS and LINKS requests for example. .TP +\fBPassword\fR +Global password for all users needed to connect to the server. The default +is empty, so no password is required. +.TP +\fBWebircPassword\fR +Password required for using the WEBIRC command used by some Web-to-IRC +gateways. If not set or empty, the WEBIRC command can't be used. +Default: not set. +.TP \fBAdminInfo1\fR, \fBAdminInfo2\fR, \fBAdminEMail\fR Information about the server and the administrator, used by the ADMIN command. diff --git a/src/ngircd/client.c b/src/ngircd/client.c index 1edc755..c565830 100644 --- a/src/ngircd/client.c +++ b/src/ngircd/client.c @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2008 Alexander Barton (alex@barton.de) + * Copyright (c)2001-2010 Alexander Barton (alex@barton.de) * * 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 @@ -181,39 +181,46 @@ Client_NewRemoteUser(CLIENT *Introducer, const char *Nick, int Hops, const char */ static CLIENT * Init_New_Client(CONN_ID Idx, CLIENT *Introducer, CLIENT *TopServer, - int Type, const char *ID, const char *User, const char *Hostname, const char *Info, int Hops, - int Token, const char *Modes, bool Idented) + int Type, const char *ID, const char *User, const char *Hostname, + const char *Info, int Hops, int Token, const char *Modes, bool Idented) { CLIENT *client; - assert( Idx >= NONE ); - assert( Introducer != NULL ); - assert( Hostname != NULL ); + assert(Idx >= NONE); + assert(Introducer != NULL); + assert(Hostname != NULL); - client = New_Client_Struct( ); - if( ! client ) return NULL; + client = New_Client_Struct(); + if (!client) + return NULL; client->starttime = time(NULL); client->conn_id = Idx; client->introducer = Introducer; client->topserver = TopServer; client->type = Type; - if( ID ) Client_SetID( client, ID ); - if( User ) Client_SetUser( client, User, Idented ); - if( Hostname ) Client_SetHostname( client, Hostname ); - if( Info ) Client_SetInfo( client, Info ); + if (ID) + Client_SetID(client, ID); + if (User) + Client_SetUser(client, User, Idented); + if (Hostname) + Client_SetHostname(client, Hostname); + if (Info) + Client_SetInfo(client, Info); client->hops = Hops; client->token = Token; - if( Modes ) Client_SetModes( client, Modes ); - if( Type == CLIENT_SERVER ) Generate_MyToken( client ); + if (Modes) + Client_SetModes(client, Modes); + if (Type == CLIENT_SERVER) + Generate_MyToken(client); - if( strchr( client->modes, 'a' )) - strlcpy( client->away, DEFAULT_AWAY_MSG, sizeof( client->away )); + if (strchr(client->modes, 'a')) + strlcpy(client->away, DEFAULT_AWAY_MSG, sizeof(client->away)); client->next = (POINTER *)My_Clients; My_Clients = client; - Adjust_Counters( client ); + Adjust_Counters(client); return client; } /* Init_New_Client */ diff --git a/src/ngircd/conf.c b/src/ngircd/conf.c index 2b592b1..694b5d4 100644 --- a/src/ngircd/conf.c +++ b/src/ngircd/conf.c @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2009 Alexander Barton (alex@barton.de) + * Copyright (c)2001-2010 Alexander Barton (alex@barton.de) * * 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 @@ -55,6 +55,7 @@ static bool Use_Log = true; static CONF_SERVER New_Server; static int New_Server_Idx; +static size_t Conf_Oper_Count; static size_t Conf_Channel_Count; static void Set_Defaults PARAMS(( bool InitServers )); static bool Read_Config PARAMS(( bool ngircd_starting )); @@ -226,6 +227,41 @@ yesno_to_str(int boolean_value) } +static void +opers_free(void) +{ + struct Conf_Oper *op; + size_t len; + + len = array_length(&Conf_Opers, sizeof(*op)); + op = array_start(&Conf_Opers); + while (len--) { + free(op->mask); + op++; + } + array_free(&Conf_Opers); +} + +static void +opers_puts(void) +{ + struct Conf_Oper *op; + size_t len; + + len = array_length(&Conf_Opers, sizeof(*op)); + op = array_start(&Conf_Opers); + while (len--) { + assert(op->name[0]); + + puts("[OPERATOR]"); + printf(" Name = %s\n", op->name); + printf(" Password = %s\n", op->pwd); + printf(" Mask = %s\n\n", op->mask ? op->mask : ""); + op++; + } +} + + GLOBAL int Conf_Test( void ) { @@ -255,16 +291,17 @@ Conf_Test( void ) } puts( "[GLOBAL]" ); - printf( " Name = %s\n", Conf_ServerName ); - printf( " Info = %s\n", Conf_ServerInfo ); - printf( " Password = %s\n", Conf_ServerPwd ); - printf( " AdminInfo1 = %s\n", Conf_ServerAdmin1 ); - printf( " AdminInfo2 = %s\n", Conf_ServerAdmin2 ); - printf( " AdminEMail = %s\n", Conf_ServerAdminMail ); - printf( " MotdFile = %s\n", Conf_MotdFile ); - printf( " MotdPhrase = %s\n", Conf_MotdPhrase ); - printf( " ChrootDir = %s\n", Conf_Chroot ); - printf( " PidFile = %s\n", Conf_PidFile); + printf(" Name = %s\n", Conf_ServerName); + printf(" Info = %s\n", Conf_ServerInfo); + printf(" Password = %s\n", Conf_ServerPwd); + printf(" WebircPassword = %s\n", Conf_WebircPwd); + printf(" AdminInfo1 = %s\n", Conf_ServerAdmin1); + printf(" AdminInfo2 = %s\n", Conf_ServerAdmin2); + printf(" AdminEMail = %s\n", Conf_ServerAdminMail); + printf(" MotdFile = %s\n", Conf_MotdFile); + printf(" MotdPhrase = %s\n", Conf_MotdPhrase); + printf(" ChrootDir = %s\n", Conf_Chroot); + printf(" PidFile = %s\n", Conf_PidFile); printf(" Listen = %s\n", Conf_ListenAddress); fputs(" Ports = ", stdout); ports_puts(&Conf_ListenPorts); @@ -304,16 +341,7 @@ Conf_Test( void ) printf(" MaxJoins = %d\n", Conf_MaxJoins > 0 ? Conf_MaxJoins : -1); printf(" MaxNickLength = %u\n\n", Conf_MaxNickLength - 1); - for( i = 0; i < Conf_Oper_Count; i++ ) { - if( ! Conf_Oper[i].name[0] ) continue; - - /* Valid "Operator" section */ - puts( "[OPERATOR]" ); - printf( " Name = %s\n", Conf_Oper[i].name ); - printf( " Password = %s\n", Conf_Oper[i].pwd ); - if ( Conf_Oper[i].mask ) printf( " Mask = %s\n", Conf_Oper[i].mask ); - puts( "" ); - } + opers_puts(); for( i = 0; i < MAX_SERVERS; i++ ) { if( ! Conf_Server[i].name[0] ) continue; @@ -609,6 +637,7 @@ Read_Config( bool ngircd_starting ) exit( 1 ); } + opers_free(); Set_Defaults( ngircd_starting ); Config_Error( LOG_INFO, "Reading configuration from \"%s\" ...", NGIRCd_ConfFile ); @@ -667,21 +696,6 @@ Read_Config( bool ngircd_starting ) if( strcasecmp( section, "[GLOBAL]" ) == 0 ) continue; - if( strcasecmp( section, "[OPERATOR]" ) == 0 ) { - if( Conf_Oper_Count + 1 > MAX_OPERATORS ) - Config_Error( LOG_ERR, "Too many operators configured."); - else { - /* Initialize new operator structure */ - Conf_Oper[Conf_Oper_Count].name[0] = '\0'; - Conf_Oper[Conf_Oper_Count].pwd[0] = '\0'; - if (Conf_Oper[Conf_Oper_Count].mask) { - free(Conf_Oper[Conf_Oper_Count].mask ); - Conf_Oper[Conf_Oper_Count].mask = NULL; - } - Conf_Oper_Count++; - } - continue; - } if( strcasecmp( section, "[SERVER]" ) == 0 ) { /* Check if there is already a server to add */ if( New_Server.name[0] ) { @@ -710,6 +724,10 @@ Read_Config( bool ngircd_starting ) Conf_Channel_Count++; continue; } + if (strcasecmp(section, "[OPERATOR]") == 0) { + Conf_Oper_Count++; + continue; + } Config_Error( LOG_ERR, "%s, line %d: Unknown section \"%s\"!", NGIRCd_ConfFile, line, section ); section[0] = 0x1; @@ -828,6 +846,13 @@ Handle_GLOBAL( int Line, char *Var, char *Arg ) Config_Error_TooLong( Line, Var ); return; } + if (strcasecmp(Var, "WebircPassword") == 0) { + /* Password required for WEBIRC command */ + len = strlcpy(Conf_WebircPwd, Arg, sizeof(Conf_WebircPwd)); + if (len >= sizeof(Conf_WebircPwd)) + Config_Error_TooLong(Line, Var); + return; + } if( strcasecmp( Var, "AdminInfo1" ) == 0 ) { /* Administrative info #1 */ len = strlcpy( Conf_ServerAdmin1, Arg, sizeof( Conf_ServerAdmin1 )); @@ -1081,36 +1106,38 @@ Handle_GLOBAL( int Line, char *Var, char *Arg ) static void Handle_OPERATOR( int Line, char *Var, char *Arg ) { - unsigned int opercount; size_t len; + struct Conf_Oper *op; + assert( Line > 0 ); assert( Var != NULL ); assert( Arg != NULL ); assert( Conf_Oper_Count > 0 ); - if ( Conf_Oper_Count == 0 ) + op = array_alloc(&Conf_Opers, sizeof(*op), Conf_Oper_Count - 1); + if (!op) { + Config_Error(LOG_ERR, "Could not allocate memory for operator (%d:%s = %s)", Line, Var, Arg); return; + } - opercount = Conf_Oper_Count - 1; - - if( strcasecmp( Var, "Name" ) == 0 ) { + if (strcasecmp(Var, "Name") == 0) { /* Name of IRC operator */ - len = strlcpy( Conf_Oper[opercount].name, Arg, sizeof( Conf_Oper[opercount].name )); - if (len >= sizeof( Conf_Oper[opercount].name )) - Config_Error_TooLong( Line, Var ); + len = strlcpy(op->name, Arg, sizeof(op->name)); + if (len >= sizeof(op->name)) + Config_Error_TooLong(Line, Var); return; } - if( strcasecmp( Var, "Password" ) == 0 ) { + if (strcasecmp(Var, "Password") == 0) { /* Password of IRC operator */ - len = strlcpy( Conf_Oper[opercount].pwd, Arg, sizeof( Conf_Oper[opercount].pwd )); - if (len >= sizeof( Conf_Oper[opercount].pwd )) - Config_Error_TooLong( Line, Var ); + len = strlcpy(op->pwd, Arg, sizeof(op->pwd)); + if (len >= sizeof(op->pwd)) + Config_Error_TooLong(Line, Var); return; } - if( strcasecmp( Var, "Mask" ) == 0 ) { - if (Conf_Oper[opercount].mask) return; /* Hostname already configured */ - - Conf_Oper[opercount].mask = strdup_warn( Arg ); + if (strcasecmp(Var, "Mask") == 0) { + if (op->mask) + return; /* Hostname already configured */ + op->mask = strdup_warn( Arg ); return; } Config_Error( LOG_ERR, "%s, line %d (section \"Operator\"): Unknown variable \"%s\"!", diff --git a/src/ngircd/conf.h b/src/ngircd/conf.h index 2308e4c..5764d0f 100644 --- a/src/ngircd/conf.h +++ b/src/ngircd/conf.h @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2008 Alexander Barton (alex@barton.de) + * Copyright (c)2001-2010 Alexander Barton (alex@barton.de) * * 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 @@ -26,12 +26,11 @@ #include "conf-ssl.h" -typedef struct _Conf_Oper -{ +struct Conf_Oper { char name[CLIENT_PASS_LEN]; /* Name (ID) of IRC operator */ char pwd[CLIENT_PASS_LEN]; /* Password */ - char *mask; -} CONF_OPER; + char *mask; /* allowed host mask */ +}; typedef struct _Conf_Server { @@ -125,8 +124,7 @@ GLOBAL int Conf_PongTimeout; GLOBAL int Conf_ConnectRetry; /* Operators */ -GLOBAL CONF_OPER Conf_Oper[MAX_OPERATORS]; -GLOBAL unsigned int Conf_Oper_Count; +GLOBAL array Conf_Opers; /* Servers */ GLOBAL CONF_SERVER Conf_Server[MAX_SERVERS]; @@ -190,6 +188,9 @@ GLOBAL bool Conf_AddServer PARAMS(( const char *Name, UINT16 Port, const char *H GLOBAL bool Conf_IsService PARAMS((int ConfServer, const char *Nick)); +/* Password required by WEBIRC command */ +GLOBAL char Conf_WebircPwd[CLIENT_PASS_LEN]; + #endif diff --git a/src/ngircd/conn.c b/src/ngircd/conn.c index 731647d..cd350a8 100644 --- a/src/ngircd/conn.c +++ b/src/ngircd/conn.c @@ -109,37 +109,51 @@ extern struct SSLOptions Conf_SSLOptions; static void cb_connserver_login_ssl PARAMS((int sock, short what)); static void cb_clientserver_ssl PARAMS((int sock, short what)); #endif -static void cb_Read_Resolver_Result PARAMS(( int sock, UNUSED short what)); -static void cb_Connect_to_Server PARAMS(( int sock, UNUSED short what)); +static void cb_Read_Resolver_Result PARAMS((int sock, UNUSED short what)); +static void cb_Connect_to_Server PARAMS((int sock, UNUSED short what)); static void cb_clientserver PARAMS((int sock, short what)); + +/** + * IO callback for listening sockets: handle new connections. This callback + * gets called when a new non-SSL connection should be accepted. + * @param sock Socket descriptor + * @param irrelevant (ignored IO specification) + */ static void cb_listen(int sock, short irrelevant) { (void) irrelevant; - if (New_Connection( sock ) >= 0) - NumConnections++; - LogDebug("Total number of connections now %ld.", NumConnections); + (void) New_Connection(sock); } #ifdef SSL_SUPPORT +/** + * IO callback for listening SSL sockets: handle new connections. This callback + * gets called when a new SSL-enabled connection should be accepted. + * @param sock Socket descriptor + * @param irrelevant (ignored IO specification) + */ static void cb_listen_ssl(int sock, short irrelevant) { int fd; + (void) irrelevant; fd = New_Connection(sock); if (fd < 0) return; - - NumConnections++; - LogDebug("Total number of connections now %ld.", NumConnections); io_event_setcb(My_Connections[fd].sock, cb_clientserver_ssl); } #endif +/** + * IO callback for new outgoing non-SSL server connections. + * @param sock Socket descriptor + * @param what IO specification (IO_WANTREAD/IO_WANTWRITE/...) + */ static void cb_connserver(int sock, UNUSED short what) { @@ -213,6 +227,10 @@ cb_connserver(int sock, UNUSED short what) } +/** + * Login to a remote server. + * @param idx Connection index + */ static void server_login(CONN_ID idx) { @@ -229,6 +247,11 @@ server_login(CONN_ID idx) #ifdef SSL_SUPPORT +/** + * IO callback for new outgoing SSL-enabled server connections. + * @param sock Socket descriptor + * @param what IO specification (IO_WANTREAD/IO_WANTWRITE/...) + */ static void cb_connserver_login_ssl(int sock, short unused) { @@ -258,6 +281,11 @@ cb_connserver_login_ssl(int sock, short unused) #endif +/** + * IO callback for established non-SSL client and server connections. + * @param sock Socket descriptor + * @param what IO specification (IO_WANTREAD/IO_WANTWRITE/...) + */ static void cb_clientserver(int sock, short what) { @@ -270,18 +298,27 @@ cb_clientserver(int sock, short what) return; } #ifdef SSL_SUPPORT - if (what & IO_WANTREAD || (Conn_OPTION_ISSET(&My_Connections[idx], CONN_SSL_WANT_WRITE))) - Read_Request( idx ); /* if TLS layer needs to write additional data, call Read_Request instead so SSL/TLS can continue */ + if (what & IO_WANTREAD + || (Conn_OPTION_ISSET(&My_Connections[idx], CONN_SSL_WANT_WRITE))) { + /* if TLS layer needs to write additional data, call + * Read_Request() instead so that SSL/TLS can continue */ + Read_Request(idx); + } #else if (what & IO_WANTREAD) - Read_Request( idx ); + Read_Request(idx); #endif if (what & IO_WANTWRITE) - Handle_Write( idx ); + Handle_Write(idx); } #ifdef SSL_SUPPORT +/** + * IO callback for established SSL-enabled client and server connections. + * @param sock Socket descriptor + * @param what IO specification (IO_WANTREAD/IO_WANTWRITE/...) + */ static void cb_clientserver_ssl(int sock, short what) { @@ -295,11 +332,13 @@ cb_clientserver_ssl(int sock, short what) } switch (ConnSSL_Accept(&My_Connections[idx])) { - case 1: break; /* OK */ - case 0: return; /* EAGAIN: this callback will be invoked again by the io layer */ - default: - Conn_Close( idx, "Socket closed!", "SSL accept error", false ); - return; + case 1: + break; /* OK */ + case 0: + return; /* EAGAIN: callback will be invoked again by IO layer */ + default: + Conn_Close(idx, "Socket closed!", "SSL accept error", false); + return; } if (what & IO_WANTREAD) Read_Request(idx); @@ -312,6 +351,9 @@ cb_clientserver_ssl(int sock, short what) #endif +/** + * Initialite connecion module. + */ GLOBAL void Conn_Init( void ) { @@ -347,6 +389,9 @@ Conn_Init( void ) } /* Conn_Init */ +/** + * Clean up connection module. + */ GLOBAL void Conn_Exit( void ) { @@ -399,6 +444,10 @@ ports_initlisteners(array *a, const char *listen_addr, void (*func)(int,short)) } +/** + * Initialize all listening sockets. + * @return Number of created listening sockets + */ GLOBAL unsigned int Conn_InitListeners( void ) { @@ -433,13 +482,12 @@ Conn_InitListeners( void ) listen_addr = strtok(NULL, ","); } - /* - * can't free() Conf_ListenAddress here. On /REHASH, if the config file + /* Can't free() Conf_ListenAddress here: on REHASH, if the config file * cannot be re-loaded, we'd end up with a NULL Conf_ListenAddress. * Instead, free() takes place in conf.c, before the config file - * is being parsed. - */ + * is being parsed. */ free(copy); + return created; } /* Conn_InitListeners */ @@ -582,6 +630,7 @@ NewListener(const char *listen_addr, UINT16 Port) return sock; } /* NewListener */ + #ifdef SSL_SUPPORT /* * SSL/TLS connections require extra treatment: @@ -1163,12 +1212,14 @@ Count_Connections(ng_ipaddr_t *a) } /* Count_Connections */ +/** + * Initialize new client connection on a listening socket. + * @param Sock Listening socket descriptor + * @return Accepted socket descriptor or -1 on error + */ static int -New_Connection( int Sock ) +New_Connection(int Sock) { - /* Neue Client-Verbindung von Listen-Socket annehmen und - * CLIENT-Struktur anlegen. */ - #ifdef TCPWRAP struct request_info req; #endif @@ -1178,10 +1229,9 @@ New_Connection( int Sock ) CLIENT *c; long cnt; - assert( Sock > NONE ); - /* Connection auf Listen-Socket annehmen */ - new_sock_len = (int)sizeof(new_addr); + assert(Sock > NONE); + new_sock_len = (int)sizeof(new_addr); new_sock = accept(Sock, (struct sockaddr *)&new_addr, (socklen_t *)&new_sock_len); if (new_sock < 0) { @@ -1198,49 +1248,56 @@ New_Connection( int Sock ) #ifdef TCPWRAP /* Validate socket using TCP Wrappers */ - request_init( &req, RQ_DAEMON, PACKAGE_NAME, RQ_FILE, new_sock, RQ_CLIENT_SIN, &new_addr, NULL ); + request_init(&req, RQ_DAEMON, PACKAGE_NAME, RQ_FILE, new_sock, + RQ_CLIENT_SIN, &new_addr, NULL); fromhost(&req); if (!hosts_access(&req)) { - Log (deny_severity, "Refused connection from %s (by TCP Wrappers)!", ip_str); - Simple_Message( new_sock, "ERROR :Connection refused" ); - close( new_sock ); + Log(deny_severity, + "Refused connection from %s (by TCP Wrappers)!", ip_str); + Simple_Message(new_sock, "ERROR :Connection refused"); + close(new_sock); return -1; } #endif - /* Socket initialisieren */ - if (!Init_Socket( new_sock )) + if (!Init_Socket(new_sock)) + return -1; + + /* Check global connection limit */ + if ((Conf_MaxConnections > 0) && + (NumConnections >= (size_t) Conf_MaxConnections)) { + Log(LOG_ALERT, "Can't accept connection: limit (%d) reached!", + Conf_MaxConnections); + Simple_Message(new_sock, "ERROR :Connection limit reached"); + close(new_sock); return -1; + } /* Check IP-based connection limit */ cnt = Count_Connections(&new_addr); if ((Conf_MaxConnectionsIP > 0) && (cnt >= Conf_MaxConnectionsIP)) { /* Access denied, too many connections from this IP address! */ - Log( LOG_ERR, "Refused connection from %s: too may connections (%ld) from this IP address!", ip_str, cnt); - Simple_Message( new_sock, "ERROR :Connection refused, too many connections from your IP address!" ); - close( new_sock ); - return -1; - } - - if ((Conf_MaxConnections > 0) && - (NumConnections >= (size_t) Conf_MaxConnections)) - { - Log( LOG_ALERT, "Can't accept connection: limit (%d) reached!", Conf_MaxConnections); - Simple_Message( new_sock, "ERROR :Connection limit reached" ); - close( new_sock ); + Log(LOG_ERR, + "Refused connection from %s: too may connections (%ld) from this IP address!", + ip_str, cnt); + Simple_Message(new_sock, + "ERROR :Connection refused, too many connections from your IP address!"); + close(new_sock); return -1; } - if( new_sock >= Pool_Size ) { + if (new_sock >= Pool_Size) { if (!array_alloc(&My_ConnArray, sizeof(CONNECTION), - (size_t)new_sock)) { - Log( LOG_EMERG, "Can't allocate memory! [New_Connection]" ); - Simple_Message( new_sock, "ERROR: Internal error" ); - close( new_sock ); + (size_t) new_sock)) { + Log(LOG_EMERG, + "Can't allocate memory! [New_Connection]"); + Simple_Message(new_sock, "ERROR: Internal error"); + close(new_sock); return -1; } LogDebug("Bumped connection pool to %ld items (internal: %ld items, %ld bytes)", - new_sock, array_length(&My_ConnArray, sizeof(CONNECTION)), array_bytes(&My_ConnArray)); + new_sock, array_length(&My_ConnArray, + sizeof(CONNECTION)), array_bytes(&My_ConnArray)); /* Adjust pointer to new block */ My_Connections = array_start(&My_ConnArray); @@ -1249,22 +1306,24 @@ New_Connection( int Sock ) } /* register callback */ - if (!io_event_create( new_sock, IO_WANTREAD, cb_clientserver)) { - Log(LOG_ALERT, "Can't accept connection: io_event_create failed!"); + if (!io_event_create(new_sock, IO_WANTREAD, cb_clientserver)) { + Log(LOG_ALERT, + "Can't accept connection: io_event_create failed!"); Simple_Message(new_sock, "ERROR :Internal error"); close(new_sock); return -1; } - c = Client_NewLocal(new_sock, ip_str, CLIENT_UNKNOWN, false ); - if( ! c ) { - Log(LOG_ALERT, "Can't accept connection: can't create client structure!"); + c = Client_NewLocal(new_sock, ip_str, CLIENT_UNKNOWN, false); + if (!c) { + Log(LOG_ALERT, + "Can't accept connection: can't create client structure!"); Simple_Message(new_sock, "ERROR :Internal error"); io_close(new_sock); return -1; } - Init_Conn_Struct( new_sock ); + Init_Conn_Struct(new_sock); My_Connections[new_sock].sock = new_sock; My_Connections[new_sock].addr = new_addr; My_Connections[new_sock].client = c; @@ -1292,7 +1351,14 @@ New_Connection( int Sock ) if (!Conf_NoDNS) Resolve_Addr(&My_Connections[new_sock].res_stat, &new_addr, identsock, cb_Read_Resolver_Result); + + /* ngIRCd waits up to 4 seconds for the result of the asynchronous + * DNS and IDENT resolver subprocess using the "penalty" mechanism. + * If there are results earlier, the delay is aborted. */ Conn_SetPenalty(new_sock, 4); + + NumConnections++; + LogDebug("Total number of connections now %ld.", NumConnections); return new_sock; } /* New_Connection */ @@ -1811,12 +1877,13 @@ Init_Socket( int Sock ) } /* Set type of service (TOS) */ -#if defined(IP_TOS) && defined(IPTOS_LOWDELAY) +#if defined(IPPROTO_IP) && defined(IPTOS_LOWDELAY) value = IPTOS_LOWDELAY; - LogDebug("Setting option IP_TOS on socket %d to IPTOS_LOWDELAY (%d).", Sock, value ); - if( setsockopt( Sock, SOL_IP, IP_TOS, &value, (socklen_t)sizeof( value )) != 0 ) - { - Log( LOG_ERR, "Can't set socket option IP_TOS: %s!", strerror( errno )); + LogDebug("Setting IP_TOS on socket %d to IPTOS_LOWDELAY.", Sock); + if (setsockopt(Sock, IPPROTO_IP, IP_TOS, &value, + (socklen_t) sizeof(value))) { + Log(LOG_ERR, "Can't set socket option IP_TOS: %s!", + strerror(errno)); /* ignore this error */ } #endif @@ -1825,7 +1892,6 @@ Init_Socket( int Sock ) } /* Init_Socket */ - static void cb_Connect_to_Server(int fd, UNUSED short events) { @@ -1933,10 +1999,14 @@ cb_Read_Resolver_Result( int r_fd, UNUSED short events ) c = Conn_GetClient( i ); assert( c != NULL ); - /* Only update client information of unregistered clients */ - if( Client_Type( c ) == CLIENT_UNKNOWN ) { - strlcpy(My_Connections[i].host, readbuf, sizeof( My_Connections[i].host)); - Client_SetHostname( c, readbuf); + /* Only update client information of unregistered clients. + * Note: user commands (e. g. WEBIRC) are always read _after_ reading + * the resolver results, so we don't have to worry to override settings + * from these commands here. */ + if(Client_Type(c) == CLIENT_UNKNOWN) { + strlcpy(My_Connections[i].host, readbuf, + sizeof(My_Connections[i].host)); + Client_SetHostname(c, readbuf); #ifdef IDENTAUTH ++identptr; if (*identptr) { @@ -1972,24 +2042,34 @@ Simple_Message( int Sock, const char *Msg ) } /* Simple_Error */ +/** + * Get CLIENT structure that belongs to a local connection identified by its + * index number. Each connection belongs to a client by definition, so it is + * not required that the caller checks for NULL return values. + * @param Idx Connection index number + * @return Pointer to CLIENT structure + */ GLOBAL CLIENT * Conn_GetClient( CONN_ID Idx ) { - /* return Client-Structure that belongs to the local Connection Idx. - * If none is found, return NULL. - */ CONNECTION *c; - assert( Idx >= 0 ); + assert(Idx >= 0); c = array_get(&My_ConnArray, sizeof (CONNECTION), (size_t)Idx); - assert(c != NULL); - return c ? c->client : NULL; } + #ifdef SSL_SUPPORT -/* we cannot access My_Connections in irc-info.c */ + +/** + * Get information about used SSL chiper. + * @param Idx Connection index number + * @param buf Buffer for returned information text + * @param len Size of return buffer "buf" + * @return true on success, false otherwise + */ GLOBAL bool Conn_GetCipherInfo(CONN_ID Idx, char *buf, size_t len) { @@ -2000,6 +2080,11 @@ Conn_GetCipherInfo(CONN_ID Idx, char *buf, size_t len) } +/** + * Check if a connection is SSL-enabled or not. + * @param Idx Connection index number + * @return true if connection is SSL-enabled, false otherwise. + */ GLOBAL bool Conn_UsesSSL(CONN_ID Idx) { @@ -2008,6 +2093,7 @@ Conn_UsesSSL(CONN_ID Idx) assert(Idx < (int) array_length(&My_ConnArray, sizeof(CONNECTION))); return Conn_OPTION_ISSET(&My_Connections[Idx], CONN_SSL); } + #endif diff --git a/src/ngircd/conn.h b/src/ngircd/conn.h index 983c884..b94b10d 100644 --- a/src/ngircd/conn.h +++ b/src/ngircd/conn.h @@ -88,7 +88,7 @@ typedef struct _Connection ZIPDATA zip; /* Compression information */ #endif /* ZLIB */ #ifdef SSL_SUPPORT - struct ConnSSL_State ssl_state; /* SSL/GNUTLS state information */ + struct ConnSSL_State ssl_state; /* SSL/GNUTLS state information */ #endif } CONNECTION; diff --git a/src/ngircd/defines.h b/src/ngircd/defines.h index 905a5a6..94c7dd1 100644 --- a/src/ngircd/defines.h +++ b/src/ngircd/defines.h @@ -1,14 +1,12 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2007 Alexander Barton (alex@barton.de) + * Copyright (c)2001-2010 Alexander Barton (alex@barton.de) * * 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 * 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. - * - * $Id: defines.h,v 1.62 2007/11/21 12:16:36 alex Exp $ */ @@ -30,8 +28,6 @@ #define HOST_LEN 256 /* Max. lenght of fully qualified host names (e. g. "abc.domain.tld") */ -#define MAX_OPERATORS 16 /* Max. count of configurable IRC Ops */ - #define MAX_SERVERS 16 /* Max. count of configurable servers */ #define MAX_WHOWAS 64 /* Max. number of WHOWAS items */ @@ -84,8 +80,8 @@ #define RECONNECT_DELAY 3 /* Time to delay re-connect attempts in seconds. */ -#define USERMODES "aios" /* Supported user modes. */ -#define CHANMODES "biIklmnoPstv" /* Supported channel modes. */ +#define USERMODES "aiorsw" /* Supported user modes. */ +#define CHANMODES "biIklmnoPstvz" /* Supported channel modes. */ #define CONNECTED true /* Internal status codes. */ #define DISCONNECTED false diff --git a/src/ngircd/irc-channel.c b/src/ngircd/irc-channel.c index af0f066..1014d3a 100644 --- a/src/ngircd/irc-channel.c +++ b/src/ngircd/irc-channel.c @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2008 Alexander Barton (alex@barton.de) + * Copyright (c)2001-2010 Alexander Barton (alex@barton.de) * * 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 @@ -62,9 +62,18 @@ part_from_all_channels(CLIENT* client, CLIENT *target) } +/** + * Check weather a local client is allowed to join an already existing + * channel or not. + * @param Client Client that sent the JOIN command + * @param chan Channel to check + * @param channame Name of the channel + * @param key Provided channel key (or NULL if none has been provided) + * @return true if client is allowed to join channel, false otherwise + */ static bool -join_allowed(CLIENT *Client, CLIENT *target, CHANNEL *chan, - const char *channame, const char *key) +join_allowed(CLIENT *Client, CHANNEL *chan, const char *channame, + const char *key) { bool is_invited, is_banned; const char *channel_modes; @@ -73,32 +82,48 @@ join_allowed(CLIENT *Client, CLIENT *target, CHANNEL *chan, if (strchr(Client_Modes(Client), 'o')) return true; - is_banned = Lists_Check(Channel_GetListBans(chan), target); - is_invited = Lists_Check(Channel_GetListInvites(chan), target); + is_banned = Lists_Check(Channel_GetListBans(chan), Client); + is_invited = Lists_Check(Channel_GetListInvites(chan), Client); if (is_banned && !is_invited) { - IRC_WriteStrClient(Client, ERR_BANNEDFROMCHAN_MSG, Client_ID(Client), channame); + /* Client is banned from channel (and not on invite list) */ + IRC_WriteStrClient(Client, ERR_BANNEDFROMCHAN_MSG, + Client_ID(Client), channame); return false; } channel_modes = Channel_Modes(chan); - if ((strchr(channel_modes, 'i')) && !is_invited) { - /* Channel is "invite-only" (and Client wasn't invited) */ - IRC_WriteStrClient(Client, ERR_INVITEONLYCHAN_MSG, Client_ID(Client), channame); + if (strchr(channel_modes, 'i') && !is_invited) { + /* Channel is "invite-only" and client is not on invite list */ + IRC_WriteStrClient(Client, ERR_INVITEONLYCHAN_MSG, + Client_ID(Client), channame); return false; } - /* Is the channel protected by a key? */ - if (!Channel_CheckKey(chan, target, key ? key : "")) { + if (!Channel_CheckKey(chan, Client, key ? key : "")) { + /* Channel is protected by a channel key and the client + * didn't specify the correct one */ IRC_WriteStrClient(Client, ERR_BADCHANNELKEY_MSG, Client_ID(Client), channame); return false; } - /* Are there already too many members? */ - if ((strchr(channel_modes, 'l')) && (Channel_MaxUsers(chan) <= Channel_MemberCount(chan))) { - IRC_WriteStrClient(Client, ERR_CHANNELISFULL_MSG, Client_ID(Client), channame); + + if (strchr(channel_modes, 'l') && + (Channel_MaxUsers(chan) <= Channel_MemberCount(chan))) { + /* There are more clints joined to this channel than allowed */ + IRC_WriteStrClient(Client, ERR_CHANNELISFULL_MSG, + Client_ID(Client), channame); + return false; + } + + if (strchr(channel_modes, 'z') && !Conn_UsesSSL(Client_Conn(Client))) { + /* Only "secure" clients are allowed, but clients doesn't + * use SSL encryption */ + IRC_WriteStrClient(Client, ERR_SECURECHANNEL_MSG, + Client_ID(Client), channame); return false; } + return true; } @@ -270,20 +295,23 @@ IRC_JOIN( CLIENT *Client, REQUEST *Req ) /* Local client? */ if (Client_Type(Client) == CLIENT_USER) { - /* Test if the user has reached his maximum channel count */ - if ((Conf_MaxJoins > 0) && (Channel_CountForUser(Client) >= Conf_MaxJoins)) - return IRC_WriteStrClient(Client, ERR_TOOMANYCHANNELS_MSG, - Client_ID(Client), channame); - if (!chan) { - /* - * New Channel: first user will be channel operator - * unless this is a modeless channel. - */ + /* Test if the user has reached the channel limit */ + if ((Conf_MaxJoins > 0) && + (Channel_CountForUser(Client) >= Conf_MaxJoins)) + return IRC_WriteStrClient(Client, + ERR_TOOMANYCHANNELS_MSG, + Client_ID(Client), channame); + if (chan) { + /* Already existing channel: check if the + * client is allowed to join */ + if (!join_allowed(Client, chan, channame, key)) + break; + } else { + /* New channel: first user will become channel + * operator unless this is a modeless channel */ if (*channame != '+') flags = "o"; - } else - if (!join_allowed(Client, target, chan, channame, key)) - break; + } /* Local client: update idle time */ Conn_UpdateIdle(Client_Conn(Client)); @@ -293,7 +321,9 @@ IRC_JOIN( CLIENT *Client, REQUEST *Req ) * that the "one shot" entries (generated by INVITE * commands) in this list become deleted when a user * joins a channel this way. */ - if (chan) (void)Lists_Check(Channel_GetListInvites(chan), target); + if (chan) + (void)Lists_Check(Channel_GetListInvites(chan), + target); } /* Join channel (and create channel if it doesn't exist) */ diff --git a/src/ngircd/irc-info.c b/src/ngircd/irc-info.c index 5a8555a..28722e7 100644 --- a/src/ngircd/irc-info.c +++ b/src/ngircd/irc-info.c @@ -465,6 +465,10 @@ uptime_mins(time_t *now) } +/** + * Handler for the IRC command "STATS". + * See RFC 2812 section 3.4.4. + */ GLOBAL bool IRC_STATS( CLIENT *Client, REQUEST *Req ) { @@ -475,11 +479,12 @@ IRC_STATS( CLIENT *Client, REQUEST *Req ) time_t time_now; unsigned int days, hrs, mins; - assert( Client != NULL ); - assert( Req != NULL ); + assert(Client != NULL); + assert(Req != NULL); if (Req->argc > 2) - return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, Client_ID(Client), Req->command); + return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, + Client_ID(Client), Req->command); /* use prefix to determine "From" */ if (Client_Type(Client) == CLIENT_SERVER) @@ -487,18 +492,21 @@ IRC_STATS( CLIENT *Client, REQUEST *Req ) else from = Client; - if (! from) - return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix); + if (!from) + return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG, + Client_ID(Client), Req->prefix); if (Req->argc == 2) { /* forward to another server? */ - target = Client_Search( Req->argv[1] ); - if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER )) - return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[1] ); + target = Client_Search(Req->argv[1]); + if ((!target) || (Client_Type(target) != CLIENT_SERVER)) + return IRC_WriteStrClient(from, ERR_NOSUCHSERVER_MSG, + Client_ID(from), Req->argv[1]); - if( target != Client_ThisServer()) { + if (target != Client_ThisServer()) { /* forward to another server */ - return IRC_WriteStrClientPrefix( target, from, "STATS %s %s", Req->argv[0], Req->argv[1] ); + return IRC_WriteStrClientPrefix(target, from, + "STATS %s %s", Req->argv[0], Req->argv[1]); } } @@ -508,57 +516,70 @@ IRC_STATS( CLIENT *Client, REQUEST *Req ) query = '*'; switch (query) { - case 'l': /* Links */ - case 'L': - time_now = time(NULL); - for (con = Conn_First(); con != NONE ;con = Conn_Next(con)) { - cl = Conn_GetClient(con); - if (!cl) - continue; - if ((Client_Type(cl) == CLIENT_SERVER) || (cl == Client)) { - /* Server link or our own connection */ + case 'l': /* Link status (servers and own link) */ + case 'L': + time_now = time(NULL); + for (con = Conn_First(); con != NONE; con = Conn_Next(con)) { + cl = Conn_GetClient(con); + if (!cl) + continue; + if ((Client_Type(cl) == CLIENT_SERVER) + || (cl == Client)) { + /* Server link or our own connection */ #ifdef ZLIB - if (Conn_Options(con) & CONN_ZIP) { - if (!IRC_WriteStrClient(from, RPL_STATSLINKINFOZIP_MSG, - Client_ID(from), Client_Mask(cl), Conn_SendQ(con), - Conn_SendMsg(con), Zip_SendBytes(con), Conn_SendBytes(con), - Conn_RecvMsg(con), Zip_RecvBytes(con), Conn_RecvBytes(con), (long)(time_now - Conn_StartTime(con)))) - return DISCONNECTED; - continue; - } -#endif - if (!IRC_WriteStrClient(from, RPL_STATSLINKINFO_MSG, Client_ID(from), - Client_Mask(cl), Conn_SendQ(con), Conn_SendMsg(con), Conn_SendBytes(con), - Conn_RecvMsg(con), Conn_RecvBytes(con), (long)(time_now - Conn_StartTime(con)))) - return DISCONNECTED; - } - } - break; - case 'm': /* IRC-Commands */ - case 'M': - cmd = Parse_GetCommandStruct( ); - for (; cmd->name ; cmd++) { - if (cmd->lcount == 0 && cmd->rcount == 0) + if (Conn_Options(con) & CONN_ZIP) { + if (!IRC_WriteStrClient + (from, RPL_STATSLINKINFOZIP_MSG, + Client_ID(from), Client_Mask(cl), + Conn_SendQ(con), Conn_SendMsg(con), + Zip_SendBytes(con), + Conn_SendBytes(con), + Conn_RecvMsg(con), + Zip_RecvBytes(con), + Conn_RecvBytes(con), + (long)(time_now - Conn_StartTime(con)))) + return DISCONNECTED; continue; - if (!IRC_WriteStrClient(from, RPL_STATSCOMMANDS_MSG, Client_ID(from), - cmd->name, cmd->lcount, cmd->bytes, cmd->rcount)) - return DISCONNECTED; + } +#endif + if (!IRC_WriteStrClient + (from, RPL_STATSLINKINFO_MSG, + Client_ID(from), Client_Mask(cl), + Conn_SendQ(con), Conn_SendMsg(con), + Conn_SendBytes(con), Conn_RecvMsg(con), + Conn_RecvBytes(con), + (long)(time_now - Conn_StartTime(con)))) + return DISCONNECTED; } - break; - case 'u': /* server uptime */ - case 'U': - time_now = time(NULL) - NGIRCd_Start; - days = uptime_days(&time_now); - hrs = uptime_hrs(&time_now); - mins = uptime_mins(&time_now); - if (!IRC_WriteStrClient(from, RPL_STATSUPTIME, Client_ID(from), - days, hrs, mins, (unsigned int) time_now)) - return DISCONNECTED; - break; + } + break; + case 'm': /* IRC command status (usage count) */ + case 'M': + cmd = Parse_GetCommandStruct(); + for (; cmd->name; cmd++) { + if (cmd->lcount == 0 && cmd->rcount == 0) + continue; + if (!IRC_WriteStrClient + (from, RPL_STATSCOMMANDS_MSG, Client_ID(from), + cmd->name, cmd->lcount, cmd->bytes, cmd->rcount)) + return DISCONNECTED; + } + break; + case 'u': /* Server uptime */ + case 'U': + time_now = time(NULL) - NGIRCd_Start; + days = uptime_days(&time_now); + hrs = uptime_hrs(&time_now); + mins = uptime_mins(&time_now); + if (!IRC_WriteStrClient(from, RPL_STATSUPTIME, Client_ID(from), + days, hrs, mins, (unsigned int)time_now)) + return DISCONNECTED; + break; } IRC_SetPenalty(from, 2); - return IRC_WriteStrClient(from, RPL_ENDOFSTATS_MSG, Client_ID(from), query); + return IRC_WriteStrClient(from, RPL_ENDOFSTATS_MSG, + Client_ID(from), query); } /* IRC_STATS */ diff --git a/src/ngircd/irc-login.c b/src/ngircd/irc-login.c index 7b73d40..2de4bd5 100644 --- a/src/ngircd/irc-login.c +++ b/src/ngircd/irc-login.c @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2008 Alexander Barton (alex@barton.de) + * Copyright (c)2001-2010 Alexander Barton (alex@barton.de) * * 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 @@ -557,6 +557,31 @@ IRC_SERVICE(CLIENT *Client, REQUEST *Req) } /* IRC_SERVICE */ +/** + * Handler for the IRC command "WEBIRC". + * Syntax: WEBIRC + */ +GLOBAL bool +IRC_WEBIRC(CLIENT *Client, REQUEST *Req) +{ + /* Exactly 4 parameters are requited */ + if (Req->argc != 4) + return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, + Client_ID(Client), Req->command); + + if (!Conf_WebircPwd[0] || strcmp(Req->argv[0], Conf_WebircPwd) != 0) + return IRC_WriteStrClient(Client, ERR_PASSWDMISMATCH_MSG, + Client_ID(Client)); + + LogDebug("Connection %d: got valid WEBIRC command: user=%s, host=%s, ip=%s", + Client_Conn(Client), Req->argv[1], Req->argv[2], Req->argv[3]); + + Client_SetUser(Client, Req->argv[1], true); + Client_SetHostname(Client, Req->argv[2]); + return CONNECTED; +} /* IRC_WEBIRC */ + + GLOBAL bool IRC_QUIT( CLIENT *Client, REQUEST *Req ) { diff --git a/src/ngircd/irc-login.h b/src/ngircd/irc-login.h index 0b92038..1504e0b 100644 --- a/src/ngircd/irc-login.h +++ b/src/ngircd/irc-login.h @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2008 Alexander Barton (alex@barton.de) + * Copyright (c)2001-2010 Alexander Barton (alex@barton.de) * * 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 @@ -19,6 +19,7 @@ GLOBAL bool IRC_PASS PARAMS((CLIENT *Client, REQUEST *Req)); GLOBAL bool IRC_NICK PARAMS((CLIENT *Client, REQUEST *Req)); GLOBAL bool IRC_USER PARAMS((CLIENT *Client, REQUEST *Req)); GLOBAL bool IRC_SERVICE PARAMS((CLIENT *Client, REQUEST *Req)); +GLOBAL bool IRC_WEBIRC PARAMS((CLIENT *Client, REQUEST *Req)); GLOBAL bool IRC_PING PARAMS((CLIENT *Client, REQUEST *Req)); GLOBAL bool IRC_PONG PARAMS((CLIENT *Client, REQUEST *Req)); GLOBAL bool IRC_QUIT PARAMS((CLIENT *Client, REQUEST *Req)); diff --git a/src/ngircd/irc-mode.c b/src/ngircd/irc-mode.c index 9509fb0..d22d32f 100644 --- a/src/ngircd/irc-mode.c +++ b/src/ngircd/irc-mode.c @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2008 Alexander Barton (alex@barton.de) + * Copyright (c)2001-2010 Alexander Barton (alex@barton.de) * * 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 @@ -401,6 +401,7 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) case 'n': /* Only members can write */ case 's': /* Secret channel */ case 't': /* Topic locked */ + case 'z': /* Secure connections only */ if (modeok) x[0] = *mode_ptr; else diff --git a/src/ngircd/irc-oper.c b/src/ngircd/irc-oper.c index 17b6044..8492603 100644 --- a/src/ngircd/irc-oper.c +++ b/src/ngircd/irc-oper.c @@ -55,25 +55,26 @@ Bad_OperPass(CLIENT *Client, char *errtoken, char *errmsg) GLOBAL bool IRC_OPER( CLIENT *Client, REQUEST *Req ) { - unsigned int i; + struct Conf_Oper *op; + size_t len, i; assert( Client != NULL ); assert( Req != NULL ); if( Req->argc != 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command ); - for( i = 0; i < Conf_Oper_Count; i++) - { - if( Conf_Oper[i].name[0] && Conf_Oper[i].pwd[0] && ( strcmp( Conf_Oper[i].name, Req->argv[0] ) == 0 )) break; - } - if( i >= Conf_Oper_Count ) + len = array_length(&Conf_Opers, sizeof(*op)); + op = array_start(&Conf_Opers); + for (i = 0; i < len && strcmp(op[i].name, Req->argv[0]); i++) + ; + if (i >= len) return Bad_OperPass(Client, Req->argv[0], "not configured"); - if( strcmp( Conf_Oper[i].pwd, Req->argv[1] ) != 0 ) - return Bad_OperPass(Client, Conf_Oper[i].name, "bad password"); + if (strcmp(op[i].pwd, Req->argv[1]) != 0) + return Bad_OperPass(Client, op[i].name, "bad password"); - if( Conf_Oper[i].mask && (! Match( Conf_Oper[i].mask, Client_Mask( Client ) ))) - return Bad_OperPass(Client, Conf_Oper[i].mask, "hostmask check failed" ); + if (op[i].mask && (!Match(op[i].mask, Client_Mask(Client)))) + return Bad_OperPass(Client, op[i].mask, "hostmask check failed"); if( ! Client_HasMode( Client, 'o' )) { diff --git a/src/ngircd/irc.c b/src/ngircd/irc.c index 2466b6b..67ad2a6 100644 --- a/src/ngircd/irc.c +++ b/src/ngircd/irc.c @@ -53,8 +53,12 @@ IRC_ERROR( CLIENT *Client, REQUEST *Req ) assert( Client != NULL ); assert( Req != NULL ); - if( Req->argc < 1 ) Log( LOG_NOTICE, "Got ERROR from \"%s\"!", Client_Mask( Client )); - else Log( LOG_NOTICE, "Got ERROR from \"%s\": %s!", Client_Mask( Client ), Req->argv[0] ); + if (Req->argc < 1) + Log(LOG_NOTICE, "Got ERROR from \"%s\"!", + Client_Mask(Client)); + else + Log(LOG_NOTICE, "Got ERROR from \"%s\": \"%s\"!", + Client_Mask(Client), Req->argv[0]); return CONNECTED; } /* IRC_ERROR */ diff --git a/src/ngircd/messages.h b/src/ngircd/messages.h index 9e15b81..e15bf16 100644 --- a/src/ngircd/messages.h +++ b/src/ngircd/messages.h @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2008 Alexander Barton + * Copyright (c)2001-2010 Alexander Barton * * 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 @@ -20,7 +20,7 @@ #define RPL_YOURHOST_MSG "002 %s :Your host is %s, running version ngircd-%s (%s/%s/%s)" #define RPL_CREATED_MSG "003 %s :This server has been started %s" #define RPL_MYINFO_MSG "004 %s %s ngircd-%s %s %s" -#define RPL_ISUPPORT1_MSG "005 %s RFC2812 CASEMAPPING=ascii PREFIX=(ov)@+ CHANTYPES=#&+ CHANMODES=bI,k,l,imnPst CHANLIMIT=#&+:%d :are supported on this server" +#define RPL_ISUPPORT1_MSG "005 %s RFC2812 IRCD=ngIRCd CASEMAPPING=ascii PREFIX=(ov)@+ CHANTYPES=#&+ CHANMODES=bI,k,l,imnPst CHANLIMIT=#&+:%d :are supported on this server" #define RPL_ISUPPORT2_MSG "005 %s CHANNELLEN=%d NICKLEN=%d TOPICLEN=%d AWAYLEN=%d KICKLEN=%d PENALTY :are supported on this server" #define RPL_TRACELINK_MSG "200 %s Link %s-%s %s %s V%s %ld %d %d" @@ -113,6 +113,7 @@ #define ERR_ALREADYREGISTRED_MSG "462 %s :Connection already registered" #define ERR_PASSWDMISMATCH_MSG "464 %s :Invalid password" #define ERR_CHANNELISFULL_MSG "471 %s %s :Cannot join channel (+l)" +#define ERR_SECURECHANNEL_MSG "471 %s %s :Cannot join channel (+z)" #define ERR_UNKNOWNMODE_MSG "472 %s: %c :is unknown mode char for %s" #define ERR_INVITEONLYCHAN_MSG "473 %s %s :Cannot join channel (+i)" #define ERR_BANNEDFROMCHAN_MSG "474 %s %s :Cannot join channel (+b)" diff --git a/src/ngircd/parse.c b/src/ngircd/parse.c index 2c28a30..3710d70 100644 --- a/src/ngircd/parse.c +++ b/src/ngircd/parse.c @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2008 Alexander Barton (alex@barton.de) + * Copyright (c)2001-2010 Alexander Barton (alex@barton.de) * * 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 @@ -103,6 +103,7 @@ static COMMAND My_Commands[] = { "USERS", IRC_USERS, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 }, { "VERSION", IRC_VERSION, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 }, { "WALLOPS", IRC_WALLOPS, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 }, + { "WEBIRC", IRC_WEBIRC, CLIENT_UNKNOWN, 0, 0, 0 }, { "WHO", IRC_WHO, CLIENT_USER, 0, 0, 0 }, { "WHOIS", IRC_WHOIS, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 }, { "WHOWAS", IRC_WHOWAS, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 }, diff --git a/src/ngircd/resolve.c b/src/ngircd/resolve.c index b1487be..37d1c51 100644 --- a/src/ngircd/resolve.c +++ b/src/ngircd/resolve.c @@ -203,7 +203,7 @@ Do_IdentQuery(int identsock, array *resolved_addr) * the IP address in resbuf and returns false. * @param IpAddr ip address to resolve * @param resbuf result buffer to store DNS name/string representation of ip address - * @reslen size of result buffer (must be >= NGT_INET_ADDRSTRLEN) + * @param reslen size of result buffer (must be >= NGT_INET_ADDRSTRLEN) * @return true if reverse lookup successful, false otherwise */ static bool