commit 162433398e320c45f3c8a523814518aa6b78372e from: Alexander Barton date: Sun Mar 27 17:33:48 2011 UTC New configuration option "RequireAuthPing": PING-PONG on login When enabled, this configuration option lets ngIRCd send a PING with an numeric "token" to clients logging in; and it will not become registered in the network until the client responds with the correct PONG. This is used by QuakeNet for example (ircu/snircd), and looks like this: NICK nick :irc.example.net PING :1858979527 USER user . . :real name PONG 1858979527 :irc.example.net 001 nick :Welcome to the Internet Relay Network ... commit - f1a4a4dc882e28affb0f2f3b940e5762df230ccd commit + 162433398e320c45f3c8a523814518aa6b78372e blob - ff4ff2ffa6285a2af8937b6df5bc1049edbe3bdc blob + fecf5d9798d97a03d5d12482a9becbfe0764b16f --- src/ngircd/client.h +++ src/ngircd/client.h @@ -26,6 +26,9 @@ #define CLIENT_SERVICE 64 /* client is a service */ #define CLIENT_UNKNOWNSERVER 128 /* unregistered server connection */ #define CLIENT_GOTPASS_2813 256 /* client did send PASS, RFC 2813 style */ +#ifndef STRICT_RFC +# define CLIENT_WAITAUTHPING 512 /* waiting for AUTH PONG from client */ +#endif #define CLIENT_TYPE int blob - 32461f3550ffb127332754e44ae0033bfbd73c86 blob + 452f744f0d103d906b8bfe905176848f687f2de8 --- src/ngircd/conf.c +++ src/ngircd/conf.c @@ -353,9 +353,12 @@ Conf_Test( void ) printf(" MaxJoins = %d\n", Conf_MaxJoins > 0 ? Conf_MaxJoins : -1); printf(" MaxNickLength = %u\n", Conf_MaxNickLength - 1); printf(" CloakHost = %s\n", Conf_CloakHost); - printf(" CloakUserToNick = %s\n\n", yesno_to_str(Conf_CloakUserToNick)); + printf(" CloakUserToNick = %s\n", yesno_to_str(Conf_CloakUserToNick)); +#ifndef STRICT_RFC + printf(" RequireAuthPing = %s\n", yesno_to_str(Conf_AuthPing)); +#endif - puts("[FEATURES]"); + printf("\n[FEATURES]\n"); printf(" DNS = %s\n", yesno_to_str(Conf_DNS)); printf(" Ident = %s\n", yesno_to_str(Conf_Ident)); printf(" PAM = %s\n", yesno_to_str(Conf_PAM)); @@ -641,6 +644,11 @@ Set_Defaults(bool InitServers) Conf_SyslogFacility = 0; #endif #endif + +#ifndef STRICT_RFC + Conf_AuthPing = false; +#endif + Set_Defaults_Optional(); /* Initialize server configuration structures */ @@ -1249,6 +1257,13 @@ Handle_GLOBAL( int Line, char *Var, char *Arg ) return; } #endif +#ifndef STRICT_RFC + if (strcasecmp(Var, "RequireAuthPing") == 0 ) { + /* Require new clients to do an "autheticatin PING-PONG" */ + Conf_AuthPing = Check_ArgIsTrue(Arg); + return; + } +#endif Config_Error(LOG_ERR, "%s, line %d (section \"Global\"): Unknown variable \"%s\"!", NGIRCd_ConfFile, Line, Var); } /* Handle_GLOBAL */ blob - 305ccaa1ff8c36540253f6283b43266d16fc043f blob + a183fcec56a0b010cb35b4bba134079f74b177de --- src/ngircd/conf.h +++ src/ngircd/conf.h @@ -199,6 +199,13 @@ GLOBAL int Conf_MaxConnectionsIP; /** Maximum length of a nick name */ GLOBAL unsigned int Conf_MaxNickLength; +#ifndef STRICT_RFC + +/** Require "AUTH PING-PONG" on login */ +GLOBAL bool Conf_AuthPing; + +#endif + #ifdef SYSLOG /* Syslog "facility" */ blob - 63093c25f64462b1468cc99bac2e4b7cea22e5a5 blob + 275215d6745ed9288c504c636014a11a1d8f175c --- src/ngircd/conn.c +++ src/ngircd/conn.c @@ -2281,8 +2281,27 @@ Conn_GetFromProc(int fd) } return NONE; } /* Conn_GetFromProc */ + +#ifndef STRICT_RFC +GLOBAL long +Conn_GetAuthPing(CONN_ID Idx) +{ + assert (Idx != NONE); + return My_Connections[Idx].auth_ping; +} /* Conn_GetAuthPing */ + +GLOBAL void +Conn_SetAuthPing(CONN_ID Idx, long ID) +{ + assert (Idx != NONE); + My_Connections[Idx].auth_ping = ID; +} /* Conn_SetAuthPing */ + +#endif + + #ifdef SSL_SUPPORT /** blob - 4228c9e41b933a3de5bd60e2638a78ecc895fc39 blob + c813729f9331e1c3897ed32f44505f851f782604 --- src/ngircd/conn.h +++ src/ngircd/conn.h @@ -91,6 +91,9 @@ typedef struct _Connection #ifdef SSL_SUPPORT struct ConnSSL_State ssl_state; /* SSL/GNUTLS state information */ #endif +#ifndef STRICT_RFC + long auth_ping; /** PING response expected on login */ +#endif } CONNECTION; GLOBAL CONNECTION *My_Connections; @@ -132,6 +135,11 @@ GLOBAL long Conn_Count PARAMS((void)); GLOBAL long Conn_CountMax PARAMS((void)); GLOBAL long Conn_CountAccepted PARAMS((void)); +#ifndef STRICT_RFC +GLOBAL long Conn_GetAuthPing PARAMS((CONN_ID Idx)); +GLOBAL void Conn_SetAuthPing PARAMS((CONN_ID Idx, long ID)); +#endif + #ifdef DEBUG GLOBAL void Conn_DebugDump PARAMS((void)); #endif blob - 92d54ab15e42ad64d2e7d05bd605bccc1cd7f734 blob + 2e99d66eeade7dfa36c25b6dd36f88a9c94f1c1e --- src/ngircd/irc-login.c +++ src/ngircd/irc-login.c @@ -271,6 +271,17 @@ IRC_NICK( CLIENT *Client, REQUEST *Req ) /* Register new nickname of this client */ Client_SetID( target, Req->argv[0] ); +#ifndef STRICT_RFC + if (Conf_AuthPing) { + Conn_SetAuthPing(Client_Conn(Client), random()); + IRC_WriteStrClient(Client, "PING :%ld", + Conn_GetAuthPing(Client_Conn(Client))); + LogDebug("Connection %d: sent AUTH PING %ld ...", + Client_Conn(Client), + Conn_GetAuthPing(Client_Conn(Client))); + } +#endif + /* If we received a valid USER command already then * register the new client! */ if( Client_Type( Client ) == CLIENT_GOTUSER ) @@ -797,18 +808,32 @@ GLOBAL bool IRC_PONG(CLIENT *Client, REQUEST *Req) { CLIENT *target, *from; + CONN_ID conn; +#ifndef STRICT_RFC + long auth_ping; +#endif char *s; assert(Client != NULL); assert(Req != NULL); /* Wrong number of arguments? */ - if (Req->argc < 1) - return IRC_WriteStrClient(Client, ERR_NOORIGIN_MSG, - Client_ID(Client)); - if (Req->argc > 2) - return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, - Client_ID(Client), Req->command); + if (Req->argc < 1) { + if (Client_Type(Client) == CLIENT_USER) + return IRC_WriteStrClient(Client, ERR_NOORIGIN_MSG, + Client_ID(Client)); + else + return CONNECTED; + } + if (Req->argc > 2) { + if (Client_Type(Client) == CLIENT_USER) + return IRC_WriteStrClient(Client, + ERR_NEEDMOREPARAMS_MSG, + Client_ID(Client), + Req->command); + else + return CONNECTED; + } /* Forward? */ if (Req->argc == 2 && Client_Type(Client) == CLIENT_SERVER) { @@ -837,15 +862,35 @@ IRC_PONG(CLIENT *Client, REQUEST *Req) /* The connection timestamp has already been updated when the data has * been read from so socket, so we don't need to update it here. */ -#ifdef DEBUG - if (Client_Conn(Client) > NONE) + + conn = Client_Conn(Client); + +#ifndef STRICT_RFC + /* Check authentication PING-PONG ... */ + auth_ping = Conn_GetAuthPing(conn); + if (auth_ping) { + LogDebug("AUTH PONG: waiting for token \"%ld\", got \"%s\" ...", + auth_ping, Req->argv[0]); + if (auth_ping == atoi(Req->argv[0])) { + Conn_SetAuthPing(conn, 0); + if (Client_Type(Client) == CLIENT_WAITAUTHPING) + Hello_User(Client); + } else + if (!IRC_WriteStrClient(Client, + "To connect, type /QUOTE PONG %ld", + auth_ping)) + return DISCONNECTED; + } +#endif + +#ifdef DEBUG + if (conn > NONE) Log(LOG_DEBUG, - "Connection %d: received PONG. Lag: %ld seconds.", - Client_Conn(Client), + "Connection %d: received PONG. Lag: %ld seconds.", conn, time(NULL) - Conn_LastPing(Client_Conn(Client))); else Log(LOG_DEBUG, - "Connection %d: received PONG.", Client_Conn(Client)); + "Connection %d: received PONG.", conn); #endif return CONNECTED; } /* IRC_PONG */ @@ -867,12 +912,25 @@ Hello_User(CLIENT * Client) { #ifdef PAM int pipefd[2], result; - CONN_ID conn; pid_t pid; +#endif + CONN_ID conn; assert(Client != NULL); conn = Client_Conn(Client); + +#ifndef STRICT_RFC + if (Conf_AuthPing) { + /* Did we receive the "auth PONG" already? */ + if (Conn_GetAuthPing(conn)) { + Client_SetType(Client, CLIENT_WAITAUTHPING); + LogDebug("Connection %d: Waiting for AUTH PONG ...", conn); + return CONNECTED; + } + } +#endif +#ifdef PAM if (!Conf_PAM) { /* Don't do any PAM authentication at all, instead emulate * the beahiour of the daemon compiled without PAM support: @@ -903,8 +961,6 @@ Hello_User(CLIENT * Client) exit(0); } #else - assert(Client != NULL); - /* Check global server password ... */ if (strcmp(Client_Password(Client), Conf_ServerPwd) != 0) { /* Bad password! */ blob - 4b49ec6cce56ba599616dce9049b1b15f99fad39 blob + 74a998800f364376a87efb290cd2d0dc030a2ab4 --- src/ngircd/ngircd.c +++ src/ngircd/ngircd.c @@ -288,6 +288,8 @@ main( int argc, const char *argv[] ) Log(LOG_ALERT, "Fatal: Could not set up signal handlers: %s", strerror(errno)); exit(1); } + + srandom(getpid()); /* Create protocol and server identification. The syntax * used by ngIRCd in PASS commands and the known "extended blob - 31f048cf673408f08737647d66b8aba0bc807612 blob + 8f5e6019694a53807d023b4df9010c281ad10d0b --- src/ngircd/parse.c +++ src/ngircd/parse.c @@ -82,7 +82,7 @@ static COMMAND My_Commands[] = { "PART", IRC_PART, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 }, { "PASS", IRC_PASS, 0xFFFF, 0, 0, 0 }, { "PING", IRC_PING, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 }, - { "PONG", IRC_PONG, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 }, + { "PONG", IRC_PONG, 0xFFFF, 0, 0, 0 }, { "PRIVMSG", IRC_PRIVMSG, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 }, { "QUIT", IRC_QUIT, 0xFFFF, 0, 0, 0 }, { "REHASH", IRC_REHASH, CLIENT_USER, 0, 0, 0 },