Parcourir la source

add sasl-only config option

tags/v1.0.0-rc1
Shivaram Lingamneni il y a 5 ans
Parent
révision
1c23af8767
14 fichiers modifiés avec 197 ajouts et 213 suppressions
  1. 4
    2
      irc/accounts.go
  2. 24
    13
      irc/client.go
  3. 3
    1
      irc/commands.go
  4. 20
    3
      irc/config.go
  5. 6
    24
      irc/connection_limits/limiter.go
  6. 6
    24
      irc/connection_limits/throttler.go
  7. 11
    38
      irc/gateways.go
  8. 0
    20
      irc/getters.go
  9. 23
    30
      irc/handlers.go
  10. 0
    5
      irc/idletimer.go
  11. 37
    16
      irc/nickserv.go
  12. 4
    3
      irc/server.go
  13. 41
    25
      irc/utils/net.go
  14. 18
    9
      oragono.yaml

+ 4
- 2
irc/accounts.go Voir le fichier

@@ -456,7 +456,7 @@ func (am *AccountManager) setPassword(account string, password string) (err erro
456 456
 }
457 457
 
458 458
 func (am *AccountManager) dispatchCallback(client *Client, casefoldedAccount string, callbackNamespace string, callbackValue string) (string, error) {
459
-	if callbackNamespace == "*" || callbackNamespace == "none" {
459
+	if callbackNamespace == "*" || callbackNamespace == "none" || callbackNamespace == "admin" {
460 460
 		return "", nil
461 461
 	} else if callbackNamespace == "mailto" {
462 462
 		return am.dispatchMailtoCallback(client, casefoldedAccount, callbackValue)
@@ -590,7 +590,9 @@ func (am *AccountManager) Verify(client *Client, account string, code string) er
590 590
 	if err != nil {
591 591
 		return err
592 592
 	}
593
-	am.Login(client, clientAccount)
593
+	if client != nil {
594
+		am.Login(client, clientAccount)
595
+	}
594 596
 	return nil
595 597
 }
596 598
 

+ 24
- 13
irc/client.go Voir le fichier

@@ -32,10 +32,6 @@ const (
32 32
 	IRCv3TimestampFormat = "2006-01-02T15:04:05.000Z"
33 33
 )
34 34
 
35
-var (
36
-	LoopbackIP = net.ParseIP("127.0.0.1")
37
-)
38
-
39 35
 // ResumeDetails is a place to stash data at various stages of
40 36
 // the resume process: when handling the RESUME command itself,
41 37
 // when completing the registration, and when rejoining channels.
@@ -55,7 +51,6 @@ type Client struct {
55 51
 	account            string
56 52
 	accountName        string // display name of the account: uncasefolded, '*' if not logged in
57 53
 	atime              time.Time
58
-	authorized         bool
59 54
 	awayMessage        string
60 55
 	capabilities       *caps.Set
61 56
 	capState           caps.State
@@ -88,12 +83,14 @@ type Client struct {
88 83
 	quitMessage        string
89 84
 	rawHostname        string
90 85
 	realname           string
86
+	realIP             net.IP
91 87
 	registered         bool
92 88
 	resumeDetails      *ResumeDetails
93 89
 	resumeToken        string
94 90
 	saslInProgress     bool
95 91
 	saslMechanism      string
96 92
 	saslValue          string
93
+	sentPassCommand    bool
97 94
 	server             *Server
98 95
 	skeleton           string
99 96
 	socket             *Socket
@@ -131,7 +128,6 @@ func NewClient(server *Server, conn net.Conn, isTLS bool) {
131 128
 	socket := NewSocket(conn, fullLineLenLimit*2, config.Server.MaxSendQBytes)
132 129
 	client := &Client{
133 130
 		atime:        now,
134
-		authorized:   server.Password() == nil,
135 131
 		capabilities: caps.NewSet(),
136 132
 		capState:     caps.NoneState,
137 133
 		capVersion:   caps.Cap301,
@@ -152,6 +148,12 @@ func NewClient(server *Server, conn net.Conn, isTLS bool) {
152 148
 	}
153 149
 	client.languages = server.languages.Default()
154 150
 
151
+	remoteAddr := conn.RemoteAddr()
152
+	client.realIP = utils.AddrToIP(remoteAddr)
153
+	if client.realIP == nil {
154
+		server.logger.Error("internal", "bad remote address", remoteAddr.String())
155
+		return
156
+	}
155 157
 	client.recomputeMaxlens()
156 158
 	if isTLS {
157 159
 		client.SetMode(modes.TLS, true)
@@ -159,7 +161,7 @@ func NewClient(server *Server, conn net.Conn, isTLS bool) {
159 161
 		// error is not useful to us here anyways so we can ignore it
160 162
 		client.certfp, _ = client.socket.CertFP()
161 163
 	}
162
-	if config.Server.CheckIdent && !utils.AddrIsUnix(conn.RemoteAddr()) {
164
+	if config.Server.CheckIdent && !utils.AddrIsUnix(remoteAddr) {
163 165
 		_, serverPortString, err := net.SplitHostPort(conn.LocalAddr().String())
164 166
 		if err != nil {
165 167
 			server.logger.Error("internal", "bad server address", err.Error())
@@ -196,6 +198,16 @@ func NewClient(server *Server, conn net.Conn, isTLS bool) {
196 198
 	go client.run()
197 199
 }
198 200
 
201
+func (client *Client) isAuthorized(config *Config) bool {
202
+	saslSent := client.account != ""
203
+	passRequirementMet := (config.Server.passwordBytes == nil) || client.sentPassCommand || (config.Accounts.SkipServerPassword && saslSent)
204
+	if !passRequirementMet {
205
+		return false
206
+	}
207
+	saslRequirementMet := !config.Accounts.RequireSasl.Enabled || saslSent || utils.IPInNets(client.IP(), config.Accounts.RequireSasl.exemptedNets)
208
+	return saslRequirementMet
209
+}
210
+
199 211
 func (client *Client) resetFakelag() {
200 212
 	fakelag := func() *Fakelag {
201 213
 		if client.HasRoleCapabs("nofakelag") {
@@ -218,14 +230,13 @@ func (client *Client) resetFakelag() {
218 230
 
219 231
 // IP returns the IP address of this client.
220 232
 func (client *Client) IP() net.IP {
233
+	client.stateMutex.RLock()
234
+	defer client.stateMutex.RUnlock()
235
+
221 236
 	if client.proxiedIP != nil {
222 237
 		return client.proxiedIP
223 238
 	}
224
-	if ip := utils.AddrToIP(client.socket.conn.RemoteAddr()); ip != nil {
225
-		return ip
226
-	}
227
-	// unix domain socket that hasn't issued PROXY/WEBIRC yet. YOLO
228
-	return LoopbackIP
239
+	return client.realIP
229 240
 }
230 241
 
231 242
 // IPString returns the IP address of this client as a string.
@@ -296,7 +307,7 @@ func (client *Client) run() {
296 307
 
297 308
 	// Set the hostname for this client
298 309
 	// (may be overridden by a later PROXY command from stunnel)
299
-	client.rawHostname = utils.AddrLookupHostname(client.socket.conn.RemoteAddr())
310
+	client.rawHostname = utils.LookupHostname(client.realIP.String())
300 311
 
301 312
 	firstLine := true
302 313
 

+ 3
- 1
irc/commands.go Voir le fichier

@@ -54,7 +54,9 @@ func (cmd *Command) Run(server *Server, client *Client, msg ircmsg.IrcMessage) b
54 54
 	}
55 55
 
56 56
 	// most servers do this only for PING/PONG, but we'll do it for any command:
57
-	client.idletimer.Touch()
57
+	if client.registered {
58
+		client.idletimer.Touch()
59
+	}
58 60
 
59 61
 	if !cmd.leaveClientIdle {
60 62
 		client.Active()

+ 20
- 3
irc/config.go Voir le fichier

@@ -11,6 +11,7 @@ import (
11 11
 	"fmt"
12 12
 	"io/ioutil"
13 13
 	"log"
14
+	"net"
14 15
 	"os"
15 16
 	"path/filepath"
16 17
 	"regexp"
@@ -54,7 +55,12 @@ func (conf *TLSListenConfig) Config() (*tls.Config, error) {
54 55
 type AccountConfig struct {
55 56
 	Registration          AccountRegistrationConfig
56 57
 	AuthenticationEnabled bool `yaml:"authentication-enabled"`
57
-	LoginThrottling       struct {
58
+	RequireSasl           struct {
59
+		Enabled      bool
60
+		Exempted     []string
61
+		exemptedNets []net.IPNet
62
+	} `yaml:"require-sasl"`
63
+	LoginThrottling struct {
58 64
 		Enabled     bool
59 65
 		Duration    time.Duration
60 66
 		MaxAttempts int `yaml:"max-attempts"`
@@ -261,8 +267,9 @@ type Config struct {
261 267
 		STS                  STSConfig
262 268
 		CheckIdent           bool `yaml:"check-ident"`
263 269
 		MOTD                 string
264
-		MOTDFormatting       bool           `yaml:"motd-formatting"`
265
-		ProxyAllowedFrom     []string       `yaml:"proxy-allowed-from"`
270
+		MOTDFormatting       bool     `yaml:"motd-formatting"`
271
+		ProxyAllowedFrom     []string `yaml:"proxy-allowed-from"`
272
+		proxyAllowedFromNets []net.IPNet
266 273
 		WebIRC               []webircConfig `yaml:"webirc"`
267 274
 		MaxSendQString       string         `yaml:"max-sendq"`
268 275
 		MaxSendQBytes        int
@@ -595,6 +602,16 @@ func LoadConfig(filename string) (config *Config, err error) {
595 602
 		}
596 603
 	}
597 604
 
605
+	config.Accounts.RequireSasl.exemptedNets, err = utils.ParseNetList(config.Accounts.RequireSasl.Exempted)
606
+	if err != nil {
607
+		return nil, fmt.Errorf("Could not parse require-sasl exempted nets: %v", err.Error())
608
+	}
609
+
610
+	config.Server.proxyAllowedFromNets, err = utils.ParseNetList(config.Server.ProxyAllowedFrom)
611
+	if err != nil {
612
+		return nil, fmt.Errorf("Could not parse proxy-allowed-from nets: %v", err.Error())
613
+	}
614
+
598 615
 	rawRegexp := config.Accounts.VHosts.ValidRegexpRaw
599 616
 	if rawRegexp != "" {
600 617
 		regexp, err := regexp.Compile(rawRegexp)

+ 6
- 24
irc/connection_limits/limiter.go Voir le fichier

@@ -8,6 +8,8 @@ import (
8 8
 	"fmt"
9 9
 	"net"
10 10
 	"sync"
11
+
12
+	"github.com/oragono/oragono/irc/utils"
11 13
 )
12 14
 
13 15
 // LimiterConfig controls the automated connection limits.
@@ -36,8 +38,6 @@ type Limiter struct {
36 38
 	// population holds IP -> count of clients connected from there
37 39
 	population map[string]int
38 40
 
39
-	// exemptedIPs holds IPs that are exempt from limits
40
-	exemptedIPs map[string]bool
41 41
 	// exemptedNets holds networks that are exempt from limits
42 42
 	exemptedNets []net.IPNet
43 43
 }
@@ -67,14 +67,9 @@ func (cl *Limiter) AddClient(addr net.IP, force bool) error {
67 67
 
68 68
 	// check exempted lists
69 69
 	// we don't track populations for exempted addresses or nets - this is by design
70
-	if cl.exemptedIPs[addr.String()] {
70
+	if utils.IPInNets(addr, cl.exemptedNets) {
71 71
 		return nil
72 72
 	}
73
-	for _, ex := range cl.exemptedNets {
74
-		if ex.Contains(addr) {
75
-			return nil
76
-		}
77
-	}
78 73
 
79 74
 	// check population
80 75
 	cl.maskAddr(addr)
@@ -121,21 +116,9 @@ func NewLimiter() *Limiter {
121 116
 // ApplyConfig atomically applies a config update to a connection limit handler
122 117
 func (cl *Limiter) ApplyConfig(config LimiterConfig) error {
123 118
 	// assemble exempted nets
124
-	exemptedIPs := make(map[string]bool)
125
-	var exemptedNets []net.IPNet
126
-	for _, cidr := range config.Exempted {
127
-		ipaddr := net.ParseIP(cidr)
128
-		_, netaddr, err := net.ParseCIDR(cidr)
129
-
130
-		if ipaddr == nil && err != nil {
131
-			return fmt.Errorf("Could not parse exempted IP/network [%s]", cidr)
132
-		}
133
-
134
-		if ipaddr != nil {
135
-			exemptedIPs[ipaddr.String()] = true
136
-		} else {
137
-			exemptedNets = append(exemptedNets, *netaddr)
138
-		}
119
+	exemptedNets, err := utils.ParseNetList(config.Exempted)
120
+	if err != nil {
121
+		return fmt.Errorf("Could not parse limiter exemption list: %v", err.Error())
139 122
 	}
140 123
 
141 124
 	cl.Lock()
@@ -151,7 +134,6 @@ func (cl *Limiter) ApplyConfig(config LimiterConfig) error {
151 134
 	if cl.subnetLimit == 0 && config.IPsPerSubnet != 0 {
152 135
 		cl.subnetLimit = config.IPsPerSubnet
153 136
 	}
154
-	cl.exemptedIPs = exemptedIPs
155 137
 	cl.exemptedNets = exemptedNets
156 138
 
157 139
 	return nil

+ 6
- 24
irc/connection_limits/throttler.go Voir le fichier

@@ -8,6 +8,8 @@ import (
8 8
 	"net"
9 9
 	"sync"
10 10
 	"time"
11
+
12
+	"github.com/oragono/oragono/irc/utils"
11 13
 )
12 14
 
13 15
 // ThrottlerConfig controls the automated connection throttling.
@@ -82,8 +84,6 @@ type Throttler struct {
82 84
 	banDuration time.Duration
83 85
 	banMessage  string
84 86
 
85
-	// exemptedIPs holds IPs that are exempt from limits
86
-	exemptedIPs map[string]bool
87 87
 	// exemptedNets holds networks that are exempt from limits
88 88
 	exemptedNets []net.IPNet
89 89
 }
@@ -126,14 +126,9 @@ func (ct *Throttler) AddClient(addr net.IP) error {
126 126
 	}
127 127
 
128 128
 	// check exempted lists
129
-	if ct.exemptedIPs[addr.String()] {
129
+	if utils.IPInNets(addr, ct.exemptedNets) {
130 130
 		return nil
131 131
 	}
132
-	for _, ex := range ct.exemptedNets {
133
-		if ex.Contains(addr) {
134
-			return nil
135
-		}
136
-	}
137 132
 
138 133
 	// check throttle
139 134
 	ct.maskAddr(addr)
@@ -184,21 +179,9 @@ func NewThrottler() *Throttler {
184 179
 // ApplyConfig atomically applies a config update to a throttler
185 180
 func (ct *Throttler) ApplyConfig(config ThrottlerConfig) error {
186 181
 	// assemble exempted nets
187
-	exemptedIPs := make(map[string]bool)
188
-	var exemptedNets []net.IPNet
189
-	for _, cidr := range config.Exempted {
190
-		ipaddr := net.ParseIP(cidr)
191
-		_, netaddr, err := net.ParseCIDR(cidr)
192
-
193
-		if ipaddr == nil && err != nil {
194
-			return fmt.Errorf("Could not parse exempted IP/network [%s]", cidr)
195
-		}
196
-
197
-		if ipaddr != nil {
198
-			exemptedIPs[ipaddr.String()] = true
199
-		} else {
200
-			exemptedNets = append(exemptedNets, *netaddr)
201
-		}
182
+	exemptedNets, err := utils.ParseNetList(config.Exempted)
183
+	if err != nil {
184
+		return fmt.Errorf("Could not parse throttle exemption list: %v", err.Error())
202 185
 	}
203 186
 
204 187
 	ct.Lock()
@@ -211,7 +194,6 @@ func (ct *Throttler) ApplyConfig(config ThrottlerConfig) error {
211 194
 	ct.duration = config.Duration
212 195
 	ct.banDuration = config.BanDuration
213 196
 	ct.banMessage = config.BanMessage
214
-	ct.exemptedIPs = exemptedIPs
215 197
 	ct.exemptedNets = exemptedNets
216 198
 
217 199
 	return nil

+ 11
- 38
irc/gateways.go Voir le fichier

@@ -25,6 +25,7 @@ type webircConfig struct {
25 25
 	Password       []byte `yaml:"password-bytes"`
26 26
 	Fingerprint    string
27 27
 	Hosts          []string
28
+	allowedNets    []net.IPNet
28 29
 }
29 30
 
30 31
 // Populate fills out our password or fingerprint.
@@ -36,49 +37,23 @@ func (wc *webircConfig) Populate() (err error) {
36 37
 	if wc.PasswordString != "" {
37 38
 		wc.Password, err = decodeLegacyPasswordHash(wc.PasswordString)
38 39
 	}
39
-	return err
40
-}
41
-
42
-func isGatewayAllowed(addr net.Addr, gatewaySpec string) bool {
43
-	// "localhost" includes any loopback IP or unix domain socket
44
-	if gatewaySpec == "localhost" {
45
-		return utils.AddrIsLocal(addr)
46
-	}
47
-
48
-	ip := utils.AddrToIP(addr)
49
-	if ip == nil {
50
-		return false
51
-	}
52 40
 
53
-	// exact IP match
54
-	if ip.String() == gatewaySpec {
55
-		return true
41
+	if err == nil {
42
+		wc.allowedNets, err = utils.ParseNetList(wc.Hosts)
56 43
 	}
57 44
 
58
-	// CIDR match
59
-	_, gatewayNet, err := net.ParseCIDR(gatewaySpec)
60
-	if err != nil {
61
-		return false
62
-	}
63
-	return gatewayNet.Contains(ip)
45
+	return err
64 46
 }
65 47
 
66 48
 // ApplyProxiedIP applies the given IP to the client.
67 49
 func (client *Client) ApplyProxiedIP(proxiedIP string, tls bool) (success bool) {
68 50
 	// ensure IP is sane
69
-	parsedProxiedIP := net.ParseIP(proxiedIP)
51
+	parsedProxiedIP := net.ParseIP(proxiedIP).To16()
70 52
 	if parsedProxiedIP == nil {
71 53
 		client.Quit(fmt.Sprintf(client.t("Proxied IP address is not valid: [%s]"), proxiedIP))
72 54
 		return false
73 55
 	}
74 56
 
75
-	// undo any mapping of v4 addresses into the v6 space: https://stackoverflow.com/a/1618259
76
-	// this is how a typical stunnel4 deployment on Linux will handle dual-stack
77
-	unmappedIP := parsedProxiedIP.To4()
78
-	if unmappedIP != nil {
79
-		parsedProxiedIP = unmappedIP
80
-	}
81
-
82 57
 	isBanned, banMsg := client.server.checkBans(parsedProxiedIP)
83 58
 	if isBanned {
84 59
 		client.Quit(banMsg)
@@ -117,14 +92,12 @@ func handleProxyCommand(server *Server, client *Client, line string) (err error)
117 92
 		return errBadProxyLine
118 93
 	}
119 94
 
120
-	for _, gateway := range server.ProxyAllowedFrom() {
121
-		if isGatewayAllowed(client.socket.conn.RemoteAddr(), gateway) {
122
-			// assume PROXY connections are always secure
123
-			if client.ApplyProxiedIP(params[2], true) {
124
-				return nil
125
-			} else {
126
-				return errBadProxyLine
127
-			}
95
+	if utils.IPInNets(client.realIP, server.Config().Server.proxyAllowedFromNets) {
96
+		// assume PROXY connections are always secure
97
+		if client.ApplyProxiedIP(params[2], true) {
98
+			return nil
99
+		} else {
100
+			return errBadProxyLine
128 101
 		}
129 102
 	}
130 103
 

+ 0
- 20
irc/getters.go Voir le fichier

@@ -32,14 +32,6 @@ func (server *Server) RecoverFromErrors() bool {
32 32
 	return *server.Config().Debug.RecoverFromErrors
33 33
 }
34 34
 
35
-func (server *Server) ProxyAllowedFrom() []string {
36
-	return server.Config().Server.ProxyAllowedFrom
37
-}
38
-
39
-func (server *Server) WebIRCConfig() []webircConfig {
40
-	return server.Config().Server.WebIRC
41
-}
42
-
43 35
 func (server *Server) DefaultChannelModes() modes.Modes {
44 36
 	return server.Config().Channels.defaultModes
45 37
 }
@@ -170,18 +162,6 @@ func (client *Client) SetAccountName(account string) (changed bool) {
170 162
 	return
171 163
 }
172 164
 
173
-func (client *Client) Authorized() bool {
174
-	client.stateMutex.RLock()
175
-	defer client.stateMutex.RUnlock()
176
-	return client.authorized
177
-}
178
-
179
-func (client *Client) SetAuthorized(authorized bool) {
180
-	client.stateMutex.Lock()
181
-	defer client.stateMutex.Unlock()
182
-	client.authorized = authorized
183
-}
184
-
185 165
 func (client *Client) HasMode(mode modes.Mode) bool {
186 166
 	// client.flags has its own synch
187 167
 	return client.flags.HasMode(mode)

+ 23
- 30
irc/handlers.go Voir le fichier

@@ -323,10 +323,6 @@ func authenticateHandler(server *Server, client *Client, msg ircmsg.IrcMessage,
323 323
 	// let the SASL handler do its thing
324 324
 	exiting := handler(server, client, client.saslMechanism, data, rb)
325 325
 
326
-	if client.LoggedIntoAccount() && server.AccountConfig().SkipServerPassword {
327
-		client.SetAuthorized(true)
328
-	}
329
-
330 326
 	// wait 'til SASL is done before emptying the sasl vars
331 327
 	client.saslInProgress = false
332 328
 	client.saslMechanism = ""
@@ -516,7 +512,7 @@ func capHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Respo
516 512
 		}
517 513
 
518 514
 	case "END":
519
-		if !client.Registered() {
515
+		if !client.registered {
520 516
 			client.capState = caps.NegotiatedState
521 517
 		}
522 518
 
@@ -1577,7 +1573,7 @@ func namesHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Res
1577 1573
 
1578 1574
 // NICK <nickname>
1579 1575
 func nickHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
1580
-	if client.Registered() {
1576
+	if client.registered {
1581 1577
 		performNickChange(server, client, client, msg.Params[0], rb)
1582 1578
 	} else {
1583 1579
 		client.preregNick = msg.Params[0]
@@ -1758,7 +1754,7 @@ func partHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp
1758 1754
 
1759 1755
 // PASS <password>
1760 1756
 func passHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
1761
-	if client.Registered() {
1757
+	if client.registered {
1762 1758
 		rb.Add(nil, server.name, ERR_ALREADYREGISTRED, client.nick, client.t("You may not reregister"))
1763 1759
 		return false
1764 1760
 	}
@@ -1766,7 +1762,6 @@ func passHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp
1766 1762
 	// if no password exists, skip checking
1767 1763
 	serverPassword := server.Password()
1768 1764
 	if serverPassword == nil {
1769
-		client.SetAuthorized(true)
1770 1765
 		return false
1771 1766
 	}
1772 1767
 
@@ -1778,7 +1773,7 @@ func passHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp
1778 1773
 		return true
1779 1774
 	}
1780 1775
 
1781
-	client.SetAuthorized(true)
1776
+	client.sentPassCommand = true
1782 1777
 	return false
1783 1778
 }
1784 1779
 
@@ -1986,7 +1981,7 @@ func resumeHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Re
1986 1981
 	oldnick := msg.Params[0]
1987 1982
 	token := msg.Params[1]
1988 1983
 
1989
-	if client.Registered() {
1984
+	if client.registered {
1990 1985
 		rb.Add(nil, server.name, ERR_CANNOT_RESUME, oldnick, client.t("Cannot resume connection, connection registration has already been completed"))
1991 1986
 		return false
1992 1987
 	}
@@ -2188,7 +2183,7 @@ func unKLineHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *R
2188 2183
 
2189 2184
 // USER <username> * 0 <realname>
2190 2185
 func userHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
2191
-	if client.Registered() {
2186
+	if client.registered {
2192 2187
 		rb.Add(nil, server.name, ERR_ALREADYREGISTRED, client.nick, client.t("You may not reregister"))
2193 2188
 		return false
2194 2189
 	}
@@ -2255,7 +2250,7 @@ func versionHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *R
2255 2250
 // WEBIRC <password> <gateway> <hostname> <ip> [:flag1 flag2=x flag3]
2256 2251
 func webircHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
2257 2252
 	// only allow unregistered clients to use this command
2258
-	if client.Registered() || client.proxiedIP != nil {
2253
+	if client.registered || client.proxiedIP != nil {
2259 2254
 		return false
2260 2255
 	}
2261 2256
 
@@ -2282,26 +2277,24 @@ func webircHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Re
2282 2277
 		}
2283 2278
 	}
2284 2279
 
2285
-	for _, info := range server.WebIRCConfig() {
2286
-		for _, gateway := range info.Hosts {
2287
-			if isGatewayAllowed(client.socket.conn.RemoteAddr(), gateway) {
2288
-				// confirm password and/or fingerprint
2289
-				givenPassword := msg.Params[0]
2290
-				if 0 < len(info.Password) && bcrypt.CompareHashAndPassword(info.Password, []byte(givenPassword)) != nil {
2291
-					continue
2292
-				}
2293
-				if 0 < len(info.Fingerprint) && client.certfp != info.Fingerprint {
2294
-					continue
2295
-				}
2280
+	givenPassword := []byte(msg.Params[0])
2281
+	for _, info := range server.Config().Server.WebIRC {
2282
+		if utils.IPInNets(client.realIP, info.allowedNets) {
2283
+			// confirm password and/or fingerprint
2284
+			if 0 < len(info.Password) && bcrypt.CompareHashAndPassword(info.Password, givenPassword) != nil {
2285
+				continue
2286
+			}
2287
+			if 0 < len(info.Fingerprint) && client.certfp != info.Fingerprint {
2288
+				continue
2289
+			}
2296 2290
 
2297
-				proxiedIP := msg.Params[3]
2298
-				// see #211; websocket gateways will wrap ipv6 addresses in square brackets
2299
-				// because IRC parameters can't start with :
2300
-				if strings.HasPrefix(proxiedIP, "[") && strings.HasSuffix(proxiedIP, "]") {
2301
-					proxiedIP = proxiedIP[1 : len(proxiedIP)-1]
2302
-				}
2303
-				return !client.ApplyProxiedIP(proxiedIP, secure)
2291
+			proxiedIP := msg.Params[3]
2292
+			// see #211; websocket gateways will wrap ipv6 addresses in square brackets
2293
+			// because IRC parameters can't start with :
2294
+			if strings.HasPrefix(proxiedIP, "[") && strings.HasSuffix(proxiedIP, "]") {
2295
+				proxiedIP = proxiedIP[1 : len(proxiedIP)-1]
2304 2296
 			}
2297
+			return !client.ApplyProxiedIP(proxiedIP, secure)
2305 2298
 		}
2306 2299
 	}
2307 2300
 

+ 0
- 5
irc/idletimer.go Voir le fichier

@@ -83,11 +83,6 @@ func (it *IdleTimer) Start() {
83 83
 }
84 84
 
85 85
 func (it *IdleTimer) Touch() {
86
-	// ignore touches from unregistered clients
87
-	if !it.client.Registered() {
88
-		return
89
-	}
90
-
91 86
 	it.updateIdleDuration()
92 87
 
93 88
 	it.Lock()

+ 37
- 16
irc/nickserv.go Voir le fichier

@@ -5,7 +5,6 @@ package irc
5 5
 
6 6
 import (
7 7
 	"fmt"
8
-	"strings"
9 8
 
10 9
 	"github.com/goshuirc/irc-go/ircfmt"
11 10
 )
@@ -123,6 +122,18 @@ SADROP forcibly de-links the given nickname from the attached user account.`,
123 122
 			enabled:   servCmdRequiresAccreg,
124 123
 			minParams: 1,
125 124
 		},
125
+		"saregister": {
126
+			handler: nsSaregisterHandler,
127
+			help: `Syntax: $bSAREGISTER <username> <password>$b
128
+
129
+SAREGISTER registers an account on someone else's behalf.
130
+This is for use in configurations that require SASL for all connections;
131
+an administrator can set use this command to set up user accounts.`,
132
+			helpShort: `$bSAREGISTER$b registers an account on someone else's behalf.`,
133
+			enabled:   servCmdRequiresAccreg,
134
+			capabs:    []string{"accreg"},
135
+			minParams: 2,
136
+		},
126 137
 		"unregister": {
127 138
 			handler: nsUnregisterHandler,
128 139
 			help: `Syntax: $bUNREGISTER <username> [code]$b
@@ -311,22 +322,12 @@ func nsInfoHandler(server *Server, client *Client, command string, params []stri
311 322
 
312 323
 func nsRegisterHandler(server *Server, client *Client, command string, params []string, rb *ResponseBuffer) {
313 324
 	// get params
314
-	username, email := params[0], params[1]
325
+	account, email := params[0], params[1]
315 326
 	var passphrase string
316 327
 	if len(params) > 2 {
317 328
 		passphrase = params[2]
318 329
 	}
319 330
 
320
-	if !server.AccountConfig().Registration.Enabled {
321
-		nsNotice(rb, client.t("Account registration has been disabled"))
322
-		return
323
-	}
324
-
325
-	if username == "" {
326
-		nsNotice(rb, client.t("No username supplied"))
327
-		return
328
-	}
329
-
330 331
 	certfp := client.certfp
331 332
 	if passphrase == "" && certfp == "" {
332 333
 		nsNotice(rb, client.t("You need to either supply a passphrase or be connected via TLS with a client cert"))
@@ -359,9 +360,6 @@ func nsRegisterHandler(server *Server, client *Client, command string, params []
359 360
 		}
360 361
 	}
361 362
 
362
-	// get and sanitise account name
363
-	account := strings.TrimSpace(username)
364
-
365 363
 	err := server.accounts.Register(client, account, callbackNamespace, callbackValue, passphrase, client.certfp)
366 364
 	if err == nil {
367 365
 		if callbackNamespace == "*" {
@@ -381,7 +379,7 @@ func nsRegisterHandler(server *Server, client *Client, command string, params []
381 379
 		errMsg := client.t("Could not register")
382 380
 		if err == errCertfpAlreadyExists {
383 381
 			errMsg = client.t("An account already exists for your certificate fingerprint")
384
-		} else if err == errAccountAlreadyRegistered {
382
+		} else if err == errAccountAlreadyRegistered || err == errAccountAlreadyVerified {
385 383
 			errMsg = client.t("Account already exists")
386 384
 		} else if err == errAccountBadPassphrase {
387 385
 			errMsg = client.t("Passphrase contains forbidden characters or is otherwise invalid")
@@ -391,6 +389,29 @@ func nsRegisterHandler(server *Server, client *Client, command string, params []
391 389
 	}
392 390
 }
393 391
 
392
+func nsSaregisterHandler(server *Server, client *Client, command string, params []string, rb *ResponseBuffer) {
393
+	account, passphrase := params[0], params[1]
394
+	err := server.accounts.Register(nil, account, "admin", "", passphrase, "")
395
+	if err == nil {
396
+		err = server.accounts.Verify(nil, account, "")
397
+	}
398
+
399
+	if err != nil {
400
+		var errMsg string
401
+		if err == errAccountAlreadyRegistered || err == errAccountAlreadyVerified {
402
+			errMsg = client.t("Account already exists")
403
+		} else if err == errAccountBadPassphrase {
404
+			errMsg = client.t("Passphrase contains forbidden characters or is otherwise invalid")
405
+		} else {
406
+			server.logger.Error("services", "unknown error from saregister", err.Error())
407
+			errMsg = client.t("Could not register")
408
+		}
409
+		nsNotice(rb, errMsg)
410
+	} else {
411
+		nsNotice(rb, fmt.Sprintf(client.t("Successfully registered account %s"), account))
412
+	}
413
+}
414
+
394 415
 func nsUnregisterHandler(server *Server, client *Client, command string, params []string, rb *ResponseBuffer) {
395 416
 	username := params[0]
396 417
 	var verificationCode string

+ 4
- 3
irc/server.go Voir le fichier

@@ -381,7 +381,7 @@ func (server *Server) generateMessageID() string {
381 381
 //
382 382
 
383 383
 func (server *Server) tryRegister(c *Client) {
384
-	if c.Registered() {
384
+	if c.registered {
385 385
 		return
386 386
 	}
387 387
 
@@ -389,9 +389,10 @@ func (server *Server) tryRegister(c *Client) {
389 389
 		return
390 390
 	}
391 391
 
392
-	// client MUST send PASS (or AUTHENTICATE, if skip-server-password is set)
392
+	// client MUST send PASS if necessary, or authenticate with SASL if necessary,
393 393
 	// before completing the other registration commands
394
-	if !c.Authorized() {
394
+	config := server.Config()
395
+	if !c.isAuthorized(config) {
395 396
 		c.Quit(c.t("Bad password"))
396 397
 		c.destroy(false)
397 398
 		return

+ 41
- 25
irc/utils/net.go Voir le fichier

@@ -11,43 +11,27 @@ import (
11 11
 
12 12
 var (
13 13
 	// subnet mask for an ipv6 /128:
14
-	mask128 = net.CIDRMask(128, 128)
14
+	mask128             = net.CIDRMask(128, 128)
15
+	IPv4LoopbackAddress = net.ParseIP("127.0.0.1").To16()
15 16
 )
16 17
 
17
-// IPString returns a simple IP string from the given net.Addr.
18
-func IPString(addr net.Addr) string {
19
-	addrStr := addr.String()
20
-	ipaddr, _, err := net.SplitHostPort(addrStr)
21
-	//TODO(dan): Why is this needed, does this happen?
22
-	if err != nil {
23
-		return addrStr
24
-	}
25
-	return ipaddr
26
-}
27
-
28
-// AddrLookupHostname returns the hostname (if possible) or address for the given `net.Addr`.
29
-func AddrLookupHostname(addr net.Addr) string {
30
-	if AddrIsUnix(addr) {
31
-		return "localhost"
32
-	}
33
-	return LookupHostname(IPString(addr))
34
-}
35
-
36 18
 // AddrIsLocal returns whether the address is from a trusted local connection (loopback or unix).
37 19
 func AddrIsLocal(addr net.Addr) bool {
38 20
 	if tcpaddr, ok := addr.(*net.TCPAddr); ok {
39 21
 		return tcpaddr.IP.IsLoopback()
40 22
 	}
41
-	_, ok := addr.(*net.UnixAddr)
42
-	return ok
23
+	return AddrIsUnix(addr)
43 24
 }
44 25
 
45
-// AddrToIP returns the IP address for a net.Addr, or nil if it's a unix domain socket.
26
+// AddrToIP returns the IP address for a net.Addr; unix domain sockets are treated as IPv4 loopback
46 27
 func AddrToIP(addr net.Addr) net.IP {
47 28
 	if tcpaddr, ok := addr.(*net.TCPAddr); ok {
48
-		return tcpaddr.IP
29
+		return tcpaddr.IP.To16()
30
+	} else if AddrIsUnix(addr) {
31
+		return IPv4LoopbackAddress
32
+	} else {
33
+		return nil
49 34
 	}
50
-	return nil
51 35
 }
52 36
 
53 37
 // AddrIsUnix returns whether the address is a unix domain socket.
@@ -100,6 +84,16 @@ func IsHostname(name string) bool {
100 84
 	return true
101 85
 }
102 86
 
87
+// Convenience to test whether `ip` is contained in any of `nets`.
88
+func IPInNets(ip net.IP, nets []net.IPNet) bool {
89
+	for _, network := range nets {
90
+		if network.Contains(ip) {
91
+			return true
92
+		}
93
+	}
94
+	return false
95
+}
96
+
103 97
 // NormalizeIPToNet represents an address (v4 or v6) as the v6 /128 CIDR
104 98
 // containing only it.
105 99
 func NormalizeIPToNet(addr net.IP) (network net.IPNet) {
@@ -156,3 +150,25 @@ func NormalizedNetFromString(str string) (result net.IPNet, err error) {
156 150
 	}
157 151
 	return NormalizeIPToNet(ip), nil
158 152
 }
153
+
154
+// Parse a list of IPs and nets as they would appear in one of our config
155
+// files, e.g., proxy-allowed-from or a throttling exemption list.
156
+func ParseNetList(netList []string) (nets []net.IPNet, err error) {
157
+	var network net.IPNet
158
+	for _, netStr := range netList {
159
+		if netStr == "localhost" {
160
+			ipv4Loopback, _ := NormalizedNetFromString("127.0.0.0/8")
161
+			ipv6Loopback, _ := NormalizedNetFromString("::1/128")
162
+			nets = append(nets, ipv4Loopback)
163
+			nets = append(nets, ipv6Loopback)
164
+			continue
165
+		}
166
+		network, err = NormalizedNetFromString(netStr)
167
+		if err != nil {
168
+			return
169
+		} else {
170
+			nets = append(nets, network)
171
+		}
172
+	}
173
+	return
174
+}

+ 18
- 9
oragono.yaml Voir le fichier

@@ -67,8 +67,8 @@ server:
67 67
     # if this is true, the motd is escaped using formatting codes like $c, $b, and $i
68 68
     motd-formatting: true
69 69
 
70
-    # addresses/hostnames the PROXY command can be used from
71
-    # this should be restricted to 127.0.0.1/8 and localhost at most
70
+    # addresses/CIDRs the PROXY command can be used from
71
+    # this should be restricted to 127.0.0.1/8 and ::1/128 (unless you have a good reason)
72 72
     # you should also add these addresses to the connection limits and throttling exemption lists
73 73
     proxy-allowed-from:
74 74
         # - localhost
@@ -85,7 +85,7 @@ server:
85 85
             # password the gateway uses to connect, made with  oragono genpasswd
86 86
             password: "$2a$04$sLEFDpIOyUp55e6gTMKbOeroT6tMXTjPFvA0eGvwvImVR9pkwv7ee"
87 87
 
88
-            # hosts that can use this webirc command
88
+            # addresses/CIDRs that can use this webirc command
89 89
             # you should also add these addresses to the connection limits and throttling exemption lists
90 90
             hosts:
91 91
                 # - localhost
@@ -117,9 +117,9 @@ server:
117 117
 
118 118
         # IPs/networks which are exempted from connection limits
119 119
         exempted:
120
-            - "127.0.0.1"
121
-            - "127.0.0.1/8"
122
-            - "::1/128"
120
+            - "localhost"
121
+            # - "192.168.1.1"
122
+            # - "2001:0db8::/32"
123 123
 
124 124
     # automated connection throttling
125 125
     connection-throttling:
@@ -145,9 +145,9 @@ server:
145 145
 
146 146
         # IPs/networks which are exempted from connection limits
147 147
         exempted:
148
-            - "127.0.0.1"
149
-            - "127.0.0.1/8"
150
-            - "::1/128"
148
+            - "localhost"
149
+            # - "192.168.1.1"
150
+            # - "2001:0db8::/32"
151 151
 
152 152
 # account options
153 153
 accounts:
@@ -198,6 +198,15 @@ accounts:
198 198
     # PASS as well, so it can be configured to authenticate with SASL only.
199 199
     skip-server-password: false
200 200
 
201
+    require-sasl:
202
+        # if this is enabled, all clients must authenticate with SASL:
203
+        enabled: false
204
+        # the following IPs/CIDRs are exempted from this requirement:
205
+        exempted:
206
+            - "localhost"
207
+            # - '127.0.0.2'
208
+            # - '10.10.0.0/16'
209
+
201 210
     # nick-reservation controls how, and whether, nicknames are linked to accounts
202 211
     nick-reservation:
203 212
         # is there any enforcement of reserved nicknames?

Chargement…
Annuler
Enregistrer