From: Alexander Barton Date: Sun, 27 Mar 2011 18:58:18 +0000 (+0200) Subject: Merge branch 'AuthPing' X-Git-Tag: rel-18-rc1~25 X-Git-Url: https://arthur.barton.de/gitweb/?a=commitdiff_plain;h=d61fbfc6e3a0a85ced036d8c1fa161fab0d9ba3d;hp=cf7e3b1c0201ec298acb43e52dc1f05abcb8c80d;p=ngircd.git Merge branch 'AuthPing' * AuthPing: Add documentation for "RequireAuthPing" configuration option New configuration option "RequireAuthPing": PING-PONG on login --- diff --git a/doc/sample-ngircd.conf.tmpl b/doc/sample-ngircd.conf.tmpl index f9c96562..b5a36b84 100644 --- a/doc/sample-ngircd.conf.tmpl +++ b/doc/sample-ngircd.conf.tmpl @@ -159,6 +159,11 @@ # messages to clients while connecting. ;NoticeAuth = no + # Let ngIRCd send an "authentication PING" when a new client connects, + # and register this client only after receiving the corresponding + # "PONG" reply. + ;RequireAuthPing = no + # Set this hostname for every client instead of the real one. # Please note: don't use the percentage sign ("%"), it is reserved for # future extensions! diff --git a/man/ngircd.conf.5.tmpl b/man/ngircd.conf.5.tmpl index b2ce02ca..d1a0a64a 100644 --- a/man/ngircd.conf.5.tmpl +++ b/man/ngircd.conf.5.tmpl @@ -256,6 +256,11 @@ Normally ngIRCd doesn't send any messages to a client until it is registered. Enable this option to let the daemon send "NOTICE AUTH" messages to clients while connecting. Default: no. .TP +\fBRequireAuthPing\fR (boolean) +Let ngIRCd send an "authentication PING" when a new client connects, and +register this client only after receiving the corresponding "PONG" reply. +Default: no. +.TP \fBCloakHost\fR (string) Set this hostname for every client instead of the real one. Default: empty, don't change. diff --git a/src/ngircd/client.h b/src/ngircd/client.h index ff4ff2ff..fecf5d97 100644 --- a/src/ngircd/client.h +++ b/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 diff --git a/src/ngircd/conf.c b/src/ngircd/conf.c index 568b9e7a..a00049ee 100644 --- a/src/ngircd/conf.c +++ b/src/ngircd/conf.c @@ -354,9 +354,12 @@ Conf_Test( void ) printf(" MaxNickLength = %u\n", Conf_MaxNickLength - 1); printf(" NoticeAuth = %s\n", yesno_to_str(Conf_NoticeAuth)); 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)); @@ -643,6 +646,11 @@ Set_Defaults(bool InitServers) Conf_SyslogFacility = 0; #endif #endif + +#ifndef STRICT_RFC + Conf_AuthPing = false; +#endif + Set_Defaults_Optional(); /* Initialize server configuration structures */ @@ -1255,6 +1263,13 @@ Handle_GLOBAL( int Line, char *Var, char *Arg ) Conf_SyslogFacility); 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); diff --git a/src/ngircd/conf.h b/src/ngircd/conf.h index 1633bc99..80d18187 100644 --- a/src/ngircd/conf.h +++ b/src/ngircd/conf.h @@ -202,6 +202,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" */ diff --git a/src/ngircd/conn.c b/src/ngircd/conn.c index 9d17a738..cc4364c4 100644 --- a/src/ngircd/conn.c +++ b/src/ngircd/conn.c @@ -2303,6 +2303,25 @@ Conn_GetFromProc(int fd) } /* 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 /** diff --git a/src/ngircd/conn.h b/src/ngircd/conn.h index 4228c9e4..c813729f 100644 --- a/src/ngircd/conn.h +++ b/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 diff --git a/src/ngircd/irc-login.c b/src/ngircd/irc-login.c index 92d54ab1..2e99d66e 100644 --- a/src/ngircd/irc-login.c +++ b/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. */ + + 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 (Client_Conn(Client) > NONE) + 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! */ diff --git a/src/ngircd/ngircd.c b/src/ngircd/ngircd.c index 4b49ec6c..74a99880 100644 --- a/src/ngircd/ngircd.c +++ b/src/ngircd/ngircd.c @@ -289,6 +289,8 @@ main( int argc, const char *argv[] ) exit(1); } + srandom(getpid()); + /* Create protocol and server identification. The syntax * used by ngIRCd in PASS commands and the known "extended * flags" are described in doc/Protocol.txt. */ diff --git a/src/ngircd/parse.c b/src/ngircd/parse.c index 31f048cf..8f5e6019 100644 --- a/src/ngircd/parse.c +++ b/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 },