X-Git-Url: http://git.pk910.de/?p=ircu2.10.12-pk.git;a=blobdiff_plain;f=patches%2Fdiffs%2Flogin-on-connect.diff;fp=patches%2Fdiffs%2Flogin-on-connect.diff;h=8fad5dba7c2be914d800f1d0f7ca45325ffbfbe0;hp=0000000000000000000000000000000000000000;hb=0400a5a6479398d82526785c18c0df8bc8b92dce;hpb=d17e10da972ce5776c60b4c317267c6abe0e1ead diff --git a/patches/diffs/login-on-connect.diff b/patches/diffs/login-on-connect.diff new file mode 100644 index 0000000..8fad5db --- /dev/null +++ b/patches/diffs/login-on-connect.diff @@ -0,0 +1,576 @@ +Index: ChangeLog +=================================================================== +RCS file: /home/coder-com/cvs/ircu2.10/ChangeLog,v +retrieving revision 1.340 +diff -u -r1.340 ChangeLog +--- ChangeLog 2002/04/12 00:19:52 1.340 ++++ ChangeLog 2002/04/12 13:17:10 +@@ -1,5 +1,33 @@ + 2002-04-12 Alex Badea + ++ * include/ircd_features.h: new feature LOGIN_ON_CONNECT ++ ++ * ircd/ircd_features.c: new feature LOGIN_ON_CONNECT ++ ++ * include/client.h (struct Client): new fields for storing ++ bot name, username and password for login-on-connect ++ ++ * ircd/m_account.c: extensions for login-on-connect: route ++ and process auth-request and auth-reply messages ++ ++ * ircd/m_pass.c: store bot name, username and password for ++ service login ++ ++ * ircd/m_user.c: store username/hostname for the client ++ even if he finished registration, as register_user may not ++ do that anymore ++ ++ * ircd/s_user.c (register_user): if the client specified ++ a service login in the PASS command, attempt to log him in; ++ also, don't set his hostname if it was set remotely by a ++ service bot ++ ++ * doc/example.conf: default value for FEAT_LOGIN_ON_CONNECT ++ ++ * doc/readme.features: documented FEAT_LOGIN_ON_CONNECT ++ ++2002-04-12 Alex Badea ++ + * ircd/m_invite.c: don't propagate invites for local channels + + * include/patchlevel.h (PATCHLEVEL): bump patchlevel +Index: doc/example.conf +=================================================================== +RCS file: /home/coder-com/cvs/ircu2.10/doc/example.conf,v +retrieving revision 1.20 +diff -u -r1.20 example.conf +--- doc/example.conf 2002/04/03 15:23:47 1.20 ++++ doc/example.conf 2002/04/12 13:17:10 +@@ -702,6 +702,7 @@ + # "HOST_HIDING"="FALSE"; + # "HIDDEN_HOST"="users.undernet.org"; + # "HIDDEN_IP"="127.0.0.1"; ++# "LOGIN_ON_CONNECT"="FALSE"; + # "KILLCHASETIMELIMIT"="30"; + # "MAXCHANNELSPERUSER"="10"; + # "AVBANLEN"="40"; +Index: doc/readme.features +=================================================================== +RCS file: /home/coder-com/cvs/ircu2.10/doc/readme.features,v +retrieving revision 1.5 +diff -u -r1.5 readme.features +--- doc/readme.features 2002/04/03 15:23:47 1.5 ++++ doc/readme.features 2002/04/12 13:17:10 +@@ -242,6 +242,13 @@ + This selects a fake IP to be shown on /USERIP and /WHO %i when the + target has a hidden host (see HOST_HIDING). + ++LOGIN_ON_CONNECT ++ * Type: boolean ++ * Default: FALSE ++ ++This selects whether local clients can use specify a service bot login ++in the connection phase. Read readme.login-on-connect for more details. ++ + KILLCHASETIMELIMIT + * Type: integer + * Default: 30 +Index: include/client.h +=================================================================== +RCS file: /home/coder-com/cvs/ircu2.10/include/client.h,v +retrieving revision 1.26 +diff -u -r1.26 client.h +--- include/client.h 2002/04/05 11:36:58 1.26 ++++ include/client.h 2002/04/12 13:17:10 +@@ -196,6 +196,10 @@ + char cli_name[HOSTLEN + 1]; /* Unique name of the client, nick or host */ + char cli_username[USERLEN + 1]; /* username here now for auth stuff */ + char cli_info[REALLEN + 1]; /* Free form additional client information */ ++ ++ char *cli_cs_user; /* channel service authentication (user)... */ ++ char *cli_cs_pass; /* ...and password... */ ++ char *cli_cs_service; /* ...and the service bot's nick */ + }; + + #define CLIENT_MAGIC 0x4ca08286 +Index: include/ircd_features.h +=================================================================== +RCS file: /home/coder-com/cvs/ircu2.10/include/ircd_features.h,v +retrieving revision 1.15 +diff -u -r1.15 ircd_features.h +--- include/ircd_features.h 2002/04/03 15:23:47 1.15 ++++ include/ircd_features.h 2002/04/12 13:17:10 +@@ -45,6 +45,7 @@ + FEAT_HOST_HIDING, + FEAT_HIDDEN_HOST, + FEAT_HIDDEN_IP, ++ FEAT_LOGIN_ON_CONNECT, + + /* features that probably should not be touched */ + FEAT_KILLCHASETIMELIMIT, +Index: ircd/ircd_features.c +=================================================================== +RCS file: /home/coder-com/cvs/ircu2.10/ircd/ircd_features.c,v +retrieving revision 1.19 +diff -u -r1.19 ircd_features.c +--- ircd/ircd_features.c 2002/04/03 15:23:48 1.19 ++++ ircd/ircd_features.c 2002/04/12 13:17:10 +@@ -252,6 +252,7 @@ + F_B(HOST_HIDING, 0, 0, 0), + F_S(HIDDEN_HOST, FEAT_CASE, "users.undernet.org", 0), + F_S(HIDDEN_IP, 0, "127.0.0.1", 0), ++ F_B(LOGIN_ON_CONNECT, 0, 0, 0), + + /* features that probably should not be touched */ + F_I(KILLCHASETIMELIMIT, 0, 30, 0), +Index: ircd/m_account.c +=================================================================== +RCS file: /home/coder-com/cvs/ircu2.10/ircd/m_account.c,v +retrieving revision 1.2 +diff -u -r1.2 m_account.c +--- ircd/m_account.c 2002/02/14 00:20:42 1.2 ++++ ircd/m_account.c 2002/04/12 13:17:10 +@@ -84,9 +84,11 @@ + #include "ircd.h" + #include "ircd_reply.h" + #include "ircd_string.h" ++#include "ircd_alloc.h" + #include "msg.h" + #include "numnicks.h" + #include "s_user.h" ++#include "s_debug.h" + #include "send.h" + + #include +@@ -96,35 +98,108 @@ + * + * parv[0] = sender prefix + * parv[1] = numeric of client to act on +- * parv[2] = account name (12 characters or less) ++ * parv[2] = message type ++ * ++ * for *parv[2] == 'R' (remote auth): ++ * parv[3] = account name (12 characters or less) ++ * ++ * for *parv[2] == 'C' (auth check): ++ * parv[3] = numeric of client to check ++ * parv[4] = username ++ * parv[parc-1] = password ++ * ++ * for *parv[2] == 'A' (auth ok) or ++ * for *parv[2] == 'D' (auth denied) or ++ * parv[3] = numeric of client to check + */ + int ms_account(struct Client* cptr, struct Client* sptr, int parc, + char* parv[]) + { + struct Client *acptr; ++ char type; + + if (parc < 3) + return need_more_params(sptr, "ACCOUNT"); ++ ++ if (parc < 4) { ++ /* old-style message, remap it */ ++ parv[4] = NULL; ++ parv[3] = parv[2]; ++ parv[2] = "R"; ++ } + + if (!IsServer(sptr)) + return protocol_violation(cptr, "ACCOUNT from non-server %s", + cli_name(sptr)); +- +- if (!(acptr = findNUser(parv[1]))) +- return 0; /* Ignore ACCOUNT for a user that QUIT; probably crossed */ +- +- if (IsAccount(acptr)) +- return protocol_violation(cptr, "ACCOUNT for already registered user %s " +- "(%s -> %s)", cli_name(acptr), +- cli_user(acptr)->account, parv[2]); +- +- assert(0 == cli_user(acptr)->account[0]); +- +- ircd_strncpy(cli_user(acptr)->account, parv[2], ACCOUNTLEN); +- hide_hostmask(acptr, FLAGS_ACCOUNT); + +- sendcmdto_serv_butone(sptr, CMD_ACCOUNT, cptr, "%C %s", acptr, +- cli_user(acptr)->account); ++ type = *parv[2]; ++ if (type == 'R') { ++ if (!(acptr = findNUser(parv[1]))) ++ return 0; /* Ignore ACCOUNT for a user that QUIT; probably crossed */ ++ ++ if (IsAccount(acptr)) ++ return protocol_violation(cptr, "ACCOUNT for already registered user %s " ++ "(%s -> %s)", cli_name(acptr), ++ cli_user(acptr)->account, parv[3]); ++ ++ assert(0 == cli_user(acptr)->account[0]); ++ ++ ircd_strncpy(cli_user(acptr)->account, parv[3], ACCOUNTLEN); ++ hide_hostmask(acptr, FLAGS_ACCOUNT); ++ ++#if 0 ++ /* XXX Enable this when all servers speak the same language */ ++ sendcmdto_serv_butone(sptr, CMD_ACCOUNT, cptr, "%C R %s", acptr, ++ cli_user(acptr)->account); ++#else ++ sendcmdto_serv_butone(sptr, CMD_ACCOUNT, cptr, "%C %s", acptr, ++ cli_user(acptr)->account); ++#endif ++ } else { ++ if (!(acptr = findNUser(parv[1])) && !(acptr = FindNServer(parv[1]))) ++ return 0; ++ ++ if (type == 'C' && parc < 6) ++ return need_more_params(sptr, "ACCOUNT"); ++ ++ if (!IsMe(acptr)) { ++ /* in-transit message, forward it */ ++ sendcmdto_one(sptr, CMD_ACCOUNT, acptr, ++ type == 'C' ? "%C %s %s %s :%s" : "%C %s %s", ++ acptr, parv[2], parv[3], parv[4], parv[parc-1]); ++ return 0; ++ } ++ ++ /* the message is for me, process it */ ++ if (type == 'C') ++ return protocol_violation(cptr, "ACCOUNT check (%s %s %s)", parv[3], parv[4], parv[parc-1]); ++ ++ if (!(acptr = findNUser(parv[3]))) ++ return 0; ++ if (IsRegistered(acptr) || !acptr->cli_cs_service) ++ return protocol_violation(cptr, "Invalid ACCOUNT %s for %s", parv[2], cli_name(acptr)); ++ ++ if (type == 'A') { ++ ircd_strncpy(cli_user(acptr)->account, acptr->cli_cs_user, ACCOUNTLEN); ++ hide_hostmask(acptr, FLAGS_ACCOUNT | FLAGS_HIDDENHOST); ++ } ++ ++ sendcmdto_one(&me, CMD_NOTICE, acptr, "%C :AUTHENTICATION %s as %s", acptr, ++ type == 'A' ? "SUCCESSFUL" : "FAILED", ++ acptr->cli_cs_user); ++ ++ MyFree(acptr->cli_cs_service); ++ MyFree(acptr->cli_cs_user); ++ MyFree(acptr->cli_cs_pass); ++ acptr->cli_cs_service = acptr->cli_cs_user = acptr->cli_cs_pass = NULL; ++ ++ if (type != 'A') { ++ sendcmdto_one(&me, CMD_NOTICE, acptr, "%C :Type /QUOTE PASS to connect anyway", acptr); ++ return 0; ++ } ++ ++ return register_user(acptr, acptr, cli_name(acptr), cli_user(acptr)->username); ++ } + + return 0; + } +Index: ircd/m_pass.c +=================================================================== +RCS file: /home/coder-com/cvs/ircu2.10/ircd/m_pass.c,v +retrieving revision 1.7 +diff -u -r1.7 m_pass.c +--- ircd/m_pass.c 2001/06/29 15:51:02 1.7 ++++ ircd/m_pass.c 2002/04/12 13:17:10 +@@ -84,7 +84,11 @@ + #include "client.h" + #include "ircd_reply.h" + #include "ircd_string.h" ++#include "ircd_alloc.h" ++#include "ircd_features.h" ++#include "s_user.h" + #include "send.h" ++#include "struct.h" + + #include + +@@ -99,15 +103,28 @@ + assert(cptr == sptr); + assert(!IsRegistered(sptr)); + +- if (EmptyString(password)) +- return need_more_params(cptr, "PASS"); +- + /* TODO: For protocol negotiation */ + #if 0 + if (ircd_strcmp(password,"PROT")==0) { + /* Do something here */ + } + #endif +- ircd_strncpy(cli_passwd(cptr), password, PASSWDLEN); ++ ++ if (!EmptyString(password)) ++ ircd_strncpy(cli_passwd(cptr), password, PASSWDLEN); ++ ++ if (!feature_bool(FEAT_LOGIN_ON_CONNECT) || cptr->cli_cs_service) ++ return 0; ++ ++ if (parc > 3) { ++ DupString(cptr->cli_cs_service, parv[parc-3]); ++ DupString(cptr->cli_cs_user, parv[parc-2]); ++ DupString(cptr->cli_cs_pass, parv[parc-1]); ++ } ++ ++ /* Deal with password retries */ ++ if ((cli_name(cptr))[0] && cli_cookie(cptr) == COOKIE_VERIFIED) ++ return register_user(cptr, cptr, cli_name(cptr), cli_user(cptr)->username); ++ + return 0; + } +Index: ircd/m_user.c +=================================================================== +RCS file: /home/coder-com/cvs/ircu2.10/ircd/m_user.c,v +retrieving revision 1.7 +diff -u -r1.7 m_user.c +--- ircd/m_user.c 2001/06/08 23:12:17 1.7 ++++ ircd/m_user.c 2002/04/12 13:17:10 +@@ -142,16 +142,14 @@ + + user->server = &me; + ircd_strncpy(cli_info(cptr), info, REALLEN); ++ ircd_strncpy(user->username, username, USERLEN); ++ ircd_strncpy(user->host, cli_sockhost(cptr), HOSTLEN); + + if ((cli_name(cptr))[0] && cli_cookie(cptr) == COOKIE_VERIFIED) { + /* + * NICK and PONG already received, now we have USER... + */ + return register_user(cptr, sptr, cli_name(sptr), username); +- } +- else { +- ircd_strncpy(user->username, username, USERLEN); +- ircd_strncpy(user->host, cli_sockhost(cptr), HOSTLEN); + } + return 0; + } +Index: ircd/s_user.c +=================================================================== +RCS file: /home/coder-com/cvs/ircu2.10/ircd/s_user.c,v +retrieving revision 1.58 +diff -u -r1.58 s_user.c +--- ircd/s_user.c 2002/04/05 11:36:59 1.58 ++++ ircd/s_user.c 2002/04/12 13:17:10 +@@ -394,6 +394,25 @@ + parv[0] = cli_name(sptr); + parv[1] = parv[2] = NULL; + ++ if (MyConnect(sptr) && sptr->cli_cs_service && sptr->cli_cs_user && sptr->cli_cs_pass) { ++ struct Client *acptr; ++ ++ if (!(acptr = FindUser(sptr->cli_cs_service)) || !IsChannelService(acptr)) { ++ sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Service '%s' is not available", sptr, sptr->cli_cs_service); ++ sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Type /QUOTE PASS to connect anyway", sptr); ++ MyFree(sptr->cli_cs_service); ++ MyFree(sptr->cli_cs_user); ++ MyFree(sptr->cli_cs_pass); ++ sptr->cli_cs_service = sptr->cli_cs_user = sptr->cli_cs_pass = NULL; ++ } else { ++ sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Attempting service login to %s", ++ sptr, cli_name(acptr)); ++ sendcmdto_one(&me, CMD_ACCOUNT, acptr, "%C C %s%s %s :%s", acptr, ++ NumNick(sptr), sptr->cli_cs_user, sptr->cli_cs_pass); ++ } ++ return 0; ++ } ++ + if (MyConnect(sptr)) + { + static time_t last_too_many1; +@@ -441,7 +460,9 @@ + IPcheck_connect_fail(cli_ip(sptr)); + return exit_client(cptr, sptr, &me, "Unknown error -- Try again"); + } +- ircd_strncpy(user->host, cli_sockhost(sptr), HOSTLEN); ++ /* The host might be already set from login-on-connect */ ++ if (!HasHiddenHost(sptr)) ++ ircd_strncpy(user->host, cli_sockhost(sptr), HOSTLEN); + ircd_strncpy(user->realhost, cli_sockhost(sptr), HOSTLEN); + aconf = cli_confs(sptr)->value.aconf; + +--- /dev/null Thu Aug 24 12:00:32 2000 ++++ doc/readme.login-on-connect Fri Apr 12 16:16:56 2002 +@@ -0,0 +1,182 @@ ++1. This feature is experimental. ++ ++2. The main point is to allow clients to log in to a service bot (i.e., X) ++*before* being announced to the network. Otherwise, a combination of a ++malicious user, /ISON, /USERIP and low latency can reveal it's real host/IP ++before he gets a chance to log in and set himself +x ++ ++3. Client<->Server changes: ++~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++The PASS command now has the following syntax: ++ ++PASS [optional Client block password] : ++ ++If the client specifies sends such a password message, after sending NICK, ++USER and PONG, it's username/passphrase are sent to the specified bot ++for validation, while holding the client in the 'registration' state. ++If the authentication succeeds, the client's account and umode +x are set, ++after which he is introduced to the network, continuing the regular connect ++phase. If authentication fails (or the bot is not on the network), the user ++is given a chance to retry (he can do this by sending another PASS command), ++or to disconnect from the server. If he wishes to connect without a hidden ++hostmask, he can send a PASS command with no parameters. ++ ++4. Server<->Server changes: ++~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++The ACCOUNT message now has the following syntax: ++ ++Auth check: ++ AC C : ++Servers send this message to request a service bot to authenticate the client. ++Note that will only be used by the originating server for ++matching auth replies, as the user has not yet been announced to the network. ++Hubs will have to propagate this message as-is towards the service bot, ++much like they do for PRIVMSGs. ++ ++Auth reply: ++ AC A|D ++Service bots send this in reply to an 'auth check' message from a server. ++"A" stands for "accepted", "D" for "denied". Again, hubs will have ++to proagate this message back to the client's server. ++ ++Remote auth: ++ AC R ++This is the current message used by service bots to announce the network ++that a user has logged in. The old format is still supported: ++ AC ++ ++5. ircu code changes ++~~~~~~~~~~~~~~~~~~~~ ++A new feature, FEAT_LOGIN_ON_CONNECT (default FALSE) will specify whether ++ircu will honour the login scheme as specified above for the PASS command. ++ircu will route ACCOUNT messages anyway, regardless of this feature's value. ++ ++6. GNUWorld patches ++~~~~~~~~~~~~~~~~~~~ ++A patch follows that will implement auth checks and replies. ++ ++Index: mod.cservice/cservice.cc ++=================================================================== ++RCS file: /cvsroot/gnuworld/gnuworld/mod.cservice/cservice.cc,v ++retrieving revision 1.213 ++diff -u -r1.213 cservice.cc ++--- mod.cservice/cservice.cc 10 Apr 2002 19:00:10 -0000 1.213 +++++ mod.cservice/cservice.cc 12 Apr 2002 12:33:45 -0000 ++@@ -2491,15 +2491,45 @@ ++ { ++ case EVT_ACCOUNT: ++ { ++- iClient* tmpUser = static_cast< iClient* >( data1 ) ; ++- networkData* tmpData = static_cast< networkData* >(tmpUser->getCustomData(this) ) ; ++- /* Lookup this user account, if its not there.. trouble */ ++- sqlUser* theUser = getUserRecord(tmpUser->getAccount()); ++- if (theUser) ++- { ++- tmpData->currentUser = theUser; ++- theUser->addAuthedClient(tmpUser); +++ char *ac_type = static_cast (data1); +++ if (*ac_type == 'R') { +++ iClient* tmpUser = static_cast< iClient* >( data2 ) ; +++ networkData* tmpData = static_cast< networkData* >(tmpUser->getCustomData(this) ) ; +++ /* Lookup this user account, if its not there.. trouble */ +++ sqlUser* theUser = getUserRecord(tmpUser->getAccount()); +++ if (theUser) +++ { +++ tmpData->currentUser = theUser; +++ theUser->addAuthedClient(tmpUser); +++ } +++ } else if (*ac_type == 'C') { +++ // server prefix, client prefix, username, password +++ char **param_list = static_cast (data2); +++ sqlUser* theUser = getUserRecord(param_list[2]); +++ strstream ac; +++ +++ LogDebugMessage("Checking account: user=%s pass=%s ok=%d susp=%d maxlog=%d/%d", +++ param_list[2], +++ param_list[3], +++ isPasswordRight(theUser, param_list[3]), +++ theUser->getFlag(sqlUser::F_GLOBAL_SUSPEND), +++ theUser->networkClientList.size() + 1, +++ theUser->getMaxLogins()); +++ +++ ac << getCharYY() << " AC " << param_list[0]; +++ +++ if (theUser && !theUser->getFlag(sqlUser::F_GLOBAL_SUSPEND) && +++ isPasswordRight(theUser, param_list[3]) && +++ theUser->networkClientList.size() + 1 <= theUser->getMaxLogins()) { +++ ac << " A "; +++ } else { +++ ac << " D "; ++ } +++ +++ ac << param_list[1] << ends; +++ Write(ac); +++ delete[] ac.str(); +++ } ++ break; ++ } ++ case EVT_BURST_ACK: ++Index: src/msg_AC.cc ++=================================================================== ++RCS file: /cvsroot/gnuworld/gnuworld/src/msg_AC.cc,v ++retrieving revision 1.1 ++diff -u -r1.1 msg_AC.cc ++--- src/msg_AC.cc 12 Jan 2002 21:42:17 -0000 1.1 +++++ src/msg_AC.cc 12 Apr 2002 12:33:46 -0000 ++@@ -14,23 +14,48 @@ ++ * SOURCE AC TARGET ACCOUNT ++ * Eg: ++ * AXAAA AC BQrTd Gte +++ * +++ * AX AC BQrTd R Gte +++ * BQ AC AX C BqrTd Gte :Gte's Pass ++ */ ++-int xServer::MSG_AC( xParameters& Param ) +++int xServer::MSG_AC(xParameters &Param) ++ { ++ /* ++ * First, update this users information. ++ */ ++ ++-iClient* theClient = Network->findClient(Param[1]); ++-if(!theClient) ++- { ++- return 0; ++- } +++const char *numeric = NULL, *account = NULL; +++static char *ac_type_C = "C"; +++static char *ac_type_R = "R"; ++ ++-theClient->setAccount(Param[2]); +++if (Param.size() < 4) { +++ numeric = Param[1]; +++ account = Param[2]; +++} else if (Param[2][0] == 'R') { +++ numeric = Param[1]; +++ account = Param[3]; +++} else if (Param[2][0] == 'C') { +++ const char *param_list[4]; +++ param_list[0] = Param[0]; +++ param_list[1] = Param[3]; +++ param_list[2] = Param[4]; +++ param_list[3] = Param[5]; +++ PostEvent(EVT_ACCOUNT, static_cast (ac_type_C), static_cast (param_list)); +++ return 0; +++} +++ +++if (!numeric || !account) +++ return 0; +++ +++iClient *theClient = Network->findClient(numeric); +++if (!theClient) +++ return 0; +++ +++theClient->setAccount(account); +++PostEvent(EVT_ACCOUNT, static_cast (ac_type_R), static_cast (theClient)) ; ++ ++-PostEvent( EVT_ACCOUNT, static_cast< void* >( theClient ) ) ; ++ return 0; +++ ++ } ++ ++ } // namespace gnuworld