mirror of
https://github.com/ergochat/ergo.git
synced 2025-11-13 20:47:24 +01:00
changes to OPER command
* Impose a throttle on OPER attempts regardless of whether they caused a password check. * Never disconnect the client on a failed attempt, even if there was a password check. * Change error numeric to ERR_NOOPERHOST * Explicit information about the failure in the server log (copying Insp) Fixes #2296.
This commit is contained in:
parent
efc1627d23
commit
6fdac13ad4
@ -358,6 +358,10 @@ server:
|
||||
secure-nets:
|
||||
# - "10.0.0.0/8"
|
||||
|
||||
# allow attempts to OPER with a password at most this often. default to
|
||||
# 10 seconds when unset.
|
||||
oper-throttle: 10s
|
||||
|
||||
# Ergo will write files to disk under certain circumstances, e.g.,
|
||||
# CPU profiling or data export. by default, these files will be written
|
||||
# to the working directory. set this to customize:
|
||||
|
||||
@ -527,7 +527,7 @@ If your client or bot is failing to connect to Ergo, here are some things to che
|
||||
|
||||
## Why can't I oper?
|
||||
|
||||
If you try to oper unsuccessfully, Ergo will disconnect you from the network. If you're unable to oper, here are some things to double-check:
|
||||
If your `OPER` command fails, check your server logs for more information. Here are some general issues to double-check:
|
||||
|
||||
1. Did you correctly generate the hashed password with `ergo genpasswd`?
|
||||
1. Did you add the password hash to the correct config file, then save the file?
|
||||
|
||||
@ -189,6 +189,8 @@ type Session struct {
|
||||
fakelag Fakelag
|
||||
deferredFakelagCount int
|
||||
|
||||
lastOperAttempt time.Time
|
||||
|
||||
certfp string
|
||||
peerCerts []*x509.Certificate
|
||||
sasl saslStatus
|
||||
|
||||
@ -599,6 +599,7 @@ type Config struct {
|
||||
Cloaks cloaks.CloakConfig `yaml:"ip-cloaking"`
|
||||
SecureNetDefs []string `yaml:"secure-nets"`
|
||||
secureNets []net.IPNet
|
||||
OperThrottle time.Duration `yaml:"oper-throttle"`
|
||||
supportedCaps *caps.Set
|
||||
supportedCapsWithoutSTS *caps.Set
|
||||
capValues caps.Values
|
||||
@ -1480,6 +1481,10 @@ func LoadConfig(filename string) (config *Config, err error) {
|
||||
config.Server.supportedCaps.Disable(caps.SASL)
|
||||
}
|
||||
|
||||
if config.Server.OperThrottle <= 0 {
|
||||
config.Server.OperThrottle = 10 * time.Second
|
||||
}
|
||||
|
||||
if err := config.Accounts.OAuth2.Postprocess(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -2545,8 +2545,19 @@ func operHandler(server *Server, client *Client, msg ircmsg.Message, rb *Respons
|
||||
return false
|
||||
}
|
||||
|
||||
config := server.Config()
|
||||
now := time.Now()
|
||||
nextAllowableAttempt := rb.session.lastOperAttempt.Add(config.Server.OperThrottle)
|
||||
if now.Before(nextAllowableAttempt) {
|
||||
timeLeft := nextAllowableAttempt.Sub(now).Round(time.Millisecond)
|
||||
rb.Add(nil, server.name, ERR_NOOPERHOST, client.Nick(), fmt.Sprintf(client.t("You must wait %v before issuing OPER again"), timeLeft))
|
||||
return false
|
||||
}
|
||||
|
||||
rb.session.lastOperAttempt = now
|
||||
|
||||
// must pass at least one check, and all enabled checks
|
||||
var checkPassed, checkFailed, passwordFailed bool
|
||||
var checkPassed, checkFailed, certFailed, passwordFailed bool
|
||||
oper := server.GetOperator(msg.Params[0])
|
||||
if oper != nil {
|
||||
if oper.Certfp != "" {
|
||||
@ -2554,11 +2565,13 @@ func operHandler(server *Server, client *Client, msg ircmsg.Message, rb *Respons
|
||||
checkPassed = true
|
||||
} else {
|
||||
checkFailed = true
|
||||
certFailed = true
|
||||
}
|
||||
}
|
||||
if !checkFailed && oper.Pass != nil {
|
||||
if len(msg.Params) == 1 {
|
||||
checkFailed = true
|
||||
passwordFailed = true
|
||||
} else if bcrypt.CompareHashAndPassword(oper.Pass, []byte(msg.Params[1])) != nil {
|
||||
checkFailed = true
|
||||
passwordFailed = true
|
||||
@ -2569,14 +2582,21 @@ func operHandler(server *Server, client *Client, msg ircmsg.Message, rb *Respons
|
||||
}
|
||||
|
||||
if !checkPassed || checkFailed {
|
||||
rb.Add(nil, server.name, ERR_PASSWDMISMATCH, client.Nick(), client.t("Password incorrect"))
|
||||
// #951: only disconnect them if we actually tried to check a password for them
|
||||
if passwordFailed {
|
||||
client.Quit(client.t("Password incorrect"), rb.session)
|
||||
return true
|
||||
rb.Add(nil, server.name, ERR_NOOPERHOST, client.Nick(), client.t("OPER failed; check the server logs for details."))
|
||||
|
||||
// hopefully not too spammy given the throttling:
|
||||
if oper == nil {
|
||||
server.logger.Info("opers", "OPER failed with invalid oper name", msg.Params[0])
|
||||
} else if certFailed {
|
||||
server.logger.Info("opers", "OPER attempt for", msg.Params[0], "failed with invalid certfp")
|
||||
} else if passwordFailed {
|
||||
server.logger.Info("opers", "OPER attempt for", msg.Params[0], "failed with invalid password")
|
||||
} else {
|
||||
return false
|
||||
// should not be possible given config validation
|
||||
server.logger.Info("opers", "OPER attempt for", msg.Params[0], "failed with invalid config")
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
if oper != nil {
|
||||
|
||||
@ -330,6 +330,10 @@ server:
|
||||
secure-nets:
|
||||
# - "10.0.0.0/8"
|
||||
|
||||
# allow attempts to OPER with a password at most this often. default to
|
||||
# 10 seconds when unset.
|
||||
oper-throttle: 10s
|
||||
|
||||
# Ergo will write files to disk under certain circumstances, e.g.,
|
||||
# CPU profiling or data export. by default, these files will be written
|
||||
# to the working directory. set this to customize:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user