*Very experimental*/under-dev release of new fully asynchronous multi-prompter.

New Dbus method "RequestPromptAsync" to handle "return-less" prompter invocations in fw-prompt.
Proper GUI locking in fw-prompt eliminates old race/crash conditions.
New DBus method "GetPendingRequests" in SGFW allows prompter to retrieve pending connections.
Policies now maintain rulesPending list of unapplied asynchronously submitted FW rules from the prompter.
Fixed reentrance/crash bug in UID and GID to name lookups.
shw_dev
Stephen Watt 7 years ago
parent 2f5e10d53d
commit 2eac4c7dc5

@ -6,11 +6,23 @@ import (
"log" "log"
) )
type dbusObject struct {
dbus.BusObject
}
type dbusServer struct { type dbusServer struct {
conn *dbus.Conn conn *dbus.Conn
run bool run bool
} }
func newDbusObjectAdd() (*dbusObject, error) {
conn, err := dbus.SystemBus()
if err != nil {
return nil, err
}
return &dbusObject{conn.Object("com.subgraph.Firewall", "/com/subgraph/Firewall")}, nil
}
func newDbusServer() (*dbusServer, error) { func newDbusServer() (*dbusServer, error) {
conn, err := dbus.SystemBus() conn, err := dbus.SystemBus()
@ -54,6 +66,13 @@ func (ds *dbusServer) RequestPrompt(guid, application, icon, path, address strin
return int32(decision.Scope), decision.Rule, nil return int32(decision.Scope), decision.Rule, nil
} }
func (ds *dbusServer) RequestPromptAsync(guid, application, icon, path, address string, port int32, ip, origin, proto string, uid, gid int32, username, groupname string, pid int32, sandbox string,
is_socks bool, optstring string, expanded, expert bool, action int32) (bool, *dbus.Error) {
log.Printf("ASYNC request prompt: guid = %s, app = %s, icon = %s, path = %s, address = %s / ip = %s, is_socks = %v, action = %v\n", guid, application, icon, path, address, ip, is_socks, action)
addRequestAsync(nil, guid, path, icon, proto, int(pid), ip, address, int(port), int(uid), int(gid), origin, is_socks, optstring, sandbox)
return true, nil
}
func (ds *dbusServer) RemovePrompt(guid string) *dbus.Error { func (ds *dbusServer) RemovePrompt(guid string) *dbus.Error {
log.Printf("++++++++ Cancelling prompt: %s\n", guid) log.Printf("++++++++ Cancelling prompt: %s\n", guid)
removeRequest(nil, guid) removeRequest(nil, guid)

@ -53,6 +53,7 @@ type ruleColumns struct {
Scope int Scope int
} }
var dbuso *dbusObject
var userPrefs fpPreferences var userPrefs fpPreferences
var mainWin *gtk.Window var mainWin *gtk.Window
var Notebook *gtk.Notebook var Notebook *gtk.Notebook
@ -327,6 +328,7 @@ func createListStore(general bool) *gtk.ListStore {
func removeRequest(listStore *gtk.ListStore, guid string) { func removeRequest(listStore *gtk.ListStore, guid string) {
removed := false removed := false
globalPromptLock.Lock() globalPromptLock.Lock()
defer globalPromptLock.Unlock()
/* XXX: This is horrible. Figure out how to do this properly. */ /* XXX: This is horrible. Figure out how to do this properly. */
for ridx := 0; ridx < 2000; ridx++ { for ridx := 0; ridx < 2000; ridx++ {
@ -342,8 +344,6 @@ func removeRequest(listStore *gtk.ListStore, guid string) {
} }
globalPromptLock.Unlock()
if !removed { if !removed {
log.Printf("Unexpected condition: SGFW requested prompt removal for non-existent GUID %v\n", guid) log.Printf("Unexpected condition: SGFW requested prompt removal for non-existent GUID %v\n", guid)
} }
@ -354,6 +354,7 @@ func addRequestInc(listStore *gtk.ListStore, guid, path, icon, proto string, pid
duplicated := false duplicated := false
globalPromptLock.Lock() globalPromptLock.Lock()
defer globalPromptLock.Unlock()
for ridx := 0; ridx < 2000; ridx++ { for ridx := 0; ridx < 2000; ridx++ {
@ -368,7 +369,7 @@ func addRequestInc(listStore *gtk.ListStore, guid, path, icon, proto string, pid
err := globalLS.SetValue(iter, 0, rule.nrefs) err := globalLS.SetValue(iter, 0, rule.nrefs)
if err != nil { if err != nil {
log.Print("Error creating duplicate firewall prompt entry:", err) log.Println("Error creating duplicate firewall prompt entry:", err)
break break
} }
@ -379,19 +380,106 @@ func addRequestInc(listStore *gtk.ListStore, guid, path, icon, proto string, pid
} }
globalPromptLock.Unlock()
return duplicated return duplicated
} }
func addRequest(listStore *gtk.ListStore, guid, path, icon, proto string, pid int, ipaddr, hostname string, port, uid, gid int, origin string, is_socks bool, optstring string, sandbox string) *decisionWaiter { func addRequestAsync(listStore *gtk.ListStore, guid, path, icon, proto string, pid int, ipaddr, hostname string, port, uid, gid int, origin string, is_socks bool, optstring string, sandbox string) bool {
if listStore == nil { if listStore == nil {
listStore = globalLS listStore = globalLS
waitTimes := []int{1, 2, 5, 10} waitTimes := []int{1, 2, 5, 10}
if listStore == nil { if listStore == nil {
log.Print("SGFW prompter was not ready to receive firewall request... waiting") log.Println("SGFW prompter was not ready to receive firewall request... waiting")
for _, wtime := range waitTimes {
time.Sleep(time.Duration(wtime) * time.Second)
listStore = globalLS
if listStore != nil {
break
}
log.Println("SGFW prompter is still waiting...")
}
}
}
if listStore == nil {
log.Fatal("SGFW prompter GUI failed to load for unknown reasons")
}
if addRequestInc(listStore, guid, path, icon, proto, pid, ipaddr, hostname, port, uid, gid, origin, is_socks, optstring, sandbox) {
fmt.Println("REQUEST WAS DUPLICATE")
return false
} else {
fmt.Println("NOT DUPLICATE")
}
globalPromptLock.Lock()
iter := listStore.Append()
if is_socks {
if (optstring != "") && (strings.Index(optstring, "SOCKS") == -1) {
optstring = "SOCKS5 / " + optstring
} else if optstring == "" {
optstring = "SOCKS5"
}
}
colVals := make([]interface{}, 14)
colVals[0] = 1
colVals[1] = guid
colVals[2] = path
colVals[3] = icon
colVals[4] = proto
colVals[5] = pid
if ipaddr == "" {
colVals[6] = "---"
} else {
colVals[6] = ipaddr
}
colVals[7] = hostname
colVals[8] = port
colVals[9] = uid
colVals[10] = gid
colVals[11] = origin
colVals[12] = 0
if is_socks {
colVals[12] = 1
}
colVals[13] = optstring
colNums := make([]int, len(colVals))
for n := 0; n < len(colVals); n++ {
colNums[n] = n
}
err := listStore.Set(iter, colNums, colVals)
globalPromptLock.Unlock()
if err != nil {
log.Fatal("Unable to add row:", err)
}
toggleHover()
return true
} }
func addRequest(listStore *gtk.ListStore, guid, path, icon, proto string, pid int, ipaddr, hostname string, port, uid, gid int, origin string, is_socks bool, optstring string, sandbox string) *decisionWaiter {
if listStore == nil {
listStore = globalLS
waitTimes := []int{1, 2, 5, 10}
if listStore == nil {
log.Println("SGFW prompter was not ready to receive firewall request... waiting")
for _, wtime := range waitTimes { for _, wtime := range waitTimes {
time.Sleep(time.Duration(wtime) * time.Second) time.Sleep(time.Duration(wtime) * time.Second)
listStore = globalLS listStore = globalLS
@ -400,7 +488,9 @@ func addRequest(listStore *gtk.ListStore, guid, path, icon, proto string, pid in
break break
} }
log.Print("SGFW prompter is still waiting...") log.Println("SGFW prompter is still waiting...")
}
} }
} }
@ -565,13 +655,26 @@ func lsGetInt(ls *gtk.ListStore, iter *gtk.TreeIter, idx int) (int, error) {
return ival.(int), nil return ival.(int), nil
} }
func makeDecision(idx int, rule string, scope int) { func makeDecision(idx int, rule string, scope int) error {
var dres bool
call := dbuso.Call("AddRuleAsync", 0, uint32(scope), rule, "*")
err := call.Store(&dres)
if err != nil {
log.Println("Error notifying SGFW of asynchronous rule addition:", err)
return err
}
fmt.Println("makeDecision remote result:", dres)
return nil
decisionWaiters[idx].Cond.L.Lock() decisionWaiters[idx].Cond.L.Lock()
decisionWaiters[idx].Rule = rule decisionWaiters[idx].Rule = rule
decisionWaiters[idx].Scope = scope decisionWaiters[idx].Scope = scope
decisionWaiters[idx].Ready = true decisionWaiters[idx].Ready = true
decisionWaiters[idx].Cond.Signal() decisionWaiters[idx].Cond.Signal()
decisionWaiters[idx].Cond.L.Unlock() decisionWaiters[idx].Cond.L.Unlock()
return nil
} }
func toggleHover() { func toggleHover() {
@ -581,7 +684,9 @@ func toggleHover() {
func toggleValidRuleState() { func toggleValidRuleState() {
ok := true ok := true
globalPromptLock.Lock() // Unfortunately, this can cause deadlock since it's a part ofi the item removal cascade
// globalPromptLock.Lock()
// defer globalPromptLock.Unlock()
if numSelections() <= 0 { if numSelections() <= 0 {
ok = false ok = false
@ -625,7 +730,6 @@ func toggleValidRuleState() {
btnApprove.SetSensitive(ok) btnApprove.SetSensitive(ok)
btnDeny.SetSensitive(ok) btnDeny.SetSensitive(ok)
btnIgnore.SetSensitive(ok) btnIgnore.SetSensitive(ok)
globalPromptLock.Unlock()
} }
func createCurrentRule() (ruleColumns, error) { func createCurrentRule() (ruleColumns, error) {
@ -710,7 +814,7 @@ func removeSelectedRule(idx int, rmdecision bool) error {
globalLS.Remove(iter) globalLS.Remove(iter)
if rmdecision { if rmdecision {
decisionWaiters = append(decisionWaiters[:idx], decisionWaiters[idx+1:]...) // decisionWaiters = append(decisionWaiters[:idx], decisionWaiters[idx+1:]...)
} }
toggleHover() toggleHover()
@ -844,6 +948,64 @@ func getSelectedRule() (ruleColumns, int, error) {
return rule, lIndex, nil return rule, lIndex, nil
} }
func addPendingPrompts(rules []string) {
for _, rule := range rules {
fields := strings.Split(rule, "|")
if len(fields) != 17 {
log.Printf("Got saved prompt message with strange data: \"%s\"", rule)
continue
}
guid := fields[0]
icon := fields[2]
path := fields[3]
address := fields[4]
port, err := strconv.Atoi(fields[5])
if err != nil {
log.Println("Error converting port in pending prompt message to integer:", err)
continue
}
ip := fields[6]
origin := fields[7]
proto := fields[8]
uid, err := strconv.Atoi(fields[9])
if err != nil {
log.Println("Error converting UID in pending prompt message to integer:", err)
continue
}
gid, err := strconv.Atoi(fields[10])
if err != nil {
log.Println("Error converting GID in pending prompt message to integer:", err)
continue
}
pid, err := strconv.Atoi(fields[13])
if err != nil {
log.Println("Error converting pid in pending prompt message to integer:", err)
continue
}
sandbox := fields[14]
is_socks, err := strconv.ParseBool(fields[15])
if err != nil {
log.Println("Error converting SOCKS flag in pending prompt message to boolean:", err)
continue
}
optstring := fields[16]
addRequestAsync(nil, guid, path, icon, proto, int(pid), ip, address, int(port), int(uid), int(gid), origin, is_socks, optstring, sandbox)
}
}
func main() { func main() {
decisionWaiters = make([]*decisionWaiter, 0) decisionWaiters = make([]*decisionWaiter, 0)
_, err := newDbusServer() _, err := newDbusServer()
@ -852,6 +1014,11 @@ func main() {
return return
} }
dbuso, err = newDbusObjectAdd()
if err != nil {
log.Fatal("Failed to connect to dbus system bus: %v", err)
}
loadPreferences() loadPreferences()
gtk.Init(nil) gtk.Init(nil)
@ -1045,17 +1212,17 @@ func main() {
tv.SetModel(listStore) tv.SetModel(listStore)
btnApprove.Connect("clicked", func() { btnApprove.Connect("clicked", func() {
// globalPromptLock.Lock() globalPromptLock.Lock()
rule, idx, err := getSelectedRule() rule, idx, err := getSelectedRule()
if err != nil { if err != nil {
// globalPromptLock.Unlock() globalPromptLock.Unlock()
promptError("Error occurred processing request: " + err.Error()) promptError("Error occurred processing request: " + err.Error())
return return
} }
rule, err = createCurrentRule() rule, err = createCurrentRule()
if err != nil { if err != nil {
// globalPromptLock.Unlock() globalPromptLock.Unlock()
promptError("Error occurred constructing new rule: " + err.Error()) promptError("Error occurred constructing new rule: " + err.Error())
return return
} }
@ -1071,7 +1238,7 @@ func main() {
fmt.Println("RULESTR = ", rulestr) fmt.Println("RULESTR = ", rulestr)
makeDecision(idx, rulestr, int(rule.Scope)) makeDecision(idx, rulestr, int(rule.Scope))
fmt.Println("Decision made.") fmt.Println("Decision made.")
// globalPromptLock.Unlock() globalPromptLock.Unlock()
err = removeSelectedRule(idx, true) err = removeSelectedRule(idx, true)
if err == nil { if err == nil {
clearEditor() clearEditor()
@ -1081,17 +1248,17 @@ func main() {
}) })
btnDeny.Connect("clicked", func() { btnDeny.Connect("clicked", func() {
// globalPromptLock.Lock() globalPromptLock.Lock()
rule, idx, err := getSelectedRule() rule, idx, err := getSelectedRule()
if err != nil { if err != nil {
// globalPromptLock.Unlock() globalPromptLock.Unlock()
promptError("Error occurred processing request: " + err.Error()) promptError("Error occurred processing request: " + err.Error())
return return
} }
rule, err = createCurrentRule() rule, err = createCurrentRule()
if err != nil { if err != nil {
// globalPromptLock.Unlock() globalPromptLock.Unlock()
promptError("Error occurred constructing new rule: " + err.Error()) promptError("Error occurred constructing new rule: " + err.Error())
return return
} }
@ -1101,7 +1268,7 @@ func main() {
fmt.Println("RULESTR = ", rulestr) fmt.Println("RULESTR = ", rulestr)
makeDecision(idx, rulestr, int(rule.Scope)) makeDecision(idx, rulestr, int(rule.Scope))
fmt.Println("Decision made.") fmt.Println("Decision made.")
// globalPromptLock.Unlock() globalPromptLock.Unlock()
err = removeSelectedRule(idx, true) err = removeSelectedRule(idx, true)
if err == nil { if err == nil {
clearEditor() clearEditor()
@ -1111,17 +1278,17 @@ func main() {
}) })
btnIgnore.Connect("clicked", func() { btnIgnore.Connect("clicked", func() {
// globalPromptLock.Lock() globalPromptLock.Lock()
_, idx, err := getSelectedRule() _, idx, err := getSelectedRule()
if err != nil { if err != nil {
// globalPromptLock.Unlock() globalPromptLock.Unlock()
promptError("Error occurred processing request: " + err.Error()) promptError("Error occurred processing request: " + err.Error())
return return
} }
makeDecision(idx, "", 0) makeDecision(idx, "", 0)
fmt.Println("Decision made.") fmt.Println("Decision made.")
// globalPromptLock.Unlock() globalPromptLock.Unlock()
err = removeSelectedRule(idx, true) err = removeSelectedRule(idx, true)
if err == nil { if err == nil {
clearEditor() clearEditor()
@ -1132,10 +1299,10 @@ func main() {
// tv.SetActivateOnSingleClick(true) // tv.SetActivateOnSingleClick(true)
tv.Connect("row-activated", func() { tv.Connect("row-activated", func() {
// globalPromptLock.Lock() globalPromptLock.Lock()
seldata, _, err := getSelectedRule() seldata, _, err := getSelectedRule()
globalPromptLock.Unlock()
if err != nil { if err != nil {
// globalPromptLock.Unlock()
promptError("Unexpected error reading selected rule: " + err.Error()) promptError("Unexpected error reading selected rule: " + err.Error())
return return
} }
@ -1182,8 +1349,6 @@ func main() {
chkUser.SetActive(false) chkUser.SetActive(false)
chkGroup.SetActive(false) chkGroup.SetActive(false)
// globalPromptLock.Unlock()
return return
}) })
@ -1206,5 +1371,16 @@ func main() {
mainWin.ShowAll() mainWin.ShowAll()
// mainWin.SetKeepAbove(true) // mainWin.SetKeepAbove(true)
var dres = []string{}
call := dbuso.Call("GetPendingRequests", 0, "*")
err = call.Store(&dres)
if err != nil {
errmsg := "Could not query running SGFW instance (maybe it's not running?): " + err.Error()
promptError(errmsg)
} else {
addPendingPrompts(dres)
}
gtk.Main() gtk.Main()
} }

@ -199,6 +199,72 @@ func (ds *dbusServer) DeleteRule(id uint32) *dbus.Error {
return nil return nil
} }
func (ds *dbusServer) GetPendingRequests(policy string) ([]string, *dbus.Error) {
log.Debug("+++ GetPendingRequests()")
ds.fw.lock.Lock()
defer ds.fw.lock.Unlock()
pending_data := make([]string, 0)
for pname := range ds.fw.policyMap {
policy := ds.fw.policyMap[pname]
pqueue := policy.pendingQueue
for _, pc := range pqueue {
addr := pc.hostname()
if addr == "" {
addr = pc.dst().String()
}
dststr := ""
if pc.dst() != nil {
dststr = pc.dst().String()
} else {
dststr = addr + " (via proxy resolver)"
}
pstr := ""
pstr += pc.getGUID() + "|"
pstr += policy.application + "|"
pstr += policy.icon + "|"
pstr += policy.path + "|"
pstr += addr + "|"
pstr += strconv.FormatUint(uint64(pc.dstPort()), 10) + "|"
pstr += dststr + "|"
pstr += pc.src().String() + "|"
pstr += pc.proto() + "|"
pstr += strconv.FormatInt(int64(pc.procInfo().UID), 10) + "|"
pstr += strconv.FormatInt(int64(pc.procInfo().GID), 10) + "|"
pstr += uidToUser(pc.procInfo().UID) + "|"
pstr += gidToGroup(pc.procInfo().GID) + "|"
pstr += strconv.FormatInt(int64(pc.procInfo().Pid), 10) + "|"
pstr += pc.sandbox() + "|"
pstr += strconv.FormatBool(pc.socks()) + "|"
pstr += pc.getOptString()
pending_data = append(pending_data, pstr)
}
}
return pending_data, nil
}
func (ds *dbusServer) AddRuleAsync(scope uint32, rule string, policy string) (bool, *dbus.Error) {
log.Debugf("AddRuleAsync %v, %v / %v\n", scope, rule, policy)
ds.fw.lock.Lock()
defer ds.fw.lock.Unlock()
prule := PendingRule{rule: rule, scope: int(scope), policy: policy}
for pname := range ds.fw.policyMap {
log.Debug("+++ Adding prule to policy")
ds.fw.policyMap[pname].rulesPending = append(ds.fw.policyMap[pname].rulesPending, prule)
}
return true, nil
}
func (ds *dbusServer) UpdateRule(rule DbusRule) *dbus.Error { func (ds *dbusServer) UpdateRule(rule DbusRule) *dbus.Error {
log.Debugf("UpdateRule %v", rule) log.Debugf("UpdateRule %v", rule)
ds.fw.lock.Lock() ds.fw.lock.Lock()

@ -6,8 +6,6 @@ import (
"strings" "strings"
"sync" "sync"
// "encoding/binary"
// nfnetlink "github.com/subgraph/go-nfnetlink" // nfnetlink "github.com/subgraph/go-nfnetlink"
"github.com/google/gopacket/layers" "github.com/google/gopacket/layers"
nfqueue "github.com/subgraph/go-nfnetlink/nfqueue" nfqueue "github.com/subgraph/go-nfnetlink/nfqueue"
@ -213,6 +211,12 @@ func (pp *pendingPkt) print() string {
return printPacket(pp.pkt, pp.name, pp.pinfo) return printPacket(pp.pkt, pp.name, pp.pinfo)
} }
type PendingRule struct {
rule string
scope int
policy string
}
type Policy struct { type Policy struct {
fw *Firewall fw *Firewall
path string path string
@ -223,6 +227,7 @@ type Policy struct {
pendingQueue []pendingConnection pendingQueue []pendingConnection
promptInProgress bool promptInProgress bool
lock sync.Mutex lock sync.Mutex
rulesPending []PendingRule
} }
func (fw *Firewall) PolicyForPath(path string) *Policy { func (fw *Firewall) PolicyForPath(path string) *Policy {
@ -312,21 +317,22 @@ func (p *Policy) processPacket(pkt *nfqueue.NFQPacket, pinfo *procsnitch.Info, o
func (p *Policy) processPromptResult(pc pendingConnection) { func (p *Policy) processPromptResult(pc pendingConnection) {
p.pendingQueue = append(p.pendingQueue, pc) p.pendingQueue = append(p.pendingQueue, pc)
//fmt.Println("processPromptResult(): p.promptInProgress = ", p.promptInProgress) //fmt.Println("processPromptResult(): p.promptInProgress = ", p.promptInProgress)
if DoMultiPrompt || (!DoMultiPrompt && !p.promptInProgress) { //if DoMultiPrompt || (!DoMultiPrompt && !p.promptInProgress) {
// if !p.promptInProgress {
p.promptInProgress = true p.promptInProgress = true
go p.fw.dbus.prompt(p) go p.fw.dbus.prompt(p)
} // }
} }
func (p *Policy) nextPending() (pendingConnection, bool) { func (p *Policy) nextPending() (pendingConnection, bool) {
p.lock.Lock() p.lock.Lock()
defer p.lock.Unlock() defer p.lock.Unlock()
if !DoMultiPrompt { /* if !DoMultiPrompt {
if len(p.pendingQueue) == 0 { if len(p.pendingQueue) == 0 {
return nil, true return nil, true
} }
return p.pendingQueue[0], false return p.pendingQueue[0], false
} }*/
if len(p.pendingQueue) == 0 { if len(p.pendingQueue) == 0 {
return nil, true return nil, true
@ -334,6 +340,7 @@ func (p *Policy) nextPending() (pendingConnection, bool) {
// for len(p.pendingQueue) != 0 { // for len(p.pendingQueue) != 0 {
for i := 0; i < len(p.pendingQueue); i++ { for i := 0; i < len(p.pendingQueue); i++ {
fmt.Printf("pendingQueue %v of %v: %v\n", i, len(p.pendingQueue), p.pendingQueue[i])
if !p.pendingQueue[i].getPrompting() { if !p.pendingQueue[i].getPrompting() {
return p.pendingQueue[i], false return p.pendingQueue[i], false
} }
@ -414,8 +421,6 @@ func (p *Policy) filterPending(rule *Rule) {
if prompter == nil { if prompter == nil {
fmt.Println("-------- prompter = NULL") fmt.Println("-------- prompter = NULL")
} else { } else {
fmt.Println("---------- could send prompter")
call := prompter.Call("com.subgraph.FirewallPrompt.RemovePrompt", 0, pc.getGUID()) call := prompter.Call("com.subgraph.FirewallPrompt.RemovePrompt", 0, pc.getGUID())
fmt.Println("CAAAAAAAAAAAAAAALL = ", call) fmt.Println("CAAAAAAAAAAAAAAALL = ", call)
} }

@ -13,15 +13,6 @@ import (
"github.com/subgraph/fw-daemon/proc-coroner" "github.com/subgraph/fw-daemon/proc-coroner"
) )
var DoMultiPrompt = true
const MAX_PROMPTS = 5
var outstandingPrompts = 0
var outstandingPromptChans [](chan *dbus.Call)
var promptLock = &sync.Mutex{}
var promptChanLock = &sync.Mutex{}
func newPrompter(conn *dbus.Conn) *prompter { func newPrompter(conn *dbus.Conn) *prompter {
p := new(prompter) p := new(prompter)
p.cond = sync.NewCond(&p.lock) p.cond = sync.NewCond(&p.lock)
@ -39,30 +30,6 @@ type prompter struct {
policyQueue []*Policy policyQueue []*Policy
} }
func saveChannel(ch chan *dbus.Call, add bool, do_close bool) {
promptChanLock.Lock()
if add {
outstandingPromptChans = append(outstandingPromptChans, ch)
} else {
for idx, och := range outstandingPromptChans {
if och == ch {
outstandingPromptChans = append(outstandingPromptChans[:idx], outstandingPromptChans[idx+1:]...)
break
}
}
}
if !add && do_close {
close(ch)
}
promptChanLock.Unlock()
return
}
func (p *prompter) prompt(policy *Policy) { func (p *prompter) prompt(policy *Policy) {
p.lock.Lock() p.lock.Lock()
defer p.lock.Unlock() defer p.lock.Unlock()
@ -91,7 +58,8 @@ func (p *prompter) promptLoop() {
func (p *prompter) processNextPacket() bool { func (p *prompter) processNextPacket() bool {
var pc pendingConnection = nil var pc pendingConnection = nil
if !DoMultiPrompt { if 1 == 2 {
// if !DoMultiPrompt {
pc, _ = p.nextConnection() pc, _ = p.nextConnection()
if pc == nil { if pc == nil {
return false return false
@ -118,66 +86,28 @@ func (p *prompter) processNextPacket() bool {
defer p.lock.Lock() defer p.lock.Lock()
// fmt.Println("XXX: Waiting for prompt lock go...") // fmt.Println("XXX: Waiting for prompt lock go...")
for { for {
promptLock.Lock()
if outstandingPrompts >= MAX_PROMPTS {
promptLock.Unlock()
continue
}
if pc.getPrompting() { if pc.getPrompting() {
log.Debugf("Skipping over already prompted connection") log.Debugf("Skipping over already prompted connection")
promptLock.Unlock()
continue continue
} }
break break
} }
// fmt.Println("XXX: Passed prompt lock!")
outstandingPrompts++
// fmt.Println("XXX: Incremented outstanding to ", outstandingPrompts)
promptLock.Unlock()
// if !pc.getPrompting() {
pc.setPrompting(true) pc.setPrompting(true)
go p.processConnection(pc) go p.processConnection(pc)
// }
return true return true
} }
func processReturn(pc pendingConnection) {
promptLock.Lock()
outstandingPrompts--
// fmt.Println("XXX: Return decremented outstanding to ", outstandingPrompts)
promptLock.Unlock()
pc.setPrompting(false)
}
func alertChannel(chidx int, scope int32, rule string) {
defer func() {
if r := recover(); r != nil {
log.Warning("SGFW recovered from panic while delivering out of band rule:", r)
}
}()
promptData := make([]interface{}, 3)
promptData[0] = scope
promptData[1] = rule
promptData[2] = 666
outstandingPromptChans[chidx] <- &dbus.Call{Body: promptData}
}
func (p *prompter) processConnection(pc pendingConnection) { func (p *prompter) processConnection(pc pendingConnection) {
var scope int32 var scope int32
var dres bool
var rule string var rule string
if pc.getPrompter() == nil { if pc.getPrompter() == nil {
pc.setPrompter(&dbusObjectP{p.dbusObj}) pc.setPrompter(&dbusObjectP{p.dbusObj})
} }
if DoMultiPrompt {
defer processReturn(pc)
}
addr := pc.hostname() addr := pc.hostname()
if addr == "" { if addr == "" {
addr = pc.dst().String() addr = pc.dst().String()
@ -192,10 +122,48 @@ func (p *prompter) processConnection(pc pendingConnection) {
dststr = addr + " (via proxy resolver)" dststr = addr + " (via proxy resolver)"
} }
callChan := make(chan *dbus.Call, 10) // callChan := make(chan *dbus.Call, 10)
saveChannel(callChan, true, false) // saveChannel(callChan, true, false)
fmt.Println("# outstanding prompt chans = ", len(outstandingPromptChans)) // fmt.Println("# outstanding prompt chans = ", len(outstandingPromptChans))
p.dbusObj.Go("com.subgraph.FirewallPrompt.RequestPrompt", 0, callChan,
// fmt.Println("ABOUT TO CALL ASYNC PROMPT")
call := p.dbusObj.Call("com.subgraph.FirewallPrompt.RequestPromptAsync", 0,
pc.getGUID(),
policy.application,
policy.icon,
policy.path,
addr,
int32(pc.dstPort()),
dststr,
pc.src().String(),
pc.proto(),
int32(pc.procInfo().UID),
int32(pc.procInfo().GID),
uidToUser(pc.procInfo().UID),
gidToGroup(pc.procInfo().GID),
int32(pc.procInfo().Pid),
pc.sandbox(),
pc.socks(),
pc.getOptString(),
FirewallConfig.PromptExpanded,
FirewallConfig.PromptExpert,
int32(FirewallConfig.DefaultActionID))
err := call.Store(&dres)
if err != nil {
log.Warningf("Error sending dbus async RequestPrompt message: %v", err)
policy.removePending(pc)
pc.drop()
return
}
if !dres {
fmt.Println("Unexpected: fw-prompt async RequestPrompt message returned:", dres)
}
return
/* p.dbusObj.Go("com.subgraph.FirewallPrompt.RequestPrompt", 0, callChan,
pc.getGUID(), pc.getGUID(),
policy.application, policy.application,
policy.icon, policy.icon,
@ -262,7 +230,7 @@ func (p *prompter) processConnection(pc pendingConnection) {
// ch <- &dbus.Call{Body: promptData} // ch <- &dbus.Call{Body: promptData}
} }
promptChanLock.Unlock() promptChanLock.Unlock() */
/* err := call.Store(&scope, &rule) /* err := call.Store(&scope, &rule)
if err != nil { if err != nil {
@ -341,10 +309,65 @@ func (p *prompter) nextConnection() (pendingConnection, bool) {
if pc == nil && qempty { if pc == nil && qempty {
p.removePolicy(policy) p.removePolicy(policy)
} else { } else {
// if pc == nil && !qempty {
if len(policy.rulesPending) > 0 {
fmt.Println("policy rules pending = ", len(policy.rulesPending))
prule := policy.rulesPending[0]
policy.rulesPending = append(policy.rulesPending[:0], policy.rulesPending[1:]...)
toks := strings.Split(prule.rule, "|")
sandbox := ""
if len(toks) > 2 {
sandbox = toks[2]
}
tempRule := fmt.Sprintf("%s|%s", toks[0], toks[1])
/* if pc.src() != nil && !pc.src().Equal(net.ParseIP("127.0.0.1")) && sandbox != "" {
tempRule += "||-1:-1|" + sandbox + "|" + pc.src().String()
} else {*/
tempRule += "||-1:-1|" + sandbox + "|"
// }
r, err := policy.parseRule(tempRule, false)
if err != nil {
log.Warningf("Error parsing rule string returned from dbus RequestPrompt: %v", err)
// policy.removePending(pc)
// pc.drop()
// return
} else {
fscope := FilterScope(prule.scope)
if fscope == APPLY_SESSION {
r.mode = RULE_MODE_SESSION
} else if fscope == APPLY_PROCESS {
r.mode = RULE_MODE_PROCESS
// r.pid = pc.procInfo().Pid
// pcoroner.MonitorProcess(r.pid)
}
if !policy.processNewRule(r, fscope) {
// p.lock.Lock()
// defer p.lock.Unlock()
// p.removePolicy(pc.policy())
}
if fscope == APPLY_FOREVER {
r.mode = RULE_MODE_PERMANENT
policy.fw.saveRules()
}
log.Warningf("Prompt returning rule: %v", tempRule)
dbusp.alertRule("sgfw prompt added new rule")
}
// }
if pc == nil && !qempty { if pc == nil && !qempty {
log.Errorf("FIX ME: I NEED TO SLEEP ON A WAKEABLE CONDITION PROPERLY!!") log.Errorf("FIX ME: I NEED TO SLEEP ON A WAKEABLE CONDITION PROPERLY!!")
time.Sleep(time.Millisecond * 300) time.Sleep(time.Millisecond * 300)
} }
}
return pc, qempty return pc, qempty
} }
} }
@ -353,14 +376,15 @@ func (p *prompter) nextConnection() (pendingConnection, bool) {
func (p *prompter) removePolicy(policy *Policy) { func (p *prompter) removePolicy(policy *Policy) {
var newQueue []*Policy = nil var newQueue []*Policy = nil
if DoMultiPrompt { // if DoMultiPrompt {
if len(p.policyQueue) == 0 { if len(p.policyQueue) == 0 {
log.Debugf("Skipping over zero length policy queue") log.Debugf("Skipping over zero length policy queue")
newQueue = make([]*Policy, 0, 0) newQueue = make([]*Policy, 0, 0)
} }
} // }
if !DoMultiPrompt || newQueue == nil { // if !DoMultiPrompt || newQueue == nil {
if newQueue == nil {
newQueue = make([]*Policy, 0, len(p.policyQueue)-1) newQueue = make([]*Policy, 0, len(p.policyQueue)-1)
} }
for _, pol := range p.policyQueue { for _, pol := range p.policyQueue {
@ -374,11 +398,17 @@ func (p *prompter) removePolicy(policy *Policy) {
var userMap = make(map[int]string) var userMap = make(map[int]string)
var groupMap = make(map[int]string) var groupMap = make(map[int]string)
var userMapLock = &sync.Mutex{}
var groupMapLock = &sync.Mutex{}
func lookupUser(uid int) string { func lookupUser(uid int) string {
if uid == -1 { if uid == -1 {
return "[unknown]" return "[unknown]"
} }
userMapLock.Lock()
defer userMapLock.Unlock()
u, err := user.LookupId(strconv.Itoa(uid)) u, err := user.LookupId(strconv.Itoa(uid))
if err != nil { if err != nil {
return fmt.Sprintf("%d", uid) return fmt.Sprintf("%d", uid)
@ -390,6 +420,10 @@ func lookupGroup(gid int) string {
if gid == -1 { if gid == -1 {
return "[unknown]" return "[unknown]"
} }
groupMapLock.Lock()
defer groupMapLock.Unlock()
g, err := user.LookupGroupId(strconv.Itoa(gid)) g, err := user.LookupGroupId(strconv.Itoa(gid))
if err != nil { if err != nil {
return fmt.Sprintf("%d", gid) return fmt.Sprintf("%d", gid)

Loading…
Cancel
Save