yakumo.izuru 065e07da4b Prefer immortal.run over runit and rc.d, use vendored modules
for convenience.

Signed-off-by: Izuru Yakumo <yakumo.izuru@chaotic.ninja>

git-svn-id: file:///srv/svn/repo/suika/trunk@822 f0ae65fe-ee39-954e-97ec-027ff2717ef4
2023-08-20 14:36:11 +00:00

90 lines
2.2 KiB
Go

package sasl
import (
"bytes"
)
// The LOGIN mechanism name.
const Login = "LOGIN"
var expectedChallenge = []byte("Password:")
type loginClient struct {
Username string
Password string
}
func (a *loginClient) Start() (mech string, ir []byte, err error) {
mech = "LOGIN"
ir = []byte(a.Username)
return
}
func (a *loginClient) Next(challenge []byte) (response []byte, err error) {
if bytes.Compare(challenge, expectedChallenge) != 0 {
return nil, ErrUnexpectedServerChallenge
} else {
return []byte(a.Password), nil
}
}
// A client implementation of the LOGIN authentication mechanism for SMTP,
// as described in http://www.iana.org/go/draft-murchison-sasl-login
//
// It is considered obsolete, and should not be used when other mechanisms are
// available. For plaintext password authentication use PLAIN mechanism.
func NewLoginClient(username, password string) Client {
return &loginClient{username, password}
}
// Authenticates users with an username and a password.
type LoginAuthenticator func(username, password string) error
type loginState int
const (
loginNotStarted loginState = iota
loginWaitingUsername
loginWaitingPassword
)
type loginServer struct {
state loginState
username, password string
authenticate LoginAuthenticator
}
// A server implementation of the LOGIN authentication mechanism, as described
// in https://tools.ietf.org/html/draft-murchison-sasl-login-00.
//
// LOGIN is obsolete and should only be enabled for legacy clients that cannot
// be updated to use PLAIN.
func NewLoginServer(authenticator LoginAuthenticator) Server {
return &loginServer{authenticate: authenticator}
}
func (a *loginServer) Next(response []byte) (challenge []byte, done bool, err error) {
switch a.state {
case loginNotStarted:
// Check for initial response field, as per RFC4422 section 3
if response == nil {
challenge = []byte("Username:")
break
}
a.state++
fallthrough
case loginWaitingUsername:
a.username = string(response)
challenge = []byte("Password:")
case loginWaitingPassword:
a.password = string(response)
err = a.authenticate(a.username, a.password)
done = true
default:
err = ErrUnexpectedClientResponse
}
a.state++
return
}