diff --git a/irc/client_lookup_set.go b/irc/client_lookup_set.go index 048b0d3b..6d9834f9 100644 --- a/irc/client_lookup_set.go +++ b/irc/client_lookup_set.go @@ -205,9 +205,18 @@ func (clients *ClientManager) SetNick(client *Client, session *Session, newNick // the client may just be changing case if currentClient != nil && currentClient != client && session != nil { // these conditions forbid reattaching to an existing session: - if registered || !bouncerAllowed || account == "" || account != currentClient.Account() || client.HasMode(modes.TLS) != currentClient.HasMode(modes.TLS) { + if registered || !bouncerAllowed || account == "" || account != currentClient.Account() { return "", errNicknameInUse } + // check TLS modes + if client.HasMode(modes.TLS) != currentClient.HasMode(modes.TLS) { + if useAccountName { + // #955: this is fatal because they can't fix it by trying a different nick + return "", errInsecureReattach + } else { + return "", errNicknameInUse + } + } reattachSuccessful, numSessions, lastSeen := currentClient.AddSession(session) if !reattachSuccessful { return "", errNicknameInUse diff --git a/irc/errors.go b/irc/errors.go index d860e9e2..fc11e320 100644 --- a/irc/errors.go +++ b/irc/errors.go @@ -42,6 +42,7 @@ var ( errNickMissing = errors.New("nick missing") errNicknameInvalid = errors.New("invalid nickname") errNicknameInUse = errors.New("nickname in use") + errInsecureReattach = errors.New("insecure reattach") errNicknameReserved = errors.New("nickname is reserved") errNickAccountMismatch = errors.New(`Your nickname must match your account name; try logging out and logging back in with SASL`) errNoExistingBan = errors.New("Ban does not exist") diff --git a/irc/nickname.go b/irc/nickname.go index a49a2137..59d7beb2 100644 --- a/irc/nickname.go +++ b/irc/nickname.go @@ -25,12 +25,11 @@ var ( restrictedSkeletons = make(map[string]bool) ) -// returns whether the change succeeded or failed -func performNickChange(server *Server, client *Client, target *Client, session *Session, nickname string, rb *ResponseBuffer) bool { +func performNickChange(server *Server, client *Client, target *Client, session *Session, nickname string, rb *ResponseBuffer) error { currentNick := client.Nick() details := target.Details() if details.nick == nickname { - return true + return nil } hadNick := details.nick != "*" origNickMask := details.nickMask @@ -52,7 +51,7 @@ func performNickChange(server *Server, client *Client, target *Client, session * rb.Add(nil, server.name, ERR_UNKNOWNERROR, currentNick, "NICK", fmt.Sprintf(client.t("Could not set or change nickname: %s"), err.Error())) } if err != nil { - return false + return err } message := utils.MakeMessage("") @@ -88,7 +87,7 @@ func performNickChange(server *Server, client *Client, target *Client, session * client.server.monitorManager.AlertAbout(target, true) target.nickTimer.Touch(rb) } // else: these will be deferred to the end of registration (see #572) - return true + return nil } func (server *Server) RandomlyRename(client *Client) { @@ -124,7 +123,7 @@ func fixupNickEqualsAccount(client *Client, rb *ResponseBuffer, config *Config) if !client.registered { return true } - if !performNickChange(client.server, client, client, rb.session, client.AccountName(), rb) { + if performNickChange(client.server, client, client, rb.session, client.AccountName(), rb) != nil { client.server.accounts.Logout(client) nsNotice(rb, client.t("A client is already using that account; try logging out and logging back in with SASL")) return false diff --git a/irc/server.go b/irc/server.go index 63a1d4d8..cc43d0ea 100644 --- a/irc/server.go +++ b/irc/server.go @@ -343,11 +343,14 @@ func (server *Server) tryRegister(c *Client, session *Session) (exiting bool) { } rb := NewResponseBuffer(session) - nickAssigned := performNickChange(server, c, c, session, c.preregNick, rb) + nickError := performNickChange(server, c, c, session, c.preregNick, rb) rb.Send(true) - if !nickAssigned { + if nickError == errInsecureReattach { + c.Quit(c.t("You can't mix secure and insecure connections to this account"), nil) + return true + } else if nickError != nil { c.preregNick = "" - return + return false } if session.client != c { @@ -355,7 +358,7 @@ func (server *Server) tryRegister(c *Client, session *Session) (exiting bool) { // we'll play the reg burst later, on the new goroutine associated with // (thisSession, otherClient). This is to avoid having to transfer state // like nickname, hostname, etc. to show the correct values in the reg burst. - return + return false } // check KLINEs