commit d61fbfc6e3a0a85ced036d8c1fa161fab0d9ba3d from: Alexander Barton date: Sun Mar 27 18:58:18 2011 UTC Merge branch 'AuthPing' * AuthPing: Add documentation for "RequireAuthPing" configuration option New configuration option "RequireAuthPing": PING-PONG on login commit - cf7e3b1c0201ec298acb43e52dc1f05abcb8c80d commit + d61fbfc6e3a0a85ced036d8c1fa161fab0d9ba3d blob - f9c96562e45ac1ce9b6d215d3ac47531caf3a1b3 blob + b5a36b843ca35505f1d05d61d42cf14f00ae5ec9 --- doc/sample-ngircd.conf.tmpl +++ 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! blob - b2ce02caa9eb97d6595ab48342f03c72f1ab93d6 blob + d1a0a64a8996a483edebc868a9f13931bbbf4381 --- man/ngircd.conf.5.tmpl +++ man/ngircd.conf.5.tmpl @@ -256,6 +256,11 @@ Normally ngIRCd doesn't send any messages to a client 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. 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 - 568b9e7a9bb2d068de5a35399af2328799e702bf blob + a00049eef97cc29630a6d22af8e556f7efd61a2c --- src/ngircd/conf.c +++ 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 */ @@ -1256,6 +1264,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 - 1633bc998932abea1176bfefc4686f52ed07caf5 blob + 80d18187db9c16932fb78a6df59c735d244e1195 --- src/ngircd/conf.h +++ 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" */ blob - 9d17a7382ff5283d34e5b0677790df1a5c2071f9 blob + cc4364c4635b8e55c7fb04ba9da3ce29d40d27f7 --- src/ngircd/conn.c +++ src/ngircd/conn.c @@ -2301,8 +2301,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 },