Browse Source

implement #199

tags/v0.11.0-beta
Shivaram Lingamneni 6 years ago
parent
commit
be86684e96
7 changed files with 79 additions and 30 deletions
  1. 1
    0
      irc/client.go
  2. 1
    0
      irc/config.go
  3. 24
    0
      irc/getters.go
  4. 18
    21
      irc/handlers.go
  5. 6
    6
      irc/nickname.go
  6. 22
    3
      irc/server.go
  7. 7
    0
      oragono.yaml

+ 1
- 0
irc/client.go View File

65
 	nickMaskString     string // cache for nickmask string since it's used with lots of replies
65
 	nickMaskString     string // cache for nickmask string since it's used with lots of replies
66
 	nickTimer          *NickTimer
66
 	nickTimer          *NickTimer
67
 	operName           string
67
 	operName           string
68
+	preregNick         string
68
 	proxiedIP          net.IP // actual remote IP if using the PROXY protocol
69
 	proxiedIP          net.IP // actual remote IP if using the PROXY protocol
69
 	quitMessage        string
70
 	quitMessage        string
70
 	rawHostname        string
71
 	rawHostname        string

+ 1
- 0
irc/config.go View File

61
 type AccountConfig struct {
61
 type AccountConfig struct {
62
 	Registration          AccountRegistrationConfig
62
 	Registration          AccountRegistrationConfig
63
 	AuthenticationEnabled bool                  `yaml:"authentication-enabled"`
63
 	AuthenticationEnabled bool                  `yaml:"authentication-enabled"`
64
+	SkipServerPassword    bool                  `yaml:"skip-server-password"`
64
 	NickReservation       NickReservationConfig `yaml:"nick-reservation"`
65
 	NickReservation       NickReservationConfig `yaml:"nick-reservation"`
65
 }
66
 }
66
 
67
 

+ 24
- 0
irc/getters.go View File

142
 	return
142
 	return
143
 }
143
 }
144
 
144
 
145
+func (client *Client) Authorized() bool {
146
+	client.stateMutex.RLock()
147
+	defer client.stateMutex.RUnlock()
148
+	return client.authorized
149
+}
150
+
151
+func (client *Client) SetAuthorized(authorized bool) {
152
+	client.stateMutex.Lock()
153
+	defer client.stateMutex.Unlock()
154
+	client.authorized = authorized
155
+}
156
+
157
+func (client *Client) PreregNick() string {
158
+	client.stateMutex.RLock()
159
+	defer client.stateMutex.RUnlock()
160
+	return client.preregNick
161
+}
162
+
163
+func (client *Client) SetPreregNick(preregNick string) {
164
+	client.stateMutex.Lock()
165
+	defer client.stateMutex.Unlock()
166
+	client.preregNick = preregNick
167
+}
168
+
145
 func (client *Client) HasMode(mode modes.Mode) bool {
169
 func (client *Client) HasMode(mode modes.Mode) bool {
146
 	client.stateMutex.RLock()
170
 	client.stateMutex.RLock()
147
 	defer client.stateMutex.RUnlock()
171
 	defer client.stateMutex.RUnlock()

+ 18
- 21
irc/handlers.go View File

319
 	// let the SASL handler do its thing
319
 	// let the SASL handler do its thing
320
 	exiting := handler(server, client, client.saslMechanism, data, rb)
320
 	exiting := handler(server, client, client.saslMechanism, data, rb)
321
 
321
 
322
+	if client.LoggedIntoAccount() && server.AccountConfig().SkipServerPassword {
323
+		client.SetAuthorized(true)
324
+	}
325
+
322
 	// wait 'til SASL is done before emptying the sasl vars
326
 	// wait 'til SASL is done before emptying the sasl vars
323
 	client.saslInProgress = false
327
 	client.saslInProgress = false
324
 	client.saslMechanism = ""
328
 	client.saslMechanism = ""
491
 		rb.Add(nil, server.name, "CAP", client.nick, "ACK", capString)
495
 		rb.Add(nil, server.name, "CAP", client.nick, "ACK", capString)
492
 
496
 
493
 	case "END":
497
 	case "END":
494
-		if !client.registered {
498
+		if !client.Registered() {
495
 			client.capState = caps.NegotiatedState
499
 			client.capState = caps.NegotiatedState
496
-			server.tryRegister(client)
497
 		}
500
 		}
498
 
501
 
499
 	default:
502
 	default:
1633
 
1636
 
1634
 // NICK <nickname>
1637
 // NICK <nickname>
1635
 func nickHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
1638
 func nickHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
1636
-	if !client.authorized {
1637
-		client.Quit("Bad password")
1638
-		return true
1639
+	if client.Registered() {
1640
+		performNickChange(server, client, client, msg.Params[0], rb)
1641
+	} else {
1642
+		client.SetPreregNick(msg.Params[0])
1639
 	}
1643
 	}
1640
-
1641
-	return performNickChange(server, client, client, msg.Params[0], rb)
1644
+	return false
1642
 }
1645
 }
1643
 
1646
 
1644
 // NOTICE <target>{,<target>} <message>
1647
 // NOTICE <target>{,<target>} <message>
1831
 
1834
 
1832
 // PASS <password>
1835
 // PASS <password>
1833
 func passHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
1836
 func passHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
1834
-	if client.registered {
1837
+	if client.Registered() {
1835
 		rb.Add(nil, server.name, ERR_ALREADYREGISTRED, client.nick, client.t("You may not reregister"))
1838
 		rb.Add(nil, server.name, ERR_ALREADYREGISTRED, client.nick, client.t("You may not reregister"))
1836
 		return false
1839
 		return false
1837
 	}
1840
 	}
1838
 
1841
 
1839
 	// if no password exists, skip checking
1842
 	// if no password exists, skip checking
1840
 	if len(server.password) == 0 {
1843
 	if len(server.password) == 0 {
1841
-		client.authorized = true
1844
+		client.SetAuthorized(true)
1842
 		return false
1845
 		return false
1843
 	}
1846
 	}
1844
 
1847
 
1850
 		return true
1853
 		return true
1851
 	}
1854
 	}
1852
 
1855
 
1853
-	client.authorized = true
1856
+	client.SetAuthorized(true)
1854
 	return false
1857
 	return false
1855
 }
1858
 }
1856
 
1859
 
1942
 // http://www.haproxy.org/download/1.8/doc/proxy-protocol.txt
1945
 // http://www.haproxy.org/download/1.8/doc/proxy-protocol.txt
1943
 func proxyHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
1946
 func proxyHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
1944
 	// only allow unregistered clients to use this command
1947
 	// only allow unregistered clients to use this command
1945
-	if client.registered || client.proxiedIP != nil {
1948
+	if client.Registered() || client.proxiedIP != nil {
1946
 		return false
1949
 		return false
1947
 	}
1950
 	}
1948
 
1951
 
2106
 		rb.Add(nil, server.name, ERR_NOSUCHNICK, client.nick, msg.Params[0], client.t("No such nick"))
2109
 		rb.Add(nil, server.name, ERR_NOSUCHNICK, client.nick, msg.Params[0], client.t("No such nick"))
2107
 		return false
2110
 		return false
2108
 	}
2111
 	}
2109
-	return performNickChange(server, client, target, msg.Params[1], rb)
2112
+	performNickChange(server, client, target, msg.Params[1], rb)
2113
+	return false
2110
 }
2114
 }
2111
 
2115
 
2112
 // SCENE <target> <message>
2116
 // SCENE <target> <message>
2320
 
2324
 
2321
 // USER <username> * 0 <realname>
2325
 // USER <username> * 0 <realname>
2322
 func userHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
2326
 func userHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
2323
-	if client.registered {
2327
+	if client.Registered() {
2324
 		rb.Add(nil, server.name, ERR_ALREADYREGISTRED, client.nick, client.t("You may not reregister"))
2328
 		rb.Add(nil, server.name, ERR_ALREADYREGISTRED, client.nick, client.t("You may not reregister"))
2325
 		return false
2329
 		return false
2326
 	}
2330
 	}
2327
 
2331
 
2328
-	if !client.authorized {
2329
-		client.Quit("Bad password")
2330
-		return true
2331
-	}
2332
-
2333
 	if client.username != "" && client.realname != "" {
2332
 	if client.username != "" && client.realname != "" {
2334
 		return false
2333
 		return false
2335
 	}
2334
 	}
2350
 		client.realname = msg.Params[3]
2349
 		client.realname = msg.Params[3]
2351
 	}
2350
 	}
2352
 
2351
 
2353
-	server.tryRegister(client)
2354
-
2355
 	return false
2352
 	return false
2356
 }
2353
 }
2357
 
2354
 
2403
 // WEBIRC <password> <gateway> <hostname> <ip> [:flag1 flag2=x flag3]
2400
 // WEBIRC <password> <gateway> <hostname> <ip> [:flag1 flag2=x flag3]
2404
 func webircHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
2401
 func webircHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
2405
 	// only allow unregistered clients to use this command
2402
 	// only allow unregistered clients to use this command
2406
-	if client.registered || client.proxiedIP != nil {
2403
+	if client.Registered() || client.proxiedIP != nil {
2407
 		return false
2404
 		return false
2408
 	}
2405
 	}
2409
 
2406
 

+ 6
- 6
irc/nickname.go View File

23
 	}
23
 	}
24
 )
24
 )
25
 
25
 
26
+// returns whether the change succeeded or failed
26
 func performNickChange(server *Server, client *Client, target *Client, newnick string, rb *ResponseBuffer) bool {
27
 func performNickChange(server *Server, client *Client, target *Client, newnick string, rb *ResponseBuffer) bool {
27
 	nickname := strings.TrimSpace(newnick)
28
 	nickname := strings.TrimSpace(newnick)
28
 	cfnick, err := CasefoldName(nickname)
29
 	cfnick, err := CasefoldName(nickname)
38
 	}
39
 	}
39
 
40
 
40
 	if target.Nick() == nickname {
41
 	if target.Nick() == nickname {
41
-		return false
42
+		return true
42
 	}
43
 	}
43
 
44
 
44
 	hadNick := target.HasNick()
45
 	hadNick := target.HasNick()
49
 		rb.Add(nil, server.name, ERR_NICKNAMEINUSE, client.nick, nickname, client.t("Nickname is already in use"))
50
 		rb.Add(nil, server.name, ERR_NICKNAMEINUSE, client.nick, nickname, client.t("Nickname is already in use"))
50
 		return false
51
 		return false
51
 	} else if err == errNicknameReserved {
52
 	} else if err == errNicknameReserved {
52
-		client.Send(nil, server.name, ERR_NICKNAMEINUSE, client.nick, nickname, client.t("Nickname is reserved by a different account"))
53
+		rb.Add(nil, server.name, ERR_NICKNAMEINUSE, client.nick, nickname, client.t("Nickname is reserved by a different account"))
53
 		return false
54
 		return false
54
 	} else if err != nil {
55
 	} else if err != nil {
55
 		rb.Add(nil, server.name, ERR_UNKNOWNERROR, client.nick, "NICK", fmt.Sprintf(client.t("Could not set or change nickname: %s"), err.Error()))
56
 		rb.Add(nil, server.name, ERR_UNKNOWNERROR, client.nick, "NICK", fmt.Sprintf(client.t("Could not set or change nickname: %s"), err.Error()))
67
 		}
68
 		}
68
 	}
69
 	}
69
 
70
 
70
-	if target.registered {
71
+	if target.Registered() {
71
 		client.server.monitorManager.AlertAbout(target, true)
72
 		client.server.monitorManager.AlertAbout(target, true)
72
-	} else {
73
-		server.tryRegister(target)
74
 	}
73
 	}
75
-	return false
74
+	// else: Run() will attempt registration immediately after this
75
+	return true
76
 }
76
 }
77
 
77
 
78
 func (server *Server) RandomlyRename(client *Client) {
78
 func (server *Server) RandomlyRename(client *Client) {

+ 22
- 3
irc/server.go View File

416
 //
416
 //
417
 
417
 
418
 func (server *Server) tryRegister(c *Client) {
418
 func (server *Server) tryRegister(c *Client) {
419
-	if c.registered || !c.HasNick() || !c.HasUsername() ||
420
-		(c.capState == caps.NegotiatingState) {
419
+	if c.Registered() {
420
+		return
421
+	}
422
+
423
+	preregNick := c.PreregNick()
424
+	if preregNick == "" || !c.HasUsername() || c.capState == caps.NegotiatingState {
425
+		return
426
+	}
427
+
428
+	// client MUST send PASS (or AUTHENTICATE, if skip-server-password is set)
429
+	// before completing the other registration commands
430
+	if !c.Authorized() {
431
+		c.Quit(c.t("Bad password"))
432
+		c.destroy(false)
433
+		return
434
+	}
435
+
436
+	rb := NewResponseBuffer(c)
437
+	nickAssigned := performNickChange(server, c, c, preregNick, rb)
438
+	rb.Send()
439
+	if !nickAssigned {
421
 		return
440
 		return
422
 	}
441
 	}
423
 
442
 
447
 	//TODO(dan): Look at adding last optional [<channel modes with a parameter>] parameter
466
 	//TODO(dan): Look at adding last optional [<channel modes with a parameter>] parameter
448
 	c.Send(nil, server.name, RPL_MYINFO, c.nick, server.name, Ver, supportedUserModesString, supportedChannelModesString)
467
 	c.Send(nil, server.name, RPL_MYINFO, c.nick, server.name, Ver, supportedUserModesString, supportedChannelModesString)
449
 
468
 
450
-	rb := NewResponseBuffer(c)
469
+	rb = NewResponseBuffer(c)
451
 	c.RplISupport(rb)
470
 	c.RplISupport(rb)
452
 	server.MOTD(c, rb)
471
 	server.MOTD(c, rb)
453
 	rb.Send()
472
 	rb.Send()

+ 7
- 0
oragono.yaml View File

170
     # is account authentication enabled?
170
     # is account authentication enabled?
171
     authentication-enabled: true
171
     authentication-enabled: true
172
 
172
 
173
+    # some clients (notably Pidgin and Hexchat) offer only a single password field,
174
+    # which makes it impossible to specify a separate server password (for the PASS
175
+    # command) and SASL password. if this option is set to true, a client that
176
+    # successfully authenticates with SASL will not be required to send
177
+    # PASS as well, so it can be configured to authenticate with SASL only.
178
+    skip-server-password: false
179
+
173
     # nick-reservation controls how, and whether, nicknames are linked to accounts
180
     # nick-reservation controls how, and whether, nicknames are linked to accounts
174
     nick-reservation:
181
     nick-reservation:
175
         # is there any enforcement of reserved nicknames?
182
         # is there any enforcement of reserved nicknames?

Loading…
Cancel
Save