From 1401ce0339d0906c9a7abbd65cba98c730b48698 Mon Sep 17 00:00:00 2001 From: Egor Date: Thu, 25 Jan 2024 05:50:16 +0200 Subject: [PATCH] run all username updates through chghost --- src/irc.c | 151 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 89 insertions(+), 62 deletions(-) diff --git a/src/irc.c b/src/irc.c index ffb611e..acf46a2 100644 --- a/src/irc.c +++ b/src/irc.c @@ -373,14 +373,8 @@ int processPacket(struct client_data *client, char *source, char *command, int a #endif } if (res != -1) { - client->umode |= UMODE_REGISTERED; - free(client->username); - client->username = mystrdup(username); - if (!client->username) - abort(); copy_strf(&databuf, ":%s 903 * :SASL authentication successful\r\n", hostname), sendbuf(client); - copy_strf(&databuf, ":%s 900 * *!%s@%s %s :You are now logged in as %s\r\n", - hostname, client->username, client->hostname, client->username, client->username), sendbuf(client); + client_chghost(client, username, 0); } else { saslerr: copy_strf(&databuf, ":%s 904 * :SASL authentication failed\r\n", hostname), sendbuf(client); @@ -413,14 +407,8 @@ saslcleanup: return err_alreadyregistered(client), sendbuf(client), 0; // set username, but only if we didn't auth yet if (!client->username || client->username[0] == '~') { - free(client->username); - size_t ulen = strlen(args[0]); - client->username = malloc(ulen+2); - if (!client->username) - abort(); - client->umode &= ~UMODE_REGISTERED; - client->username[0] = '~'; - memcpy(client->username + 1, args[0], ulen+1); + args[0][-1] = '~'; // ugly hack + client_chghost(client, args[0]-1, 0); } // set realname free(client->realname); @@ -1182,6 +1170,7 @@ saslcleanup: if (cl->cctx && tls_peer_cert_provided(cl->cctx)) rpl_whoiscertfp(client, cl, tls_peer_cert_hash(cl->cctx)), sendbuf(client); #endif + // TODO: this needs to do a nicks.txt lookup if (cl->umode & UMODE_REGISTERED && !strcmp(cl->key, cl->username)) rpl_whoisregnick(client, cl), sendbuf(client); rpl_whoisuser(client, cl), sendbuf(client); @@ -1346,8 +1335,7 @@ void newUser(struct client_data *client) { if (!(client->umode & UMODE_SECURE) || res == -1) { return err_passwdmismatch(client), sendbuf(client); } else { - client->umode |= UMODE_REGISTERED; - memmove(client->username, client->username+1, strlen(client->username)); + client_chghost(client, client->username+1, 0); } } setNick(client, client->nick_reg); @@ -1499,64 +1487,103 @@ void setNick(struct client_data *client, char* nickname) { rpl_mononline(0, client), sendbuf_monitor(client->key, 0, 0, 0); return; } +/* changes username, hostname or both + * NULL means no change. additionally username can be client->username+1 + * this has to work during registration, so there are no assumptions about nick/username already existing + */ void client_chghost(struct client_data *client, const char *newusername, const char *newhostname) { - if (!strcmp(client->username, newusername) && !strcmp(client->hostname, newhostname)) + if (client->username && newusername && !strcmp(client->username, newusername)) + newusername = 0; + if (newhostname && !strcmp(client->hostname, newhostname)) + newhostname = 0; + if (!newusername && !newhostname) return; - msg_quit(client, "Changing hostname", ""); - sendbuf_visible_caps(client, 0, CAP_CHGHOST); - msg_chghost(client, newusername, newhostname); - int cookie = sendbuf_visible_caps(client, CAP_CHGHOST, 0); - sendbuf_monitor(client->key, cookie, CAP_CHGHOST|CAP_EXTENDEDMONITOR, 0); - if (client->cookie != cookie) - sendbuf(client); - rpl_visiblehost(client), sendbuf(client); - int changedacc = client->username[0] != '~' || newusername[0] != '~'; - int loggedout = client->username[0] != '~' && newusername[0] == '~'; + int wasloggedin = client->username && client->username[0] != '~'; + int willbeloggedin = newusername ? newusername[0] != '~' : wasloggedin; + int changedacc = newusername && (wasloggedin || willbeloggedin); - free(client->username); - client->username = mystrdup(newusername); - free(client->hostname); - client->hostname = mystrdup(newhostname); - free(client->nuh); - client->nuh = malloc(strlen(client->nick) + strlen(client->username) + strlen(client->hostname) + 3); - if (!client->nuh) - abort(); - sprintf(client->nuh, "%s!%s@%s", client->nick, client->username, client->hostname); - stringlower(client->nuh); + // notify clients that the user is changing their hostname + if (is_registered(client)) { + msg_quit(client, "Changing hostname", ""); + sendbuf_visible_caps(client, 0, CAP_CHGHOST); + msg_chghost(client, newusername ? newusername : client->username, newhostname ? newhostname : client->hostname); + int cookie = sendbuf_visible_caps(client, CAP_CHGHOST, 0); + sendbuf_monitor(client->key, cookie, CAP_CHGHOST|CAP_EXTENDEDMONITOR, 0); + if (client->cookie != cookie) + sendbuf(client); + rpl_visiblehost(client), sendbuf(client); + } - struct channel *chan; - map_foreach(&client->channels, 0, &chan) { - msg_join(client, chan); - sendbuf_list_sans_self_caps(client, &chan->members, 0, 0, CAP_EXTENDEDJOIN|CAP_CHGHOST); - msg_join_extended(client, chan); - sendbuf_list_sans_self_caps(client, &chan->members, 0, CAP_EXTENDEDJOIN, CAP_CHGHOST); - if (map_get(&chan->v, client->key)) { - copy_strf(&databuf, ":cia!cia@cia.gov MODE %s +v %s\r\n", chan->name, client->nick); - sendbuf_list_sans_self_caps(client, &chan->members, 0, 0, CAP_CHGHOST); + // update username + if (newusername == client->username+1) { + memmove(client->username, client->username+1, strlen(client->username)); + } else if (newusername) { + free(client->username); + client->username = mystrdup(newusername); + if (!client->username) + abort(); + } + // update hostname + if (newhostname) { + free(client->hostname); + client->hostname = mystrdup(newhostname); + if (!client->hostname) + abort(); + } + // update nuh + { + char *n = client->nick ? client->nick : "*"; + char *u = client->username ? client->username : "*"; + char *h = client->hostname; + free(client->nuh); + client->nuh = malloc(strlen(n) + strlen(u) + strlen(h) + 3); + if (!client->nuh) + abort(); + sprintf(client->nuh, "%s!%s@%s", n, u, h); + stringlower(client->nuh); + } + + // now we have to simulate rejoins for clients without chghost support + if (is_registered(client)) { + struct channel *chan; + map_foreach(&client->channels, 0, &chan) { + msg_join(client, chan); + sendbuf_list_sans_self_caps(client, &chan->members, 0, 0, CAP_EXTENDEDJOIN|CAP_CHGHOST); + msg_join_extended(client, chan); + sendbuf_list_sans_self_caps(client, &chan->members, 0, CAP_EXTENDEDJOIN, CAP_CHGHOST); + if (map_get(&chan->v, client->key)) { + copy_strf(&databuf, ":cia!cia@cia.gov MODE %s +v %s\r\n", chan->name, client->nick); + sendbuf_list_sans_self_caps(client, &chan->members, 0, 0, CAP_CHGHOST); + } + if (map_get(&chan->o, client->key)) { + copy_strf(&databuf, ":cia!cia@cia.gov MODE %s +o %s\r\n", chan->name, client->nick); + sendbuf_list_sans_self_caps(client, &chan->members, 0, 0, CAP_CHGHOST); + } } - if (map_get(&chan->o, client->key)) { - copy_strf(&databuf, ":cia!cia@cia.gov MODE %s +o %s\r\n", chan->name, client->nick); - sendbuf_list_sans_self_caps(client, &chan->members, 0, 0, CAP_CHGHOST); + if (changedacc) { + msg_account(client); + int cookie = sendbuf_visible_caps(client, CAP_ACCOUNTNOTIFY, 0); + sendbuf_monitor(client->key, cookie, CAP_ACCOUNTNOTIFY|CAP_EXTENDEDMONITOR, 0); + if (client->cookie != cookie) + sendbuf(client); } } - if (changedacc) { - msg_account(client); - int cookie = sendbuf_visible_caps(client, CAP_ACCOUNTNOTIFY, 0); - sendbuf_monitor(client->key, cookie, CAP_ACCOUNTNOTIFY|CAP_EXTENDEDMONITOR, 0); - if (client->cookie != cookie) - sendbuf(client); - } - if (newusername[0] != '~') { - copy_strf(&databuf, ":%s 900 %s %s %s :You are now logged in as %s\r\n", - hostname, client->nick, client->nuh, client->username, client->username), sendbuf(client); + + // notify the user of their new account name, and update the +r mode + if (willbeloggedin) { + if (newusername) + copy_strf(&databuf, ":%s 900 %s %s %s :You are now logged in as %s\r\n", + hostname, client->nick ? client->nick : "*", client->nuh, client->username, client->username), sendbuf(client); client->umode |= UMODE_REGISTERED; } else { - if (loggedout) + if (wasloggedin) copy_strf(&databuf, ":%s 901 %s %s :You are now logged out\r\n", - hostname, client->nick, client->nuh), sendbuf(client); + hostname, client->nick ? client->nick : "*", client->nuh), sendbuf(client); client->umode &= ~UMODE_REGISTERED; } + if (is_registered(client) && wasloggedin != willbeloggedin) + copy_strf(&databuf, ":cia!cia@cia.gov MODE %s %cr\r\n", client->nick, willbeloggedin ? '+' : '-'), sendbuf(client); } void channel_sendtopic(struct client_data *client, struct channel *chan, int joining) { -- 2.56.0