|
@@ -8,7 +8,6 @@ package irc
|
8
|
8
|
|
9
|
9
|
import (
|
10
|
10
|
"bytes"
|
11
|
|
- "encoding/base64"
|
12
|
11
|
"fmt"
|
13
|
12
|
"net"
|
14
|
13
|
"os"
|
|
@@ -180,7 +179,6 @@ func acceptHandler(server *Server, client *Client, msg ircmsg.Message, rb *Respo
|
180
|
179
|
}
|
181
|
180
|
|
182
|
181
|
const (
|
183
|
|
- saslMaxArgLength = 400 // required by SASL spec
|
184
|
182
|
saslMaxResponseLength = 8192 // implementation-defined sanity check, long enough for bearer tokens
|
185
|
183
|
)
|
186
|
184
|
|
|
@@ -207,7 +205,7 @@ func authenticateHandler(server *Server, client *Client, msg ircmsg.Message, rb
|
207
|
205
|
return false
|
208
|
206
|
}
|
209
|
207
|
|
210
|
|
- // start new sasl session
|
|
208
|
+ // start new sasl session: parameter is the authentication mechanism
|
211
|
209
|
if session.sasl.mechanism == "" {
|
212
|
210
|
throttled, remainingTime := client.loginThrottle.Touch()
|
213
|
211
|
if throttled {
|
|
@@ -246,44 +244,28 @@ func authenticateHandler(server *Server, client *Client, msg ircmsg.Message, rb
|
246
|
244
|
return false
|
247
|
245
|
}
|
248
|
246
|
|
249
|
|
- // continue existing sasl session
|
250
|
|
- rawData := msg.Params[0]
|
251
|
|
-
|
252
|
|
- // https://ircv3.net/specs/extensions/sasl-3.1:
|
253
|
|
- // "The response is encoded in Base64 (RFC 4648), then split to 400-byte chunks,
|
254
|
|
- // and each chunk is sent as a separate AUTHENTICATE command."
|
255
|
|
- if len(rawData) > saslMaxArgLength {
|
256
|
|
- rb.Add(nil, server.name, ERR_SASLTOOLONG, details.nick, client.t("SASL message too long"))
|
257
|
|
- session.sasl.Clear()
|
258
|
|
- return false
|
259
|
|
- } else if len(rawData) == saslMaxArgLength {
|
260
|
|
- if session.sasl.value.Len() >= saslMaxResponseLength {
|
261
|
|
- rb.Add(nil, server.name, ERR_SASLFAIL, details.nick, client.t("SASL authentication failed: Passphrase too long"))
|
262
|
|
- session.sasl.Clear()
|
263
|
|
- return false
|
|
247
|
+ // continue existing sasl session: parameter is a message chunk
|
|
248
|
+ done, value, err := session.sasl.value.Add(msg.Params[0])
|
|
249
|
+ if err == nil {
|
|
250
|
+ if done {
|
|
251
|
+ // call actual handler
|
|
252
|
+ handler := EnabledSaslMechanisms[session.sasl.mechanism]
|
|
253
|
+ return handler(server, client, session, value, rb)
|
|
254
|
+ } else {
|
|
255
|
+ return false // wait for continuation line
|
264
|
256
|
}
|
265
|
|
- session.sasl.value.WriteString(rawData)
|
266
|
|
- return false
|
267
|
257
|
}
|
268
|
|
- if rawData != "+" {
|
269
|
|
- session.sasl.value.WriteString(rawData)
|
270
|
|
- }
|
271
|
|
-
|
272
|
|
- var data []byte
|
273
|
|
- var err error
|
274
|
|
- if session.sasl.value.Len() > 0 {
|
275
|
|
- data, err = base64.StdEncoding.DecodeString(session.sasl.value.String())
|
276
|
|
- session.sasl.value.Reset()
|
277
|
|
- if err != nil {
|
278
|
|
- rb.Add(nil, server.name, ERR_SASLFAIL, details.nick, client.t("SASL authentication failed: Invalid b64 encoding"))
|
279
|
|
- session.sasl.Clear()
|
280
|
|
- return false
|
281
|
|
- }
|
|
258
|
+ // else: error handling
|
|
259
|
+ switch err {
|
|
260
|
+ case ircutils.ErrSASLTooLong:
|
|
261
|
+ rb.Add(nil, server.name, ERR_SASLTOOLONG, details.nick, client.t("SASL message too long"))
|
|
262
|
+ case ircutils.ErrSASLLimitExceeded:
|
|
263
|
+ rb.Add(nil, server.name, ERR_SASLFAIL, details.nick, client.t("SASL authentication failed: Passphrase too long"))
|
|
264
|
+ default:
|
|
265
|
+ rb.Add(nil, server.name, ERR_SASLFAIL, details.nick, client.t("SASL authentication failed: Invalid b64 encoding"))
|
282
|
266
|
}
|
283
|
|
-
|
284
|
|
- // call actual handler
|
285
|
|
- handler := EnabledSaslMechanisms[session.sasl.mechanism]
|
286
|
|
- return handler(server, client, session, data, rb)
|
|
267
|
+ session.sasl.Clear()
|
|
268
|
+ return false
|
287
|
269
|
}
|
288
|
270
|
|
289
|
271
|
// AUTHENTICATE PLAIN
|
|
@@ -495,21 +477,9 @@ func authOauthBearerHandler(server *Server, client *Client, session *Session, va
|
495
|
477
|
|
496
|
478
|
// helper to b64 a sasl response and chunk it into 400-byte lines
|
497
|
479
|
// as per https://ircv3.net/specs/extensions/sasl-3.1
|
498
|
|
-// TODO replace this with ircutils.EncodeSASLResponse
|
499
|
480
|
func sendSASLChallenge(server *Server, rb *ResponseBuffer, challenge []byte) {
|
500
|
|
- challengeStr := base64.StdEncoding.EncodeToString(challenge)
|
501
|
|
- lastLen := 0
|
502
|
|
- for len(challengeStr) > 0 {
|
503
|
|
- end := saslMaxArgLength
|
504
|
|
- if end > len(challengeStr) {
|
505
|
|
- end = len(challengeStr)
|
506
|
|
- }
|
507
|
|
- lastLen = end
|
508
|
|
- rb.Add(nil, server.name, "AUTHENTICATE", challengeStr[:end])
|
509
|
|
- challengeStr = challengeStr[end:]
|
510
|
|
- }
|
511
|
|
- if lastLen == saslMaxArgLength {
|
512
|
|
- rb.Add(nil, server.name, "AUTHENTICATE", "+")
|
|
481
|
+ for _, chunk := range ircutils.EncodeSASLResponse(challenge) {
|
|
482
|
+ rb.Add(nil, server.name, "AUTHENTICATE", chunk)
|
513
|
483
|
}
|
514
|
484
|
}
|
515
|
485
|
|