Browse Source

fix #1443

Improve auditability of sensitive operator actions
tags/v2.5.0-rc1
Shivaram Lingamneni 3 years ago
parent
commit
64bc363cf1
4 changed files with 40 additions and 13 deletions
  1. 13
    5
      irc/chanserv.go
  2. 4
    0
      irc/config.go
  3. 15
    4
      irc/handlers.go
  4. 8
    4
      irc/nickserv.go

+ 13
- 5
irc/chanserv.go View File

@@ -502,10 +502,13 @@ func csTransferHandler(service *ircService, server *Server, client *Client, comm
502 502
 	chname = regInfo.Name
503 503
 	account := client.Account()
504 504
 	isFounder := account != "" && account == regInfo.Founder
505
-	hasPrivs := client.HasRoleCapabs("chanreg")
506
-	if !(isFounder || hasPrivs) {
507
-		service.Notice(rb, client.t("Insufficient privileges"))
508
-		return
505
+	var oper *Oper
506
+	if !isFounder {
507
+		oper = client.Oper()
508
+		if !oper.HasRoleCapab("chanreg") {
509
+			service.Notice(rb, client.t("Insufficient privileges"))
510
+			return
511
+		}
509 512
 	}
510 513
 	target := params[1]
511 514
 	targetAccount, err := server.accounts.LoadAccount(params[1])
@@ -522,7 +525,12 @@ func csTransferHandler(service *ircService, server *Server, client *Client, comm
522 525
 			return
523 526
 		}
524 527
 	}
525
-	status, err := channel.Transfer(client, target, hasPrivs)
528
+	if !isFounder {
529
+		message := fmt.Sprintf("Operator %s ran CS TRANSFER on %s to account %s", oper.Name, chname, target)
530
+		server.snomasks.Send(sno.LocalOpers, message)
531
+		server.logger.Info("opers", message)
532
+	}
533
+	status, err := channel.Transfer(client, target, oper != nil)
526 534
 	if err == nil {
527 535
 		switch status {
528 536
 		case channelTransferComplete:

+ 4
- 0
irc/config.go View File

@@ -733,6 +733,10 @@ type Oper struct {
733 733
 	Modes     []modes.ModeChange
734 734
 }
735 735
 
736
+func (oper *Oper) HasRoleCapab(capab string) bool {
737
+	return oper != nil && oper.Class.Capabilities.Has(capab)
738
+}
739
+
736 740
 // Operators returns a map of operator configs from the given OperClass and config.
737 741
 func (conf *Config) Operators(oc map[string]*OperClass) (map[string]*Oper, error) {
738 742
 	operators := make(map[string]*Oper)

+ 15
- 4
irc/handlers.go View File

@@ -826,7 +826,7 @@ func formatBanForListing(client *Client, key string, info IPBanInfo) string {
826 826
 func dlineHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
827 827
 	// check oper permissions
828 828
 	oper := client.Oper()
829
-	if oper == nil || !oper.Class.Capabilities.Has("ban") {
829
+	if !oper.HasRoleCapab("ban") {
830 830
 		rb.Add(nil, server.name, ERR_NOPRIVS, client.nick, msg.Command, client.t("Insufficient oper privs"))
831 831
 		return false
832 832
 	}
@@ -1273,6 +1273,10 @@ func sajoinHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Re
1273 1273
 		}
1274 1274
 	}
1275 1275
 
1276
+	message := fmt.Sprintf("Operator %s ran SAJOIN %s", client.Oper().Name, strings.Join(msg.Params, " "))
1277
+	server.snomasks.Send(sno.LocalOpers, message)
1278
+	server.logger.Info("opers", message)
1279
+
1276 1280
 	channels := strings.Split(channelString, ",")
1277 1281
 	for _, chname := range channels {
1278 1282
 		err, _ := server.channels.Join(target, chname, "", true, rb)
@@ -1364,7 +1368,7 @@ func klineHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Res
1364 1368
 	details := client.Details()
1365 1369
 	// check oper permissions
1366 1370
 	oper := client.Oper()
1367
-	if oper == nil || !oper.Class.Capabilities.Has("ban") {
1371
+	if !oper.HasRoleCapab("ban") {
1368 1372
 		rb.Add(nil, server.name, ERR_NOPRIVS, details.nick, msg.Command, client.t("Insufficient oper privs"))
1369 1373
 		return false
1370 1374
 	}
@@ -1737,6 +1741,12 @@ func umodeHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Res
1737 1741
 		return false
1738 1742
 	}
1739 1743
 
1744
+	if msg.Command == "SAMODE" {
1745
+		message := fmt.Sprintf("Operator %s ran SAMODE %s", client.Oper().Name, strings.Join(msg.Params, " "))
1746
+		server.snomasks.Send(sno.LocalOpers, message)
1747
+		server.logger.Info("opers", message)
1748
+	}
1749
+
1740 1750
 	// applied mode changes
1741 1751
 	applied := make(modes.ModeChanges, 0)
1742 1752
 
@@ -2307,6 +2317,7 @@ func applyOper(client *Client, oper *Oper, rb *ResponseBuffer) {
2307 2317
 		copy(modeChanges[1:], oper.Modes)
2308 2318
 		applied := ApplyUserModeChanges(client, modeChanges, true, oper)
2309 2319
 
2320
+		client.server.logger.Info("opers", details.nick, "opered up as", oper.Name)
2310 2321
 		client.server.snomasks.Send(sno.LocalOpers, fmt.Sprintf(ircfmt.Unescape("Client opered up $c[grey][$r%s$c[grey], $r%s$c[grey]]"), newDetails.nickMask, oper.Name))
2311 2322
 
2312 2323
 		rb.Broadcast(nil, client.server.name, RPL_YOUREOPER, details.nick, client.t("You are now an IRC operator"))
@@ -2814,7 +2825,7 @@ func topicHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Res
2814 2825
 func unDLineHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
2815 2826
 	// check oper permissions
2816 2827
 	oper := client.Oper()
2817
-	if oper == nil || !oper.Class.Capabilities.Has("ban") {
2828
+	if !oper.HasRoleCapab("ban") {
2818 2829
 		rb.Add(nil, server.name, ERR_NOPRIVS, client.nick, msg.Command, client.t("Insufficient oper privs"))
2819 2830
 		return false
2820 2831
 	}
@@ -2853,7 +2864,7 @@ func unKLineHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *R
2853 2864
 	details := client.Details()
2854 2865
 	// check oper permissions
2855 2866
 	oper := client.Oper()
2856
-	if oper == nil || !oper.Class.Capabilities.Has("ban") {
2867
+	if !oper.HasRoleCapab("ban") {
2857 2868
 		rb.Add(nil, server.name, ERR_NOPRIVS, details.nick, msg.Command, client.t("Insufficient oper privs"))
2858 2869
 		return false
2859 2870
 	}

+ 8
- 4
irc/nickserv.go View File

@@ -995,17 +995,21 @@ func nsPasswdHandler(service *ircService, server *Server, client *Client, comman
995 995
 	var newPassword string
996 996
 	var errorMessage string
997 997
 
998
-	hasPrivs := client.HasRoleCapabs("accreg")
998
+	var oper *Oper
999 999
 
1000 1000
 	switch len(params) {
1001 1001
 	case 2:
1002
-		if !hasPrivs {
1002
+		oper = client.Oper()
1003
+		if !oper.HasRoleCapab("accreg") {
1003 1004
 			errorMessage = `Insufficient privileges`
1004 1005
 		} else {
1005 1006
 			target, newPassword = params[0], params[1]
1006 1007
 			if newPassword == "*" {
1007 1008
 				newPassword = ""
1008 1009
 			}
1010
+			message := fmt.Sprintf("Operator %s ran NS PASSWD for account %s", oper.Name, target)
1011
+			server.snomasks.Send(sno.LocalOpers, message)
1012
+			server.logger.Info("opers", message)
1009 1013
 		}
1010 1014
 	case 3:
1011 1015
 		target = client.Account()
@@ -1041,7 +1045,7 @@ func nsPasswdHandler(service *ircService, server *Server, client *Client, comman
1041 1045
 		return
1042 1046
 	}
1043 1047
 
1044
-	err := server.accounts.setPassword(target, newPassword, hasPrivs)
1048
+	err := server.accounts.setPassword(target, newPassword, oper != nil)
1045 1049
 	switch err {
1046 1050
 	case nil:
1047 1051
 		service.Notice(rb, client.t("Password changed"))
@@ -1144,7 +1148,7 @@ func nsClientsLogoutHandler(service *ircService, server *Server, client *Client,
1144 1148
 		// User must have "kill" privileges to logout other user sessions.
1145 1149
 		if target != client {
1146 1150
 			oper := client.Oper()
1147
-			if oper == nil || !oper.Class.Capabilities.Has("kill") {
1151
+			if oper.HasRoleCapab("kill") {
1148 1152
 				service.Notice(rb, client.t("Insufficient oper privs"))
1149 1153
 				return
1150 1154
 			}

Loading…
Cancel
Save