diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/ngircd/channel.c | 14 | ||||
| -rw-r--r-- | src/ngircd/conf.c | 15 | ||||
| -rw-r--r-- | src/ngircd/conf.h | 5 | ||||
| -rw-r--r-- | src/ngircd/conn.c | 156 | ||||
| -rw-r--r-- | src/ngircd/irc-info.c | 3 | ||||
| -rw-r--r-- | src/ngircd/irc-login.c | 10 | ||||
| -rw-r--r-- | src/ngircd/log.c | 2 | ||||
| -rw-r--r-- | src/ngircd/login.c | 10 | ||||
| -rw-r--r-- | src/ngircd/messages.h | 1 | ||||
| -rw-r--r-- | src/ngircd/sighandlers.c | 24 |
10 files changed, 193 insertions, 47 deletions
diff --git a/src/ngircd/channel.c b/src/ngircd/channel.c index 4eab2726..45bf615c 100644 --- a/src/ngircd/channel.c +++ b/src/ngircd/channel.c @@ -326,6 +326,13 @@ Channel_Kick(CLIENT *Peer, CLIENT *Target, CLIENT *Origin, const char *Name, } } + /* Check that the client to be kicked is on the specified channel */ + if (!Channel_IsMemberOf(chan, Target)) { + IRC_WriteStrClient(Origin, ERR_USERNOTINCHANNEL_MSG, + Client_ID(Origin), Client_ID(Target), Name ); + return; + } + if(Client_Type(Peer) == CLIENT_USER) { /* Channel mode 'Q' and user mode 'q' on target: nobody but * IRC Operators and servers can kick the target user */ @@ -382,13 +389,6 @@ Channel_Kick(CLIENT *Peer, CLIENT *Target, CLIENT *Origin, const char *Name, } } - /* Check that the client to be kicked is on the specified channel */ - if (!Channel_IsMemberOf(chan, Target)) { - IRC_WriteStrClient(Origin, ERR_USERNOTINCHANNEL_MSG, - Client_ID(Origin), Client_ID(Target), Name ); - return; - } - /* Kick Client from channel */ Remove_Client( REMOVE_KICK, chan, Target, Origin, Reason, true); } /* Channel_Kick */ diff --git a/src/ngircd/conf.c b/src/ngircd/conf.c index 929ab054..e46dcfee 100644 --- a/src/ngircd/conf.c +++ b/src/ngircd/conf.c @@ -370,6 +370,7 @@ Conf_Test( void ) puts("[LIMITS]"); printf(" ConnectRetry = %d\n", Conf_ConnectRetry); + printf(" IdleTimeout = %d\n", Conf_IdleTimeout); printf(" MaxConnections = %d\n", Conf_MaxConnections); printf(" MaxConnectionsIP = %d\n", Conf_MaxConnectionsIP); printf(" MaxJoins = %d\n", Conf_MaxJoins > 0 ? Conf_MaxJoins : -1); @@ -736,6 +737,7 @@ Set_Defaults(bool InitServers) /* Limits */ Conf_ConnectRetry = 60; + Conf_IdleTimeout = 0; Conf_MaxConnections = 0; Conf_MaxConnectionsIP = 5; Conf_MaxJoins = 10; @@ -830,8 +832,8 @@ Read_TextFile(const char *Filename, const char *Name, array *Destination) fp = fopen(Filename, "r"); if (!fp) { - Config_Error(LOG_WARNING, "Can't read %s file \"%s\": %s", - Name, Filename, strerror(errno)); + Config_Error(LOG_ERR, "Can't read %s file \"%s\": %s", + Name, Filename, strerror(errno)); return false; } @@ -841,7 +843,7 @@ Read_TextFile(const char *Filename, const char *Name, array *Destination) /* add text including \0 */ if (!array_catb(Destination, line, strlen(line) + 1)) { - Log(LOG_WARNING, "Cannot read/add \"%s\", line %d: %s", + Log(LOG_ERR, "Cannot read/add \"%s\", line %d: %s", Filename, line_no, strerror(errno)); break; } @@ -1241,6 +1243,7 @@ CheckLegacyGlobalOption(int Line, char *Var, char *Arg) return "[Options]"; } if (strcasecmp(Var, "ConnectRetry") == 0 + || strcasecmp(Var, "IdleTimeout") == 0 || strcasecmp(Var, "MaxConnections") == 0 || strcasecmp(Var, "MaxConnectionsIP") == 0 || strcasecmp(Var, "MaxJoins") == 0 @@ -1490,6 +1493,12 @@ Handle_LIMITS(int Line, char *Var, char *Arg) } return; } + if (strcasecmp(Var, "IdleTimeout") == 0) { + Conf_IdleTimeout = atoi(Arg); + if (!Conf_IdleTimeout && strcmp(Arg, "0")) + Config_Error_NaN(Line, Var); + return; + } if (strcasecmp(Var, "MaxConnections") == 0) { Conf_MaxConnections = atoi(Arg); if (!Conf_MaxConnections && strcmp(Arg, "0")) diff --git a/src/ngircd/conf.h b/src/ngircd/conf.h index c203b570..bbf4f36c 100644 --- a/src/ngircd/conf.h +++ b/src/ngircd/conf.h @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors. + * Copyright (c)2001-2013 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 @@ -211,6 +211,9 @@ GLOBAL bool Conf_ConnectIPv6; /** Try to connect to remote systems using the IPv4 protocol (true) */ GLOBAL bool Conf_ConnectIPv4; +/** Idle timout (seconds), after which the daemon should exit */ +GLOBAL int Conf_IdleTimeout; + /** Maximum number of simultaneous connections to this server */ GLOBAL int Conf_MaxConnections; diff --git a/src/ngircd/conn.c b/src/ngircd/conn.c index 142cf23a..3c1427d5 100644 --- a/src/ngircd/conn.c +++ b/src/ngircd/conn.c @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors. + * Copyright (c)2001-2013 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 @@ -82,6 +82,8 @@ #define MAX_COMMANDS_SERVER_MIN 10 #define MAX_COMMANDS_SERVICE 10 +#define SD_LISTEN_FDS_START 3 + static bool Handle_Write PARAMS(( CONN_ID Idx )); static bool Conn_Write PARAMS(( CONN_ID Idx, char *Data, size_t Len )); @@ -119,6 +121,42 @@ 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)); +time_t idle_t = 0; + + +/** + * Get number of sockets available from systemd(8). + * + * ngIRCd needs to implement its own sd_listen_fds(3) function and can't + * use the one provided by systemd itself, becaus the sockets will be + * used in a forked child process with a new PID, and this would trigger + * an error in the standard implementation. + * + * @return Number of sockets available, -1 if sockets have already been + * initialized, or 0 when no sockets have been passed. + */ +static int +my_sd_listen_fds(void) +{ + const char *e; + int count; + + /* Check if LISTEN_PID exists; but we ignore the result, because + * normally ngircd forks a child before checking this, and therefore + * the PID set in the environment is always wrong ... */ + e = getenv("LISTEN_PID"); + if (!e || !*e) + return 0; + + e = getenv("LISTEN_FDS"); + if (!e || !*e) + return -1; + count = atoi(e); + unsetenv("LISTEN_FDS"); + + return count; +} + /** * IO callback for listening sockets: handle new connections. This callback @@ -454,7 +492,7 @@ Conn_CloseAllSockets(int ExceptOf) * @returns Number of listening sockets created. */ static unsigned int -ports_initlisteners(array *a, const char *listen_addr, void (*func)(int,short)) +Init_Listeners(array *a, const char *listen_addr, void (*func)(int,short)) { unsigned int created = 0; size_t len; @@ -470,8 +508,9 @@ ports_initlisteners(array *a, const char *listen_addr, void (*func)(int,short)) continue; } if (!io_event_create( fd, IO_WANTREAD, func )) { - Log( LOG_ERR, "io_event_create(): Could not add listening fd %d (port %u): %s!", - fd, (unsigned int) *port, strerror(errno)); + Log(LOG_ERR, + "io_event_create(): Can't add fd %d (port %u): %s!", + fd, (unsigned int) *port, strerror(errno)); close(fd); port++; continue; @@ -493,14 +532,76 @@ Conn_InitListeners( void ) { /* Initialize ports on which the server should accept connections */ unsigned int created = 0; - char *copy, *listen_addr; + char *af_str, *copy, *listen_addr; + int count, fd, i, addr_len; + ng_ipaddr_t addr; assert(Conf_ListenAddress); + count = my_sd_listen_fds(); + if (count < 0) { + Log(LOG_INFO, + "Not re-initializing listening sockets of systemd(8) ..."); + return 0; + } + if (count > 0) { + /* systemd(8) passed sockets to us, so don't try to initialize + * listening sockets on our own but use the passed ones */ + LogDebug("Initializing %d systemd sockets ...", count); + for (i = 0; i < count; i++) { + fd = SD_LISTEN_FDS_START + i; + addr_len = (int)sizeof(addr); + getsockname(fd, (struct sockaddr *)&addr, (socklen_t*)&addr_len); +#ifdef WANT_IPV6 + if (addr.sin4.sin_family != AF_INET && addr.sin4.sin_family != AF_INET6) +#else + if (addr.sin4.sin_family != AF_INET) +#endif + { + /* Socket is of unsupported type! For example, systemd passed in + * an IPv6 socket but ngIRCd isn't compiled with IPv6 support. */ + switch (addr.sin4.sin_family) + { + case AF_UNSPEC: af_str = "AF_UNSPEC"; break; + case AF_UNIX: af_str = "AF_UNIX"; break; + case AF_INET: af_str = "AF_INET"; break; +#ifdef AF_INET6 + case AF_INET6: af_str = "AF_INET6"; break; +#endif +#ifdef AF_NETLINK + case AF_NETLINK: af_str = "AF_NETLINK"; break; +#endif + default: af_str = "unknown"; break; + } + Log(LOG_CRIT, + "Socket %d is of unsupported type \"%s\" (%d), have to ignore it!", + fd, af_str, addr.sin4.sin_family); + close(fd); + continue; + } + + Init_Socket(fd); + if (!io_event_create(fd, IO_WANTREAD, cb_listen)) { + Log(LOG_ERR, + "io_event_create(): Can't add fd %d: %s!", + fd, strerror(errno)); + continue; + } + Log(LOG_INFO, + "Initialized socket %d from systemd(8): %s:%d.", fd, + ng_ipaddr_tostr(&addr), ng_ipaddr_getport(&addr)); + created++; + } + return created; + } + + /* not using systemd socket activation, initialize listening sockets: */ + /* can't use Conf_ListenAddress directly, see below */ copy = strdup(Conf_ListenAddress); if (!copy) { - Log(LOG_CRIT, "Cannot copy %s: %s", Conf_ListenAddress, strerror(errno)); + Log(LOG_CRIT, "Cannot copy %s: %s", Conf_ListenAddress, + strerror(errno)); return 0; } listen_addr = strtok(copy, ","); @@ -508,9 +609,11 @@ Conn_InitListeners( void ) while (listen_addr) { ngt_TrimStr(listen_addr); if (*listen_addr) { - created += ports_initlisteners(&Conf_ListenPorts, listen_addr, cb_listen); + created += Init_Listeners(&Conf_ListenPorts, + listen_addr, cb_listen); #ifdef SSL_SUPPORT - created += ports_initlisteners(&Conf_SSLOptions.ListenPorts, listen_addr, cb_listen_ssl); + created += Init_Listeners(&Conf_SSLOptions.ListenPorts, + listen_addr, cb_listen_ssl); #endif } @@ -537,7 +640,12 @@ Conn_ExitListeners( void ) int *fd; size_t arraylen; + /* Get number of listening sockets to shut down. There can be none + * if ngIRCd has been "socket activated" by systemd. */ arraylen = array_length(&My_Listeners, sizeof (int)); + if (arraylen < 1) + return; + Log(LOG_INFO, "Shutting down all listening sockets (%d total) ...", arraylen); fd = array_start(&My_Listeners); @@ -620,8 +728,9 @@ NewListener(const char *listen_addr, UINT16 Port) af = ng_ipaddr_af(&addr); sock = socket(af, SOCK_STREAM, 0); - if( sock < 0 ) { - Log(LOG_CRIT, "Can't create socket (af %d) : %s!", af, strerror(errno)); + if (sock < 0) { + Log(LOG_CRIT, "Can't create socket (af %d) : %s!", af, + strerror(errno)); return -1; } @@ -632,21 +741,22 @@ NewListener(const char *listen_addr, UINT16 Port) if (bind(sock, (struct sockaddr *)&addr, ng_ipaddr_salen(&addr)) != 0) { Log(LOG_CRIT, "Can't bind socket to address %s:%d - %s!", - ng_ipaddr_tostr(&addr), Port, strerror(errno)); + ng_ipaddr_tostr(&addr), Port, strerror(errno)); close(sock); return -1; } - if( listen( sock, 10 ) != 0 ) { - Log( LOG_CRIT, "Can't listen on socket: %s!", strerror( errno )); - close( sock ); + if (listen(sock, 10) != 0) { + Log(LOG_CRIT, "Can't listen on socket: %s!", strerror(errno)); + close(sock); return -1; } /* keep fd in list so we can close it when ngircd restarts/shuts down */ - if (!array_catb( &My_Listeners,(char*) &sock, sizeof(int) )) { - Log( LOG_CRIT, "Can't add socket to My_Listeners array: %s!", strerror( errno )); - close( sock ); + if (!array_catb(&My_Listeners, (char *)&sock, sizeof(int))) { + Log(LOG_CRIT, "Can't add socket to My_Listeners array: %s!", + strerror(errno)); + close(sock); return -1; } @@ -830,6 +940,15 @@ Conn_Handler(void) PACKAGE_NAME); exit(1); } + + /* Should ngIRCd timeout when idle? */ + if (Conf_IdleTimeout > 0 && NumConnectionsAccepted > 0 + && idle_t > 0 && time(NULL) - idle_t >= Conf_IdleTimeout) { + LogDebug("Server idle timeout reached: %d second%s. Initiating shutdown ...", + Conf_IdleTimeout, + Conf_IdleTimeout == 1 ? "" : "s"); + NGIRCd_SignalQuit = true; + } } if (NGIRCd_SignalQuit) @@ -1191,6 +1310,8 @@ Conn_Close( CONN_ID Idx, const char *LogMsg, const char *FwdMsg, bool InformClie NumConnections--; LogDebug("Shutdown of connection %d completed, %ld connection%s left.", Idx, NumConnections, NumConnections != 1 ? "s" : ""); + + idle_t = NumConnections > 0 ? 0 : time(NULL); } /* Conn_Close */ @@ -1562,6 +1683,7 @@ static void Account_Connection(void) { NumConnections++; + idle_t = 0; if (NumConnections > NumConnectionsMax) NumConnectionsMax = NumConnections; LogDebug("Total number of connections now %lu (max %lu).", diff --git a/src/ngircd/irc-info.c b/src/ngircd/irc-info.c index 3c8dcd51..24d65651 100644 --- a/src/ngircd/irc-info.c +++ b/src/ngircd/irc-info.c @@ -1251,7 +1251,8 @@ IRC_WHOIS( CLIENT *Client, REQUEST *Req ) */ if (!has_wildcards || is_remote) { c = Client_Search(query); - if (c && Client_Type(c) == CLIENT_USER) { + if (c && (Client_Type(c) == CLIENT_USER + || Client_Type(c) == CLIENT_SERVICE)) { if (!IRC_WHOIS_SendReply(Client, from, c)) return DISCONNECTED; } else { diff --git a/src/ngircd/irc-login.c b/src/ngircd/irc-login.c index e7d83eff..52c6e46e 100644 --- a/src/ngircd/irc-login.c +++ b/src/ngircd/irc-login.c @@ -444,7 +444,7 @@ IRC_USER(CLIENT * Client, REQUEST * Req) ptr = Req->argv[0]; while (*ptr) { if (!isalnum((int)*ptr) && - *ptr != '+' && *ptr != '-' && + *ptr != '+' && *ptr != '-' && *ptr != '@' && *ptr != '.' && *ptr != '_') { Conn_Close(Client_Conn(Client), NULL, "Invalid user name", true); @@ -453,6 +453,13 @@ IRC_USER(CLIENT * Client, REQUEST * Req) ptr++; } + /* Save the received username for authentication, and use + * it up to the first '@' as default user name (like ircd2.11, + * bahamut, ircd-seven, ...), prefixed with '~', if needed: */ + Client_SetOrigUser(Client, Req->argv[0]); + ptr = strchr(Req->argv[0], '@'); + if (ptr) + *ptr = '\0'; #ifdef IDENTAUTH ptr = Client_User(Client); if (!ptr || !*ptr || *ptr == '~') @@ -460,7 +467,6 @@ IRC_USER(CLIENT * Client, REQUEST * Req) #else Client_SetUser(Client, Req->argv[0], false); #endif - Client_SetOrigUser(Client, Req->argv[0]); /* "Real name" or user info text: Don't set it to the empty * string, the original ircd can't deal with such "real names" diff --git a/src/ngircd/log.c b/src/ngircd/log.c index 375f4bc1..e5bed791 100644 --- a/src/ngircd/log.c +++ b/src/ngircd/log.c @@ -109,7 +109,7 @@ Log_ReInit(void) GLOBAL void Log_Exit( void ) { - Log(LOG_NOTICE, "%s done%s, served %lu connection%s.", PACKAGE_NAME, + Log(LOG_INFO, "%s done%s, served %lu connection%s.", PACKAGE_NAME, NGIRCd_SignalRestart ? " (restarting)" : "", Conn_CountAccepted(), Conn_CountAccepted() == 1 ? "" : "s"); #ifdef SYSLOG diff --git a/src/ngircd/login.c b/src/ngircd/login.c index d79344b5..d8c8c40a 100644 --- a/src/ngircd/login.c +++ b/src/ngircd/login.c @@ -202,6 +202,7 @@ Login_User_PostAuth(CLIENT *Client) static void cb_Read_Auth_Result(int r_fd, UNUSED short events) { + char user[CLIENT_USER_LEN], *ptr; CONN_ID conn; CLIENT *client; int result; @@ -233,7 +234,14 @@ cb_Read_Auth_Result(int r_fd, UNUSED short events) } if (result == true) { - Client_SetUser(client, Client_OrigUser(client), true); + /* Authentication succeeded, now set the correct user name + * supplied by the client (without prepended '~' for exmaple), + * but cut it at the first '@' character: */ + strlcpy(user, Client_OrigUser(client), sizeof(user)); + ptr = strchr(user, '@'); + if (ptr) + *ptr = '\0'; + Client_SetUser(client, user, true); (void)Login_User_PostAuth(client); } else Client_Reject(client, "Bad password", false); diff --git a/src/ngircd/messages.h b/src/ngircd/messages.h index a6a6d8c2..371abc26 100644 --- a/src/ngircd/messages.h +++ b/src/ngircd/messages.h @@ -56,6 +56,7 @@ #define RPL_UNAWAY_MSG "305 %s :You are no longer marked as being away" #define RPL_NOWAWAY_MSG "306 %s :You have been marked as being away" #define RPL_WHOISREGNICK_MSG "307 %s %s :is a registered nick" +#define RPL_WHOISSERVICE_MSG "310 %s %s :is an IRC service" #define RPL_WHOISUSER_MSG "311 %s %s %s %s * :%s" #define RPL_WHOISSERVER_MSG "312 %s %s %s :%s" #define RPL_WHOISOPERATOR_MSG "313 %s %s :is an IRC operator" diff --git a/src/ngircd/sighandlers.c b/src/ngircd/sighandlers.c index 8f0a5a1b..6d5ea8f8 100644 --- a/src/ngircd/sighandlers.c +++ b/src/ngircd/sighandlers.c @@ -1,5 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon + * Copyright (c)2001-2013 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 @@ -40,7 +41,6 @@ static const int signals_catch[] = { SIGINT, SIGQUIT, SIGTERM, SIGHUP, SIGCHLD, SIGUSR1, SIGUSR2 }; - #ifdef DEBUG static void @@ -57,7 +57,6 @@ Dump_State(void) #endif - static void Signal_Block(int sig) { @@ -73,7 +72,6 @@ Signal_Block(int sig) #endif } - static void Signal_Unblock(int sig) { @@ -90,7 +88,6 @@ Signal_Unblock(int sig) #endif } - /** * Reload the server configuration file. */ @@ -117,18 +114,21 @@ Rehash(void) * be changed during run-time */ if (strcmp(old_name, Conf_ServerName) != 0 ) { strlcpy(Conf_ServerName, old_name, sizeof Conf_ServerName); - Log(LOG_ERR, "Can't change \"ServerName\" on runtime! Ignored new name."); + Log(LOG_ERR, + "Can't change \"ServerName\" on runtime! Ignored new name."); } if (old_nicklen != Conf_MaxNickLength) { Conf_MaxNickLength = old_nicklen; - Log(LOG_ERR, "Can't change \"MaxNickLength\" on runtime! Ignored new value."); + Log(LOG_ERR, + "Can't change \"MaxNickLength\" on runtime! Ignored new value."); } /* Create new pre-defined channels */ Channel_InitPredefined( ); if (!ConnSSL_InitLibrary()) - Log(LOG_WARNING, "Re-Initializing SSL failed, using old keys"); + Log(LOG_WARNING, + "Re-Initializing of SSL failed, using old keys!"); /* Start listening on sockets */ Conn_InitListeners( ); @@ -139,7 +139,6 @@ Rehash(void) Log( LOG_NOTICE|LOG_snotice, "Re-reading of configuration done." ); } /* Rehash */ - /** * Signal handler of ngIRCd. * This function is called whenever ngIRCd catches a signal sent by the @@ -198,7 +197,6 @@ Signal_Handler(int Signal) Signal_Block(Signal); } /* Signal_Handler */ - /** * Signal processing handler of ngIRCd. * This function is called from the main conn event loop in (io_dispatch) @@ -231,7 +229,6 @@ Signal_Handler_BH(int Signal) Signal_Unblock(Signal); } - static void Signal_Callback(int fd, short UNUSED what) { @@ -248,15 +245,15 @@ Signal_Callback(int fd, short UNUSED what) if (errno == EAGAIN || errno == EINTR) return; - Log(LOG_EMERG, "read from signal pipe: %s", strerror(errno)); + Log(LOG_EMERG, "Read from signal pipe: %s - Exiting!", + strerror(errno)); exit(1); } - Log(LOG_EMERG, "EOF on signal pipe"); + Log(LOG_EMERG, "EOF on signal pipe!? - Exiting!"); exit(1); } - /** * Initialize the signal handlers, catch * those signals we are interested in and sets SIGPIPE to be ignored. @@ -306,7 +303,6 @@ Signals_Init(void) return io_event_create(signalpipe[0], IO_WANTREAD, Signal_Callback); } /* Signals_Init */ - /** * Restores signals to their default behaviour. * |