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,6 +65,7 @@ type Client struct {
65 65
 	nickMaskString     string // cache for nickmask string since it's used with lots of replies
66 66
 	nickTimer          *NickTimer
67 67
 	operName           string
68
+	preregNick         string
68 69
 	proxiedIP          net.IP // actual remote IP if using the PROXY protocol
69 70
 	quitMessage        string
70 71
 	rawHostname        string

+ 1
- 0
irc/config.go View File

@@ -61,6 +61,7 @@ func (conf *PassConfig) PasswordBytes() []byte {
61 61
 type AccountConfig struct {
62 62
 	Registration          AccountRegistrationConfig
63 63
 	AuthenticationEnabled bool                  `yaml:"authentication-enabled"`
64
+	SkipServerPassword    bool                  `yaml:"skip-server-password"`
64 65
 	NickReservation       NickReservationConfig `yaml:"nick-reservation"`
65 66
 }
66 67
 

+ 24
- 0
irc/getters.go View File

@@ -142,6 +142,30 @@ func (client *Client) SetAccountName(account string) (changed bool) {
142 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 169
 func (client *Client) HasMode(mode modes.Mode) bool {
146 170
 	client.stateMutex.RLock()
147 171
 	defer client.stateMutex.RUnlock()

+ 18
- 21
irc/handlers.go View File

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

+ 6
- 6
irc/nickname.go View File

@@ -23,6 +23,7 @@ var (
23 23
 	}
24 24
 )
25 25
 
26
+// returns whether the change succeeded or failed
26 27
 func performNickChange(server *Server, client *Client, target *Client, newnick string, rb *ResponseBuffer) bool {
27 28
 	nickname := strings.TrimSpace(newnick)
28 29
 	cfnick, err := CasefoldName(nickname)
@@ -38,7 +39,7 @@ func performNickChange(server *Server, client *Client, target *Client, newnick s
38 39
 	}
39 40
 
40 41
 	if target.Nick() == nickname {
41
-		return false
42
+		return true
42 43
 	}
43 44
 
44 45
 	hadNick := target.HasNick()
@@ -49,7 +50,7 @@ func performNickChange(server *Server, client *Client, target *Client, newnick s
49 50
 		rb.Add(nil, server.name, ERR_NICKNAMEINUSE, client.nick, nickname, client.t("Nickname is already in use"))
50 51
 		return false
51 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 54
 		return false
54 55
 	} else if err != nil {
55 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,12 +68,11 @@ func performNickChange(server *Server, client *Client, target *Client, newnick s
67 68
 		}
68 69
 	}
69 70
 
70
-	if target.registered {
71
+	if target.Registered() {
71 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 78
 func (server *Server) RandomlyRename(client *Client) {

+ 22
- 3
irc/server.go View File

@@ -416,8 +416,27 @@ func (server *Server) generateMessageID() string {
416 416
 //
417 417
 
418 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 440
 		return
422 441
 	}
423 442
 
@@ -447,7 +466,7 @@ func (server *Server) tryRegister(c *Client) {
447 466
 	//TODO(dan): Look at adding last optional [<channel modes with a parameter>] parameter
448 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 470
 	c.RplISupport(rb)
452 471
 	server.MOTD(c, rb)
453 472
 	rb.Send()

+ 7
- 0
oragono.yaml View File

@@ -170,6 +170,13 @@ accounts:
170 170
     # is account authentication enabled?
171 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 180
     # nick-reservation controls how, and whether, nicknames are linked to accounts
174 181
     nick-reservation:
175 182
         # is there any enforcement of reserved nicknames?

Loading…
Cancel
Save