X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fngircd%2Firc-login.c;h=8e77e7fe34ddcefde11788fd00a5e15c0c7e77f9;hb=0c0d4af55ae6d098ccfabc258508a6b85b8c7449;hp=9a04a3f74cf29c3eba66208904f8615fbf520c47;hpb=d93030ad27af9cd6a807de8f672ae73ec0e1dff8;p=ngircd-alex.git diff --git a/src/ngircd/irc-login.c b/src/ngircd/irc-login.c index 9a04a3f7..8e77e7fe 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 @@ -40,7 +40,7 @@ static bool Hello_User PARAMS(( CLIENT *Client )); static void Kill_Nick PARAMS(( char *Nick, char *Reason )); -static void Introduce_Client PARAMS((CLIENT *To, CLIENT *Client)); +static void Introduce_Client PARAMS((CLIENT *To, CLIENT *Client, int Type)); static void cb_introduceClient PARAMS((CLIENT *Client, CLIENT *Prefix, void *i)); @@ -148,7 +148,6 @@ IRC_PASS( CLIENT *Client, REQUEST *Req ) } else { /* The peer seems to be a server supporting the * "original" IRC protocol (RFC 2813). */ - serverver = ""; if (strchr(orig_flags, 'Z')) flags = "Z"; else @@ -242,7 +241,7 @@ IRC_NICK( CLIENT *Client, REQUEST *Req ) Client_Type(target) != CLIENT_SERVICE && Client_Type(target) != CLIENT_SERVER) { /* New client */ - Log( LOG_DEBUG, "Connection %d: got valid NICK command ...", + LogDebug("Connection %d: got valid NICK command ...", Client_Conn( Client )); /* Register new nickname of this client */ @@ -322,18 +321,18 @@ IRC_NICK( CLIENT *Client, REQUEST *Req ) info = Req->argv[0]; } - /* Nick ueberpruefen */ c = Client_Search(nick); if(c) { - /* Der neue Nick ist auf diesem Server bereits registriert: - * sowohl der neue, als auch der alte Client muessen nun - * disconnectiert werden. */ + /* + * the new nick is already present on this server: + * the new and the old one have to be disconnected now. + */ Log( LOG_ERR, "Server %s introduces already registered nick \"%s\"!", Client_ID( Client ), Req->argv[0] ); Kill_Nick( Req->argv[0], "Nick collision" ); return CONNECTED; } - /* Server, zu dem der Client connectiert ist, suchen */ + /* Find the Server this client is connected to */ intr_c = Client_GetFromToken(Client, token); if( ! intr_c ) { @@ -342,14 +341,11 @@ IRC_NICK( CLIENT *Client, REQUEST *Req ) return CONNECTED; } - /* Neue Client-Struktur anlegen */ c = Client_NewRemoteUser(intr_c, nick, hops, user, hostname, token, modes, info, true); if( ! c ) { - /* Eine neue Client-Struktur konnte nicht angelegt werden. - * Der Client muss disconnectiert werden, damit der Netz- - * status konsistent bleibt. */ + /* out of memory, need to disconnect client to keep network state consistent */ Log( LOG_ALERT, "Can't create client structure! (on connection %d)", Client_Conn( Client )); Kill_Nick( Req->argv[0], "Server error" ); return CONNECTED; @@ -360,11 +356,11 @@ IRC_NICK( CLIENT *Client, REQUEST *Req ) * RFC 1459: announce the new client only after receiving the * USER command, first we need more information! */ if (Req->argc < 7) { - LogDebug("Client \"%s\" is beeing registered (RFC 1459) ...", + LogDebug("Client \"%s\" is being registered (RFC 1459) ...", Client_Mask(c)); Client_SetType(c, CLIENT_GOTNICK); } else - Introduce_Client(Client, c); + Introduce_Client(Client, c, CLIENT_USER); return CONNECTED; } @@ -448,7 +444,7 @@ IRC_USER(CLIENT * Client, REQUEST * Req) /* RFC 1459 style user registration? * Introduce client to network: */ if (Client_Type(c) == CLIENT_GOTNICK) - Introduce_Client(Client, c); + Introduce_Client(Client, c, CLIENT_USER); return CONNECTED; } else if (Client_Type(Client) == CLIENT_USER) { @@ -464,17 +460,25 @@ IRC_USER(CLIENT * Client, REQUEST * Req) /** - * Service registration. - * ngIRCd does not support services at the moment, so this function is a - * dummy that returns ERR_ERRONEUSNICKNAME on each call. + * Handler for the IRC command "SERVICE". + * This function implements IRC Services registration using the SERVICE command + * defined in RFC 2812 3.1.6 and RFC 2813 4.1.4. + * At the moment ngIRCd doesn't support directly linked services, so this + * function returns ERR_ERRONEUSNICKNAME when the SERVICE command has not been + * received from a peer server. */ GLOBAL bool IRC_SERVICE(CLIENT *Client, REQUEST *Req) { + CLIENT *c, *intr_c; + char *nick, *user, *host, *info, *modes, *ptr; + int token, hops; + assert(Client != NULL); assert(Req != NULL); - if (Client_Type(Client) != CLIENT_GOTPASS) + if (Client_Type(Client) != CLIENT_GOTPASS && + Client_Type(Client) != CLIENT_SERVER) return IRC_WriteStrClient(Client, ERR_ALREADYREGISTRED_MSG, Client_ID(Client)); @@ -482,11 +486,102 @@ IRC_SERVICE(CLIENT *Client, REQUEST *Req) return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, Client_ID(Client), Req->command); - return IRC_WriteStrClient(Client, ERR_ERRONEUSNICKNAME_MSG, + if (Client_Type(Client) != CLIENT_SERVER) + return IRC_WriteStrClient(Client, ERR_ERRONEUSNICKNAME_MSG, Client_ID(Client), Req->argv[0]); + + /* Bad number of parameters? */ + if (Req->argc != 6) + return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, + Client_ID(Client), Req->command); + + nick = Req->argv[0]; + user = NULL; host = NULL; + token = atoi(Req->argv[1]); + hops = atoi(Req->argv[4]); + info = Req->argv[5]; + + /* Validate service name ("nick name") */ + c = Client_Search(nick); + if(c) { + /* Nick name collission: disconnect (KILL) both clients! */ + Log(LOG_ERR, "Server %s introduces already registered service \"%s\"!", + Client_ID(Client), nick); + Kill_Nick(nick, "Nick collision"); + return CONNECTED; + } + + /* Get the server to which the service is connected */ + intr_c = Client_GetFromToken(Client, token); + if (! intr_c) { + Log(LOG_ERR, "Server %s introduces service \"%s\" on unknown server!?", + Client_ID(Client), nick); + Kill_Nick(nick, "Unknown server"); + return CONNECTED; + } + + /* Get user and host name */ + ptr = strchr(nick, '@'); + if (ptr) { + *ptr = '\0'; + host = ++ptr; + } + if (!host) + host = Client_Hostname(intr_c); + ptr = strchr(nick, '!'); + if (ptr) { + *ptr = '\0'; + user = ++ptr; + } + if (!user) + user = nick; + + /* According to RFC 2812/2813 parameter 4 "is currently reserved + * for future usage"; but we use it to transfer the modes and check + * that the first character is a '+' sign and ignore it otherwise. */ + modes = (Req->argv[3][0] == '+') ? ++Req->argv[3] : ""; + + c = Client_NewRemoteUser(intr_c, nick, hops, user, host, + token, modes, info, true); + if (! c) { + /* Couldn't create client structure, so KILL the service to + * keep network status consistent ... */ + Log(LOG_ALERT, "Can't create client structure! (on connection %d)", + Client_Conn(Client)); + Kill_Nick(nick, "Server error"); + return CONNECTED; + } + + Introduce_Client(Client, c, CLIENT_SERVICE); + return CONNECTED; } /* 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 ) { @@ -509,7 +604,6 @@ IRC_QUIT( CLIENT *Client, REQUEST *Req ) target = Client_Search( Req->prefix ); if( ! target ) { - /* Den Client kennen wir nicht (mehr), also nichts zu tun. */ Log( LOG_WARNING, "Got QUIT from %s for unknown client!?", Client_ID( Client )); return CONNECTED; } @@ -527,7 +621,7 @@ IRC_QUIT( CLIENT *Client, REQUEST *Req ) strlcat(quitmsg, "\"", sizeof quitmsg ); } - /* User, Service, oder noch nicht registriert */ + /* User, Service, or not yet registered */ Conn_Close( Client_Conn( Client ), "Got QUIT command.", Req->argc == 1 ? quitmsg : NULL, true); return DISCONNECTED; @@ -543,7 +637,6 @@ IRC_PING(CLIENT *Client, REQUEST *Req) assert(Client != NULL); assert(Req != NULL); - /* Wrong number of arguments? */ if (Req->argc < 1) return IRC_WriteStrClient(Client, ERR_NOORIGIN_MSG, Client_ID(Client)); @@ -649,7 +742,7 @@ 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) Log(LOG_DEBUG, "Connection %d: received PONG. Lag: %ld seconds.", @@ -658,7 +751,7 @@ IRC_PONG(CLIENT *Client, REQUEST *Req) else Log(LOG_DEBUG, "Connection %d: received PONG.", Client_Conn(Client)); - +#endif return CONNECTED; } /* IRC_PONG */ @@ -678,7 +771,7 @@ Hello_User(CLIENT * Client) return DISCONNECTED; } - Introduce_Client(NULL, Client); + Introduce_Client(NULL, Client, CLIENT_USER); if (!IRC_WriteStrClient (Client, RPL_WELCOME_MSG, Client_ID(Client), Client_Mask(Client))) @@ -733,25 +826,30 @@ Kill_Nick( char *Nick, char *Reason ) static void -Introduce_Client(CLIENT *From, CLIENT *Client) +Introduce_Client(CLIENT *From, CLIENT *Client, int Type) { - char *type; - - Client_SetType(Client, CLIENT_USER); + /* Set client type (user or service) */ + Client_SetType(Client, Type); if (From) { - if (Conf_IsService(Conf_GetServer(Client_Conn(From)), Client_ID(Client))) { - type = "Service"; + if (Conf_IsService(Conf_GetServer(Client_Conn(From)), + Client_ID(Client))) Client_SetType(Client, CLIENT_SERVICE); - } else - type = "User"; LogDebug("%s \"%s\" (+%s) registered (via %s, on %s, %d hop%s).", - type, Client_Mask(Client), Client_Modes(Client), - Client_ID(From), Client_ID(Client_Introducer(Client)), + Client_TypeText(Client), Client_Mask(Client), + Client_Modes(Client), Client_ID(From), + Client_ID(Client_Introducer(Client)), Client_Hops(Client), Client_Hops(Client) > 1 ? "s": ""); - } else - Log(LOG_NOTICE, "User \"%s\" registered (connection %d).", - Client_Mask(Client), Client_Conn(Client)); + } else { + Log(LOG_NOTICE, "%s \"%s\" registered (connection %d).", + Client_TypeText(Client), Client_Mask(Client), + Client_Conn(Client)); + Log_ServerNotice('c', "Client connecting: %s (%s@%s) [%s] - %s", + Client_ID(Client), Client_User(Client), + Client_Hostname(Client), + Conn_IPA(Client_Conn(Client)), + Client_TypeText(Client)); + } /* Inform other servers */ IRC_WriteStrServersPrefixFlag_CB(From, @@ -783,8 +881,17 @@ cb_introduceClient(CLIENT *To, CLIENT *Prefix, void *data) Conn_WriteStr(conn, ":%s MODE %s +%s", Client_ID(c), Client_ID(c), modes); } else { - /* RFC 2813 mode: one combined NICK command */ - IRC_WriteStrClientPrefix(To, Prefix, + /* RFC 2813 mode: one combined NICK or SERVICE command */ + if (Client_Type(c) == CLIENT_SERVICE + && strchr(Client_Flags(To), 'S')) + IRC_WriteStrClientPrefix(To, Prefix, + "SERVICE %s %d * +%s %d :%s", + Client_Mask(c), + Client_MyToken(Client_Introducer(c)), + Client_Modes(c), Client_Hops(c) + 1, + Client_Info(c)); + else + IRC_WriteStrClientPrefix(To, Prefix, "NICK %s %d %s %s %d +%s :%s", Client_ID(c), Client_Hops(c) + 1, user, host,