Improve auditability of sensitive operator actions
This commit is contained in:
Shivaram Lingamneni 2021-01-15 09:26:34 -05:00
parent e195854851
commit 64bc363cf1
4 changed files with 40 additions and 13 deletions

View File

@ -502,11 +502,14 @@ func csTransferHandler(service *ircService, server *Server, client *Client, comm
chname = regInfo.Name chname = regInfo.Name
account := client.Account() account := client.Account()
isFounder := account != "" && account == regInfo.Founder isFounder := account != "" && account == regInfo.Founder
hasPrivs := client.HasRoleCapabs("chanreg") var oper *Oper
if !(isFounder || hasPrivs) { if !isFounder {
oper = client.Oper()
if !oper.HasRoleCapab("chanreg") {
service.Notice(rb, client.t("Insufficient privileges")) service.Notice(rb, client.t("Insufficient privileges"))
return return
} }
}
target := params[1] target := params[1]
targetAccount, err := server.accounts.LoadAccount(params[1]) targetAccount, err := server.accounts.LoadAccount(params[1])
if err != nil { if err != nil {
@ -522,7 +525,12 @@ func csTransferHandler(service *ircService, server *Server, client *Client, comm
return return
} }
} }
status, err := channel.Transfer(client, target, hasPrivs) if !isFounder {
message := fmt.Sprintf("Operator %s ran CS TRANSFER on %s to account %s", oper.Name, chname, target)
server.snomasks.Send(sno.LocalOpers, message)
server.logger.Info("opers", message)
}
status, err := channel.Transfer(client, target, oper != nil)
if err == nil { if err == nil {
switch status { switch status {
case channelTransferComplete: case channelTransferComplete:

View File

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

View File

@ -826,7 +826,7 @@ func formatBanForListing(client *Client, key string, info IPBanInfo) string {
func dlineHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool { func dlineHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
// check oper permissions // check oper permissions
oper := client.Oper() oper := client.Oper()
if oper == nil || !oper.Class.Capabilities.Has("ban") { if !oper.HasRoleCapab("ban") {
rb.Add(nil, server.name, ERR_NOPRIVS, client.nick, msg.Command, client.t("Insufficient oper privs")) rb.Add(nil, server.name, ERR_NOPRIVS, client.nick, msg.Command, client.t("Insufficient oper privs"))
return false return false
} }
@ -1273,6 +1273,10 @@ func sajoinHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Re
} }
} }
message := fmt.Sprintf("Operator %s ran SAJOIN %s", client.Oper().Name, strings.Join(msg.Params, " "))
server.snomasks.Send(sno.LocalOpers, message)
server.logger.Info("opers", message)
channels := strings.Split(channelString, ",") channels := strings.Split(channelString, ",")
for _, chname := range channels { for _, chname := range channels {
err, _ := server.channels.Join(target, chname, "", true, rb) err, _ := server.channels.Join(target, chname, "", true, rb)
@ -1364,7 +1368,7 @@ func klineHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Res
details := client.Details() details := client.Details()
// check oper permissions // check oper permissions
oper := client.Oper() oper := client.Oper()
if oper == nil || !oper.Class.Capabilities.Has("ban") { if !oper.HasRoleCapab("ban") {
rb.Add(nil, server.name, ERR_NOPRIVS, details.nick, msg.Command, client.t("Insufficient oper privs")) rb.Add(nil, server.name, ERR_NOPRIVS, details.nick, msg.Command, client.t("Insufficient oper privs"))
return false return false
} }
@ -1737,6 +1741,12 @@ func umodeHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Res
return false return false
} }
if msg.Command == "SAMODE" {
message := fmt.Sprintf("Operator %s ran SAMODE %s", client.Oper().Name, strings.Join(msg.Params, " "))
server.snomasks.Send(sno.LocalOpers, message)
server.logger.Info("opers", message)
}
// applied mode changes // applied mode changes
applied := make(modes.ModeChanges, 0) applied := make(modes.ModeChanges, 0)
@ -2307,6 +2317,7 @@ func applyOper(client *Client, oper *Oper, rb *ResponseBuffer) {
copy(modeChanges[1:], oper.Modes) copy(modeChanges[1:], oper.Modes)
applied := ApplyUserModeChanges(client, modeChanges, true, oper) applied := ApplyUserModeChanges(client, modeChanges, true, oper)
client.server.logger.Info("opers", details.nick, "opered up as", oper.Name)
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)) 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))
rb.Broadcast(nil, client.server.name, RPL_YOUREOPER, details.nick, client.t("You are now an IRC operator")) 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
func unDLineHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool { func unDLineHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
// check oper permissions // check oper permissions
oper := client.Oper() oper := client.Oper()
if oper == nil || !oper.Class.Capabilities.Has("ban") { if !oper.HasRoleCapab("ban") {
rb.Add(nil, server.name, ERR_NOPRIVS, client.nick, msg.Command, client.t("Insufficient oper privs")) rb.Add(nil, server.name, ERR_NOPRIVS, client.nick, msg.Command, client.t("Insufficient oper privs"))
return false return false
} }
@ -2853,7 +2864,7 @@ func unKLineHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *R
details := client.Details() details := client.Details()
// check oper permissions // check oper permissions
oper := client.Oper() oper := client.Oper()
if oper == nil || !oper.Class.Capabilities.Has("ban") { if !oper.HasRoleCapab("ban") {
rb.Add(nil, server.name, ERR_NOPRIVS, details.nick, msg.Command, client.t("Insufficient oper privs")) rb.Add(nil, server.name, ERR_NOPRIVS, details.nick, msg.Command, client.t("Insufficient oper privs"))
return false return false
} }

View File

@ -995,17 +995,21 @@ func nsPasswdHandler(service *ircService, server *Server, client *Client, comman
var newPassword string var newPassword string
var errorMessage string var errorMessage string
hasPrivs := client.HasRoleCapabs("accreg") var oper *Oper
switch len(params) { switch len(params) {
case 2: case 2:
if !hasPrivs { oper = client.Oper()
if !oper.HasRoleCapab("accreg") {
errorMessage = `Insufficient privileges` errorMessage = `Insufficient privileges`
} else { } else {
target, newPassword = params[0], params[1] target, newPassword = params[0], params[1]
if newPassword == "*" { if newPassword == "*" {
newPassword = "" newPassword = ""
} }
message := fmt.Sprintf("Operator %s ran NS PASSWD for account %s", oper.Name, target)
server.snomasks.Send(sno.LocalOpers, message)
server.logger.Info("opers", message)
} }
case 3: case 3:
target = client.Account() target = client.Account()
@ -1041,7 +1045,7 @@ func nsPasswdHandler(service *ircService, server *Server, client *Client, comman
return return
} }
err := server.accounts.setPassword(target, newPassword, hasPrivs) err := server.accounts.setPassword(target, newPassword, oper != nil)
switch err { switch err {
case nil: case nil:
service.Notice(rb, client.t("Password changed")) service.Notice(rb, client.t("Password changed"))
@ -1144,7 +1148,7 @@ func nsClientsLogoutHandler(service *ircService, server *Server, client *Client,
// User must have "kill" privileges to logout other user sessions. // User must have "kill" privileges to logout other user sessions.
if target != client { if target != client {
oper := client.Oper() oper := client.Oper()
if oper == nil || !oper.Class.Capabilities.Has("kill") { if oper.HasRoleCapab("kill") {
service.Notice(rb, client.t("Insufficient oper privs")) service.Notice(rb, client.t("Insufficient oper privs"))
return return
} }