Procházet zdrojové kódy

add sasl-only config option

tags/v1.0.0-rc1
Shivaram Lingamneni před 5 roky
rodič
revize
1c23af8767
14 změnil soubory, kde provedl 197 přidání a 213 odebrání
  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 Zobrazit soubor

456
 }
456
 }
457
 
457
 
458
 func (am *AccountManager) dispatchCallback(client *Client, casefoldedAccount string, callbackNamespace string, callbackValue string) (string, error) {
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
 		return "", nil
460
 		return "", nil
461
 	} else if callbackNamespace == "mailto" {
461
 	} else if callbackNamespace == "mailto" {
462
 		return am.dispatchMailtoCallback(client, casefoldedAccount, callbackValue)
462
 		return am.dispatchMailtoCallback(client, casefoldedAccount, callbackValue)
590
 	if err != nil {
590
 	if err != nil {
591
 		return err
591
 		return err
592
 	}
592
 	}
593
-	am.Login(client, clientAccount)
593
+	if client != nil {
594
+		am.Login(client, clientAccount)
595
+	}
594
 	return nil
596
 	return nil
595
 }
597
 }
596
 
598
 

+ 24
- 13
irc/client.go Zobrazit soubor

32
 	IRCv3TimestampFormat = "2006-01-02T15:04:05.000Z"
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
 // ResumeDetails is a place to stash data at various stages of
35
 // ResumeDetails is a place to stash data at various stages of
40
 // the resume process: when handling the RESUME command itself,
36
 // the resume process: when handling the RESUME command itself,
41
 // when completing the registration, and when rejoining channels.
37
 // when completing the registration, and when rejoining channels.
55
 	account            string
51
 	account            string
56
 	accountName        string // display name of the account: uncasefolded, '*' if not logged in
52
 	accountName        string // display name of the account: uncasefolded, '*' if not logged in
57
 	atime              time.Time
53
 	atime              time.Time
58
-	authorized         bool
59
 	awayMessage        string
54
 	awayMessage        string
60
 	capabilities       *caps.Set
55
 	capabilities       *caps.Set
61
 	capState           caps.State
56
 	capState           caps.State
88
 	quitMessage        string
83
 	quitMessage        string
89
 	rawHostname        string
84
 	rawHostname        string
90
 	realname           string
85
 	realname           string
86
+	realIP             net.IP
91
 	registered         bool
87
 	registered         bool
92
 	resumeDetails      *ResumeDetails
88
 	resumeDetails      *ResumeDetails
93
 	resumeToken        string
89
 	resumeToken        string
94
 	saslInProgress     bool
90
 	saslInProgress     bool
95
 	saslMechanism      string
91
 	saslMechanism      string
96
 	saslValue          string
92
 	saslValue          string
93
+	sentPassCommand    bool
97
 	server             *Server
94
 	server             *Server
98
 	skeleton           string
95
 	skeleton           string
99
 	socket             *Socket
96
 	socket             *Socket
131
 	socket := NewSocket(conn, fullLineLenLimit*2, config.Server.MaxSendQBytes)
128
 	socket := NewSocket(conn, fullLineLenLimit*2, config.Server.MaxSendQBytes)
132
 	client := &Client{
129
 	client := &Client{
133
 		atime:        now,
130
 		atime:        now,
134
-		authorized:   server.Password() == nil,
135
 		capabilities: caps.NewSet(),
131
 		capabilities: caps.NewSet(),
136
 		capState:     caps.NoneState,
132
 		capState:     caps.NoneState,
137
 		capVersion:   caps.Cap301,
133
 		capVersion:   caps.Cap301,
152
 	}
148
 	}
153
 	client.languages = server.languages.Default()
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
 	client.recomputeMaxlens()
157
 	client.recomputeMaxlens()
156
 	if isTLS {
158
 	if isTLS {
157
 		client.SetMode(modes.TLS, true)
159
 		client.SetMode(modes.TLS, true)
159
 		// error is not useful to us here anyways so we can ignore it
161
 		// error is not useful to us here anyways so we can ignore it
160
 		client.certfp, _ = client.socket.CertFP()
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
 		_, serverPortString, err := net.SplitHostPort(conn.LocalAddr().String())
165
 		_, serverPortString, err := net.SplitHostPort(conn.LocalAddr().String())
164
 		if err != nil {
166
 		if err != nil {
165
 			server.logger.Error("internal", "bad server address", err.Error())
167
 			server.logger.Error("internal", "bad server address", err.Error())
196
 	go client.run()
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
 func (client *Client) resetFakelag() {
211
 func (client *Client) resetFakelag() {
200
 	fakelag := func() *Fakelag {
212
 	fakelag := func() *Fakelag {
201
 		if client.HasRoleCapabs("nofakelag") {
213
 		if client.HasRoleCapabs("nofakelag") {
218
 
230
 
219
 // IP returns the IP address of this client.
231
 // IP returns the IP address of this client.
220
 func (client *Client) IP() net.IP {
232
 func (client *Client) IP() net.IP {
233
+	client.stateMutex.RLock()
234
+	defer client.stateMutex.RUnlock()
235
+
221
 	if client.proxiedIP != nil {
236
 	if client.proxiedIP != nil {
222
 		return client.proxiedIP
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
 // IPString returns the IP address of this client as a string.
242
 // IPString returns the IP address of this client as a string.
296
 
307
 
297
 	// Set the hostname for this client
308
 	// Set the hostname for this client
298
 	// (may be overridden by a later PROXY command from stunnel)
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
 	firstLine := true
312
 	firstLine := true
302
 
313
 

+ 3
- 1
irc/commands.go Zobrazit soubor

54
 	}
54
 	}
55
 
55
 
56
 	// most servers do this only for PING/PONG, but we'll do it for any command:
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
 	if !cmd.leaveClientIdle {
61
 	if !cmd.leaveClientIdle {
60
 		client.Active()
62
 		client.Active()

+ 20
- 3
irc/config.go Zobrazit soubor

11
 	"fmt"
11
 	"fmt"
12
 	"io/ioutil"
12
 	"io/ioutil"
13
 	"log"
13
 	"log"
14
+	"net"
14
 	"os"
15
 	"os"
15
 	"path/filepath"
16
 	"path/filepath"
16
 	"regexp"
17
 	"regexp"
54
 type AccountConfig struct {
55
 type AccountConfig struct {
55
 	Registration          AccountRegistrationConfig
56
 	Registration          AccountRegistrationConfig
56
 	AuthenticationEnabled bool `yaml:"authentication-enabled"`
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
 		Enabled     bool
64
 		Enabled     bool
59
 		Duration    time.Duration
65
 		Duration    time.Duration
60
 		MaxAttempts int `yaml:"max-attempts"`
66
 		MaxAttempts int `yaml:"max-attempts"`
261
 		STS                  STSConfig
267
 		STS                  STSConfig
262
 		CheckIdent           bool `yaml:"check-ident"`
268
 		CheckIdent           bool `yaml:"check-ident"`
263
 		MOTD                 string
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
 		WebIRC               []webircConfig `yaml:"webirc"`
273
 		WebIRC               []webircConfig `yaml:"webirc"`
267
 		MaxSendQString       string         `yaml:"max-sendq"`
274
 		MaxSendQString       string         `yaml:"max-sendq"`
268
 		MaxSendQBytes        int
275
 		MaxSendQBytes        int
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
 	rawRegexp := config.Accounts.VHosts.ValidRegexpRaw
615
 	rawRegexp := config.Accounts.VHosts.ValidRegexpRaw
599
 	if rawRegexp != "" {
616
 	if rawRegexp != "" {
600
 		regexp, err := regexp.Compile(rawRegexp)
617
 		regexp, err := regexp.Compile(rawRegexp)

+ 6
- 24
irc/connection_limits/limiter.go Zobrazit soubor

8
 	"fmt"
8
 	"fmt"
9
 	"net"
9
 	"net"
10
 	"sync"
10
 	"sync"
11
+
12
+	"github.com/oragono/oragono/irc/utils"
11
 )
13
 )
12
 
14
 
13
 // LimiterConfig controls the automated connection limits.
15
 // LimiterConfig controls the automated connection limits.
36
 	// population holds IP -> count of clients connected from there
38
 	// population holds IP -> count of clients connected from there
37
 	population map[string]int
39
 	population map[string]int
38
 
40
 
39
-	// exemptedIPs holds IPs that are exempt from limits
40
-	exemptedIPs map[string]bool
41
 	// exemptedNets holds networks that are exempt from limits
41
 	// exemptedNets holds networks that are exempt from limits
42
 	exemptedNets []net.IPNet
42
 	exemptedNets []net.IPNet
43
 }
43
 }
67
 
67
 
68
 	// check exempted lists
68
 	// check exempted lists
69
 	// we don't track populations for exempted addresses or nets - this is by design
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
 		return nil
71
 		return nil
72
 	}
72
 	}
73
-	for _, ex := range cl.exemptedNets {
74
-		if ex.Contains(addr) {
75
-			return nil
76
-		}
77
-	}
78
 
73
 
79
 	// check population
74
 	// check population
80
 	cl.maskAddr(addr)
75
 	cl.maskAddr(addr)
121
 // ApplyConfig atomically applies a config update to a connection limit handler
116
 // ApplyConfig atomically applies a config update to a connection limit handler
122
 func (cl *Limiter) ApplyConfig(config LimiterConfig) error {
117
 func (cl *Limiter) ApplyConfig(config LimiterConfig) error {
123
 	// assemble exempted nets
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
 	cl.Lock()
124
 	cl.Lock()
151
 	if cl.subnetLimit == 0 && config.IPsPerSubnet != 0 {
134
 	if cl.subnetLimit == 0 && config.IPsPerSubnet != 0 {
152
 		cl.subnetLimit = config.IPsPerSubnet
135
 		cl.subnetLimit = config.IPsPerSubnet
153
 	}
136
 	}
154
-	cl.exemptedIPs = exemptedIPs
155
 	cl.exemptedNets = exemptedNets
137
 	cl.exemptedNets = exemptedNets
156
 
138
 
157
 	return nil
139
 	return nil

+ 6
- 24
irc/connection_limits/throttler.go Zobrazit soubor

8
 	"net"
8
 	"net"
9
 	"sync"
9
 	"sync"
10
 	"time"
10
 	"time"
11
+
12
+	"github.com/oragono/oragono/irc/utils"
11
 )
13
 )
12
 
14
 
13
 // ThrottlerConfig controls the automated connection throttling.
15
 // ThrottlerConfig controls the automated connection throttling.
82
 	banDuration time.Duration
84
 	banDuration time.Duration
83
 	banMessage  string
85
 	banMessage  string
84
 
86
 
85
-	// exemptedIPs holds IPs that are exempt from limits
86
-	exemptedIPs map[string]bool
87
 	// exemptedNets holds networks that are exempt from limits
87
 	// exemptedNets holds networks that are exempt from limits
88
 	exemptedNets []net.IPNet
88
 	exemptedNets []net.IPNet
89
 }
89
 }
126
 	}
126
 	}
127
 
127
 
128
 	// check exempted lists
128
 	// check exempted lists
129
-	if ct.exemptedIPs[addr.String()] {
129
+	if utils.IPInNets(addr, ct.exemptedNets) {
130
 		return nil
130
 		return nil
131
 	}
131
 	}
132
-	for _, ex := range ct.exemptedNets {
133
-		if ex.Contains(addr) {
134
-			return nil
135
-		}
136
-	}
137
 
132
 
138
 	// check throttle
133
 	// check throttle
139
 	ct.maskAddr(addr)
134
 	ct.maskAddr(addr)
184
 // ApplyConfig atomically applies a config update to a throttler
179
 // ApplyConfig atomically applies a config update to a throttler
185
 func (ct *Throttler) ApplyConfig(config ThrottlerConfig) error {
180
 func (ct *Throttler) ApplyConfig(config ThrottlerConfig) error {
186
 	// assemble exempted nets
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
 	ct.Lock()
187
 	ct.Lock()
211
 	ct.duration = config.Duration
194
 	ct.duration = config.Duration
212
 	ct.banDuration = config.BanDuration
195
 	ct.banDuration = config.BanDuration
213
 	ct.banMessage = config.BanMessage
196
 	ct.banMessage = config.BanMessage
214
-	ct.exemptedIPs = exemptedIPs
215
 	ct.exemptedNets = exemptedNets
197
 	ct.exemptedNets = exemptedNets
216
 
198
 
217
 	return nil
199
 	return nil

+ 11
- 38
irc/gateways.go Zobrazit soubor

25
 	Password       []byte `yaml:"password-bytes"`
25
 	Password       []byte `yaml:"password-bytes"`
26
 	Fingerprint    string
26
 	Fingerprint    string
27
 	Hosts          []string
27
 	Hosts          []string
28
+	allowedNets    []net.IPNet
28
 }
29
 }
29
 
30
 
30
 // Populate fills out our password or fingerprint.
31
 // Populate fills out our password or fingerprint.
36
 	if wc.PasswordString != "" {
37
 	if wc.PasswordString != "" {
37
 		wc.Password, err = decodeLegacyPasswordHash(wc.PasswordString)
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
 // ApplyProxiedIP applies the given IP to the client.
48
 // ApplyProxiedIP applies the given IP to the client.
67
 func (client *Client) ApplyProxiedIP(proxiedIP string, tls bool) (success bool) {
49
 func (client *Client) ApplyProxiedIP(proxiedIP string, tls bool) (success bool) {
68
 	// ensure IP is sane
50
 	// ensure IP is sane
69
-	parsedProxiedIP := net.ParseIP(proxiedIP)
51
+	parsedProxiedIP := net.ParseIP(proxiedIP).To16()
70
 	if parsedProxiedIP == nil {
52
 	if parsedProxiedIP == nil {
71
 		client.Quit(fmt.Sprintf(client.t("Proxied IP address is not valid: [%s]"), proxiedIP))
53
 		client.Quit(fmt.Sprintf(client.t("Proxied IP address is not valid: [%s]"), proxiedIP))
72
 		return false
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
 	isBanned, banMsg := client.server.checkBans(parsedProxiedIP)
57
 	isBanned, banMsg := client.server.checkBans(parsedProxiedIP)
83
 	if isBanned {
58
 	if isBanned {
84
 		client.Quit(banMsg)
59
 		client.Quit(banMsg)
117
 		return errBadProxyLine
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 Zobrazit soubor

32
 	return *server.Config().Debug.RecoverFromErrors
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
 func (server *Server) DefaultChannelModes() modes.Modes {
35
 func (server *Server) DefaultChannelModes() modes.Modes {
44
 	return server.Config().Channels.defaultModes
36
 	return server.Config().Channels.defaultModes
45
 }
37
 }
170
 	return
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
 func (client *Client) HasMode(mode modes.Mode) bool {
165
 func (client *Client) HasMode(mode modes.Mode) bool {
186
 	// client.flags has its own synch
166
 	// client.flags has its own synch
187
 	return client.flags.HasMode(mode)
167
 	return client.flags.HasMode(mode)

+ 23
- 30
irc/handlers.go Zobrazit soubor

323
 	// let the SASL handler do its thing
323
 	// let the SASL handler do its thing
324
 	exiting := handler(server, client, client.saslMechanism, data, rb)
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
 	// wait 'til SASL is done before emptying the sasl vars
326
 	// wait 'til SASL is done before emptying the sasl vars
331
 	client.saslInProgress = false
327
 	client.saslInProgress = false
332
 	client.saslMechanism = ""
328
 	client.saslMechanism = ""
516
 		}
512
 		}
517
 
513
 
518
 	case "END":
514
 	case "END":
519
-		if !client.Registered() {
515
+		if !client.registered {
520
 			client.capState = caps.NegotiatedState
516
 			client.capState = caps.NegotiatedState
521
 		}
517
 		}
522
 
518
 
1577
 
1573
 
1578
 // NICK <nickname>
1574
 // NICK <nickname>
1579
 func nickHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
1575
 func nickHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
1580
-	if client.Registered() {
1576
+	if client.registered {
1581
 		performNickChange(server, client, client, msg.Params[0], rb)
1577
 		performNickChange(server, client, client, msg.Params[0], rb)
1582
 	} else {
1578
 	} else {
1583
 		client.preregNick = msg.Params[0]
1579
 		client.preregNick = msg.Params[0]
1758
 
1754
 
1759
 // PASS <password>
1755
 // PASS <password>
1760
 func passHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
1756
 func passHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
1761
-	if client.Registered() {
1757
+	if client.registered {
1762
 		rb.Add(nil, server.name, ERR_ALREADYREGISTRED, client.nick, client.t("You may not reregister"))
1758
 		rb.Add(nil, server.name, ERR_ALREADYREGISTRED, client.nick, client.t("You may not reregister"))
1763
 		return false
1759
 		return false
1764
 	}
1760
 	}
1766
 	// if no password exists, skip checking
1762
 	// if no password exists, skip checking
1767
 	serverPassword := server.Password()
1763
 	serverPassword := server.Password()
1768
 	if serverPassword == nil {
1764
 	if serverPassword == nil {
1769
-		client.SetAuthorized(true)
1770
 		return false
1765
 		return false
1771
 	}
1766
 	}
1772
 
1767
 
1778
 		return true
1773
 		return true
1779
 	}
1774
 	}
1780
 
1775
 
1781
-	client.SetAuthorized(true)
1776
+	client.sentPassCommand = true
1782
 	return false
1777
 	return false
1783
 }
1778
 }
1784
 
1779
 
1986
 	oldnick := msg.Params[0]
1981
 	oldnick := msg.Params[0]
1987
 	token := msg.Params[1]
1982
 	token := msg.Params[1]
1988
 
1983
 
1989
-	if client.Registered() {
1984
+	if client.registered {
1990
 		rb.Add(nil, server.name, ERR_CANNOT_RESUME, oldnick, client.t("Cannot resume connection, connection registration has already been completed"))
1985
 		rb.Add(nil, server.name, ERR_CANNOT_RESUME, oldnick, client.t("Cannot resume connection, connection registration has already been completed"))
1991
 		return false
1986
 		return false
1992
 	}
1987
 	}
2188
 
2183
 
2189
 // USER <username> * 0 <realname>
2184
 // USER <username> * 0 <realname>
2190
 func userHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
2185
 func userHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
2191
-	if client.Registered() {
2186
+	if client.registered {
2192
 		rb.Add(nil, server.name, ERR_ALREADYREGISTRED, client.nick, client.t("You may not reregister"))
2187
 		rb.Add(nil, server.name, ERR_ALREADYREGISTRED, client.nick, client.t("You may not reregister"))
2193
 		return false
2188
 		return false
2194
 	}
2189
 	}
2255
 // WEBIRC <password> <gateway> <hostname> <ip> [:flag1 flag2=x flag3]
2250
 // WEBIRC <password> <gateway> <hostname> <ip> [:flag1 flag2=x flag3]
2256
 func webircHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
2251
 func webircHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
2257
 	// only allow unregistered clients to use this command
2252
 	// only allow unregistered clients to use this command
2258
-	if client.Registered() || client.proxiedIP != nil {
2253
+	if client.registered || client.proxiedIP != nil {
2259
 		return false
2254
 		return false
2260
 	}
2255
 	}
2261
 
2256
 
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 Zobrazit soubor

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

+ 37
- 16
irc/nickserv.go Zobrazit soubor

5
 
5
 
6
 import (
6
 import (
7
 	"fmt"
7
 	"fmt"
8
-	"strings"
9
 
8
 
10
 	"github.com/goshuirc/irc-go/ircfmt"
9
 	"github.com/goshuirc/irc-go/ircfmt"
11
 )
10
 )
123
 			enabled:   servCmdRequiresAccreg,
122
 			enabled:   servCmdRequiresAccreg,
124
 			minParams: 1,
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
 		"unregister": {
137
 		"unregister": {
127
 			handler: nsUnregisterHandler,
138
 			handler: nsUnregisterHandler,
128
 			help: `Syntax: $bUNREGISTER <username> [code]$b
139
 			help: `Syntax: $bUNREGISTER <username> [code]$b
311
 
322
 
312
 func nsRegisterHandler(server *Server, client *Client, command string, params []string, rb *ResponseBuffer) {
323
 func nsRegisterHandler(server *Server, client *Client, command string, params []string, rb *ResponseBuffer) {
313
 	// get params
324
 	// get params
314
-	username, email := params[0], params[1]
325
+	account, email := params[0], params[1]
315
 	var passphrase string
326
 	var passphrase string
316
 	if len(params) > 2 {
327
 	if len(params) > 2 {
317
 		passphrase = params[2]
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
 	certfp := client.certfp
331
 	certfp := client.certfp
331
 	if passphrase == "" && certfp == "" {
332
 	if passphrase == "" && certfp == "" {
332
 		nsNotice(rb, client.t("You need to either supply a passphrase or be connected via TLS with a client cert"))
333
 		nsNotice(rb, client.t("You need to either supply a passphrase or be connected via TLS with a client cert"))
359
 		}
360
 		}
360
 	}
361
 	}
361
 
362
 
362
-	// get and sanitise account name
363
-	account := strings.TrimSpace(username)
364
-
365
 	err := server.accounts.Register(client, account, callbackNamespace, callbackValue, passphrase, client.certfp)
363
 	err := server.accounts.Register(client, account, callbackNamespace, callbackValue, passphrase, client.certfp)
366
 	if err == nil {
364
 	if err == nil {
367
 		if callbackNamespace == "*" {
365
 		if callbackNamespace == "*" {
381
 		errMsg := client.t("Could not register")
379
 		errMsg := client.t("Could not register")
382
 		if err == errCertfpAlreadyExists {
380
 		if err == errCertfpAlreadyExists {
383
 			errMsg = client.t("An account already exists for your certificate fingerprint")
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
 			errMsg = client.t("Account already exists")
383
 			errMsg = client.t("Account already exists")
386
 		} else if err == errAccountBadPassphrase {
384
 		} else if err == errAccountBadPassphrase {
387
 			errMsg = client.t("Passphrase contains forbidden characters or is otherwise invalid")
385
 			errMsg = client.t("Passphrase contains forbidden characters or is otherwise invalid")
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
 func nsUnregisterHandler(server *Server, client *Client, command string, params []string, rb *ResponseBuffer) {
415
 func nsUnregisterHandler(server *Server, client *Client, command string, params []string, rb *ResponseBuffer) {
395
 	username := params[0]
416
 	username := params[0]
396
 	var verificationCode string
417
 	var verificationCode string

+ 4
- 3
irc/server.go Zobrazit soubor

381
 //
381
 //
382
 
382
 
383
 func (server *Server) tryRegister(c *Client) {
383
 func (server *Server) tryRegister(c *Client) {
384
-	if c.Registered() {
384
+	if c.registered {
385
 		return
385
 		return
386
 	}
386
 	}
387
 
387
 
389
 		return
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
 	// before completing the other registration commands
393
 	// before completing the other registration commands
394
-	if !c.Authorized() {
394
+	config := server.Config()
395
+	if !c.isAuthorized(config) {
395
 		c.Quit(c.t("Bad password"))
396
 		c.Quit(c.t("Bad password"))
396
 		c.destroy(false)
397
 		c.destroy(false)
397
 		return
398
 		return

+ 41
- 25
irc/utils/net.go Zobrazit soubor

11
 
11
 
12
 var (
12
 var (
13
 	// subnet mask for an ipv6 /128:
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
 // AddrIsLocal returns whether the address is from a trusted local connection (loopback or unix).
18
 // AddrIsLocal returns whether the address is from a trusted local connection (loopback or unix).
37
 func AddrIsLocal(addr net.Addr) bool {
19
 func AddrIsLocal(addr net.Addr) bool {
38
 	if tcpaddr, ok := addr.(*net.TCPAddr); ok {
20
 	if tcpaddr, ok := addr.(*net.TCPAddr); ok {
39
 		return tcpaddr.IP.IsLoopback()
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
 func AddrToIP(addr net.Addr) net.IP {
27
 func AddrToIP(addr net.Addr) net.IP {
47
 	if tcpaddr, ok := addr.(*net.TCPAddr); ok {
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
 // AddrIsUnix returns whether the address is a unix domain socket.
37
 // AddrIsUnix returns whether the address is a unix domain socket.
100
 	return true
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
 // NormalizeIPToNet represents an address (v4 or v6) as the v6 /128 CIDR
97
 // NormalizeIPToNet represents an address (v4 or v6) as the v6 /128 CIDR
104
 // containing only it.
98
 // containing only it.
105
 func NormalizeIPToNet(addr net.IP) (network net.IPNet) {
99
 func NormalizeIPToNet(addr net.IP) (network net.IPNet) {
156
 	}
150
 	}
157
 	return NormalizeIPToNet(ip), nil
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 Zobrazit soubor

67
     # if this is true, the motd is escaped using formatting codes like $c, $b, and $i
67
     # if this is true, the motd is escaped using formatting codes like $c, $b, and $i
68
     motd-formatting: true
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
     # you should also add these addresses to the connection limits and throttling exemption lists
72
     # you should also add these addresses to the connection limits and throttling exemption lists
73
     proxy-allowed-from:
73
     proxy-allowed-from:
74
         # - localhost
74
         # - localhost
85
             # password the gateway uses to connect, made with  oragono genpasswd
85
             # password the gateway uses to connect, made with  oragono genpasswd
86
             password: "$2a$04$sLEFDpIOyUp55e6gTMKbOeroT6tMXTjPFvA0eGvwvImVR9pkwv7ee"
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
             # you should also add these addresses to the connection limits and throttling exemption lists
89
             # you should also add these addresses to the connection limits and throttling exemption lists
90
             hosts:
90
             hosts:
91
                 # - localhost
91
                 # - localhost
117
 
117
 
118
         # IPs/networks which are exempted from connection limits
118
         # IPs/networks which are exempted from connection limits
119
         exempted:
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
     # automated connection throttling
124
     # automated connection throttling
125
     connection-throttling:
125
     connection-throttling:
145
 
145
 
146
         # IPs/networks which are exempted from connection limits
146
         # IPs/networks which are exempted from connection limits
147
         exempted:
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
 # account options
152
 # account options
153
 accounts:
153
 accounts:
198
     # PASS as well, so it can be configured to authenticate with SASL only.
198
     # PASS as well, so it can be configured to authenticate with SASL only.
199
     skip-server-password: false
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
     # nick-reservation controls how, and whether, nicknames are linked to accounts
210
     # nick-reservation controls how, and whether, nicknames are linked to accounts
202
     nick-reservation:
211
     nick-reservation:
203
         # is there any enforcement of reserved nicknames?
212
         # is there any enforcement of reserved nicknames?

Načítá se…
Zrušit
Uložit