From 2eac4c7dc584fa054501312e3a35b23434a894bd Mon Sep 17 00:00:00 2001 From: Stephen Watt Date: Tue, 26 Sep 2017 23:13:18 -0400 Subject: [PATCH] *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. --- fw-prompt/dbus.go | 19 +++ fw-prompt/fw-prompt.go | 238 ++++++++++++++++++++++++++++++----- sgfw/dbus.go | 66 ++++++++++ sgfw/policy.go | 25 ++-- sgfw/prompt.go | 278 +++++++++++++++++++++++------------------ 5 files changed, 463 insertions(+), 163 deletions(-) diff --git a/fw-prompt/dbus.go b/fw-prompt/dbus.go index 1104c2e..d9ca0fe 100644 --- a/fw-prompt/dbus.go +++ b/fw-prompt/dbus.go @@ -6,11 +6,23 @@ import ( "log" ) +type dbusObject struct { + dbus.BusObject +} + type dbusServer struct { conn *dbus.Conn 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) { 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 } +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 { log.Printf("++++++++ Cancelling prompt: %s\n", guid) removeRequest(nil, guid) diff --git a/fw-prompt/fw-prompt.go b/fw-prompt/fw-prompt.go index d3bf8c1..786371d 100644 --- a/fw-prompt/fw-prompt.go +++ b/fw-prompt/fw-prompt.go @@ -53,6 +53,7 @@ type ruleColumns struct { Scope int } +var dbuso *dbusObject var userPrefs fpPreferences var mainWin *gtk.Window var Notebook *gtk.Notebook @@ -327,6 +328,7 @@ func createListStore(general bool) *gtk.ListStore { func removeRequest(listStore *gtk.ListStore, guid string) { removed := false globalPromptLock.Lock() + defer globalPromptLock.Unlock() /* XXX: This is horrible. Figure out how to do this properly. */ for ridx := 0; ridx < 2000; ridx++ { @@ -342,8 +344,6 @@ func removeRequest(listStore *gtk.ListStore, guid string) { } - globalPromptLock.Unlock() - if !removed { 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 globalPromptLock.Lock() + defer globalPromptLock.Unlock() 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) if err != nil { - log.Print("Error creating duplicate firewall prompt entry:", err) + log.Println("Error creating duplicate firewall prompt entry:", err) break } @@ -379,28 +380,117 @@ func addRequestInc(listStore *gtk.ListStore, guid, path, icon, proto string, pid } - globalPromptLock.Unlock() 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 { listStore = globalLS waitTimes := []int{1, 2, 5, 10} 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...") + } + } - for _, wtime := range waitTimes { - time.Sleep(time.Duration(wtime) * time.Second) - listStore = globalLS + } - if listStore != nil { - break + 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 { + time.Sleep(time.Duration(wtime) * time.Second) + listStore = globalLS + + if listStore != nil { + break + } + + log.Println("SGFW prompter is still waiting...") } - log.Print("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 } -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].Rule = rule decisionWaiters[idx].Scope = scope decisionWaiters[idx].Ready = true decisionWaiters[idx].Cond.Signal() decisionWaiters[idx].Cond.L.Unlock() + return nil } func toggleHover() { @@ -581,7 +684,9 @@ func toggleHover() { func toggleValidRuleState() { 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 { ok = false @@ -625,7 +730,6 @@ func toggleValidRuleState() { btnApprove.SetSensitive(ok) btnDeny.SetSensitive(ok) btnIgnore.SetSensitive(ok) - globalPromptLock.Unlock() } func createCurrentRule() (ruleColumns, error) { @@ -710,7 +814,7 @@ func removeSelectedRule(idx int, rmdecision bool) error { globalLS.Remove(iter) if rmdecision { - decisionWaiters = append(decisionWaiters[:idx], decisionWaiters[idx+1:]...) + // decisionWaiters = append(decisionWaiters[:idx], decisionWaiters[idx+1:]...) } toggleHover() @@ -844,6 +948,64 @@ func getSelectedRule() (ruleColumns, int, error) { 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() { decisionWaiters = make([]*decisionWaiter, 0) _, err := newDbusServer() @@ -852,6 +1014,11 @@ func main() { return } + dbuso, err = newDbusObjectAdd() + if err != nil { + log.Fatal("Failed to connect to dbus system bus: %v", err) + } + loadPreferences() gtk.Init(nil) @@ -1045,17 +1212,17 @@ func main() { tv.SetModel(listStore) btnApprove.Connect("clicked", func() { - // globalPromptLock.Lock() + globalPromptLock.Lock() rule, idx, err := getSelectedRule() if err != nil { - // globalPromptLock.Unlock() + globalPromptLock.Unlock() promptError("Error occurred processing request: " + err.Error()) return } rule, err = createCurrentRule() if err != nil { - // globalPromptLock.Unlock() + globalPromptLock.Unlock() promptError("Error occurred constructing new rule: " + err.Error()) return } @@ -1071,7 +1238,7 @@ func main() { fmt.Println("RULESTR = ", rulestr) makeDecision(idx, rulestr, int(rule.Scope)) fmt.Println("Decision made.") - // globalPromptLock.Unlock() + globalPromptLock.Unlock() err = removeSelectedRule(idx, true) if err == nil { clearEditor() @@ -1081,17 +1248,17 @@ func main() { }) btnDeny.Connect("clicked", func() { - // globalPromptLock.Lock() + globalPromptLock.Lock() rule, idx, err := getSelectedRule() if err != nil { - // globalPromptLock.Unlock() + globalPromptLock.Unlock() promptError("Error occurred processing request: " + err.Error()) return } rule, err = createCurrentRule() if err != nil { - // globalPromptLock.Unlock() + globalPromptLock.Unlock() promptError("Error occurred constructing new rule: " + err.Error()) return } @@ -1101,7 +1268,7 @@ func main() { fmt.Println("RULESTR = ", rulestr) makeDecision(idx, rulestr, int(rule.Scope)) fmt.Println("Decision made.") - // globalPromptLock.Unlock() + globalPromptLock.Unlock() err = removeSelectedRule(idx, true) if err == nil { clearEditor() @@ -1111,17 +1278,17 @@ func main() { }) btnIgnore.Connect("clicked", func() { - // globalPromptLock.Lock() + globalPromptLock.Lock() _, idx, err := getSelectedRule() if err != nil { - // globalPromptLock.Unlock() + globalPromptLock.Unlock() promptError("Error occurred processing request: " + err.Error()) return } makeDecision(idx, "", 0) fmt.Println("Decision made.") - // globalPromptLock.Unlock() + globalPromptLock.Unlock() err = removeSelectedRule(idx, true) if err == nil { clearEditor() @@ -1132,10 +1299,10 @@ func main() { // tv.SetActivateOnSingleClick(true) tv.Connect("row-activated", func() { - // globalPromptLock.Lock() + globalPromptLock.Lock() seldata, _, err := getSelectedRule() + globalPromptLock.Unlock() if err != nil { - // globalPromptLock.Unlock() promptError("Unexpected error reading selected rule: " + err.Error()) return } @@ -1182,8 +1349,6 @@ func main() { chkUser.SetActive(false) chkGroup.SetActive(false) - - // globalPromptLock.Unlock() return }) @@ -1206,5 +1371,16 @@ func main() { mainWin.ShowAll() // 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() } diff --git a/sgfw/dbus.go b/sgfw/dbus.go index 14547ce..9abfa99 100644 --- a/sgfw/dbus.go +++ b/sgfw/dbus.go @@ -199,6 +199,72 @@ func (ds *dbusServer) DeleteRule(id uint32) *dbus.Error { 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 { log.Debugf("UpdateRule %v", rule) ds.fw.lock.Lock() diff --git a/sgfw/policy.go b/sgfw/policy.go index bfcddd6..2f9858d 100644 --- a/sgfw/policy.go +++ b/sgfw/policy.go @@ -6,8 +6,6 @@ import ( "strings" "sync" - // "encoding/binary" - // nfnetlink "github.com/subgraph/go-nfnetlink" "github.com/google/gopacket/layers" nfqueue "github.com/subgraph/go-nfnetlink/nfqueue" @@ -213,6 +211,12 @@ func (pp *pendingPkt) print() string { return printPacket(pp.pkt, pp.name, pp.pinfo) } +type PendingRule struct { + rule string + scope int + policy string +} + type Policy struct { fw *Firewall path string @@ -223,6 +227,7 @@ type Policy struct { pendingQueue []pendingConnection promptInProgress bool lock sync.Mutex + rulesPending []PendingRule } 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) { p.pendingQueue = append(p.pendingQueue, pc) //fmt.Println("processPromptResult(): p.promptInProgress = ", p.promptInProgress) - if DoMultiPrompt || (!DoMultiPrompt && !p.promptInProgress) { - p.promptInProgress = true - go p.fw.dbus.prompt(p) - } + //if DoMultiPrompt || (!DoMultiPrompt && !p.promptInProgress) { + // if !p.promptInProgress { + p.promptInProgress = true + go p.fw.dbus.prompt(p) + // } } func (p *Policy) nextPending() (pendingConnection, bool) { p.lock.Lock() defer p.lock.Unlock() - if !DoMultiPrompt { + /* if !DoMultiPrompt { if len(p.pendingQueue) == 0 { return nil, true } return p.pendingQueue[0], false - } + }*/ if len(p.pendingQueue) == 0 { return nil, true @@ -334,6 +340,7 @@ func (p *Policy) nextPending() (pendingConnection, bool) { // for len(p.pendingQueue) != 0 { 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() { return p.pendingQueue[i], false } @@ -414,8 +421,6 @@ func (p *Policy) filterPending(rule *Rule) { if prompter == nil { fmt.Println("-------- prompter = NULL") } else { - fmt.Println("---------- could send prompter") - call := prompter.Call("com.subgraph.FirewallPrompt.RemovePrompt", 0, pc.getGUID()) fmt.Println("CAAAAAAAAAAAAAAALL = ", call) } diff --git a/sgfw/prompt.go b/sgfw/prompt.go index 14945dd..ee72a13 100644 --- a/sgfw/prompt.go +++ b/sgfw/prompt.go @@ -13,15 +13,6 @@ import ( "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 { p := new(prompter) p.cond = sync.NewCond(&p.lock) @@ -39,30 +30,6 @@ type prompter struct { 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) { p.lock.Lock() defer p.lock.Unlock() @@ -91,7 +58,8 @@ func (p *prompter) promptLoop() { func (p *prompter) processNextPacket() bool { var pc pendingConnection = nil - if !DoMultiPrompt { + if 1 == 2 { + // if !DoMultiPrompt { pc, _ = p.nextConnection() if pc == nil { return false @@ -118,66 +86,28 @@ func (p *prompter) processNextPacket() bool { defer p.lock.Lock() // fmt.Println("XXX: Waiting for prompt lock go...") for { - promptLock.Lock() - if outstandingPrompts >= MAX_PROMPTS { - promptLock.Unlock() - continue - } if pc.getPrompting() { log.Debugf("Skipping over already prompted connection") - promptLock.Unlock() continue } break } - // fmt.Println("XXX: Passed prompt lock!") - outstandingPrompts++ - // fmt.Println("XXX: Incremented outstanding to ", outstandingPrompts) - promptLock.Unlock() - // if !pc.getPrompting() { pc.setPrompting(true) go p.processConnection(pc) - // } 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) { var scope int32 + var dres bool var rule string if pc.getPrompter() == nil { pc.setPrompter(&dbusObjectP{p.dbusObj}) } - if DoMultiPrompt { - defer processReturn(pc) - } - addr := pc.hostname() if addr == "" { addr = pc.dst().String() @@ -192,10 +122,12 @@ func (p *prompter) processConnection(pc pendingConnection) { dststr = addr + " (via proxy resolver)" } - callChan := make(chan *dbus.Call, 10) - saveChannel(callChan, true, false) - fmt.Println("# outstanding prompt chans = ", len(outstandingPromptChans)) - p.dbusObj.Go("com.subgraph.FirewallPrompt.RequestPrompt", 0, callChan, + // callChan := make(chan *dbus.Call, 10) + // saveChannel(callChan, true, false) + // fmt.Println("# outstanding prompt chans = ", len(outstandingPromptChans)) + + // fmt.Println("ABOUT TO CALL ASYNC PROMPT") + call := p.dbusObj.Call("com.subgraph.FirewallPrompt.RequestPromptAsync", 0, pc.getGUID(), policy.application, policy.icon, @@ -217,52 +149,88 @@ func (p *prompter) processConnection(pc pendingConnection) { FirewallConfig.PromptExpert, int32(FirewallConfig.DefaultActionID)) - select { - case call := <-callChan: + err := call.Store(&dres) + if err != nil { + log.Warningf("Error sending dbus async RequestPrompt message: %v", err) + policy.removePending(pc) + pc.drop() + return + } - if call.Err != nil { - fmt.Println("Error reading DBus channel (accepting packet): ", call.Err) - policy.removePending(pc) - pc.accept() - saveChannel(callChan, false, true) - time.Sleep(1 * time.Second) - return - } + if !dres { + fmt.Println("Unexpected: fw-prompt async RequestPrompt message returned:", dres) + } - if len(call.Body) != 2 { - log.Warning("SGFW got back response in unrecognized format, len = ", len(call.Body)) - saveChannel(callChan, false, true) + return - if (len(call.Body) == 3) && (call.Body[2] == 666) { - fmt.Printf("+++++++++ AWESOME: %v | %v | %v\n", call.Body[0], call.Body[1], call.Body[2]) - scope = call.Body[0].(int32) - rule = call.Body[1].(string) + /* p.dbusObj.Go("com.subgraph.FirewallPrompt.RequestPrompt", 0, callChan, + 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)) + + select { + case call := <-callChan: + + if call.Err != nil { + fmt.Println("Error reading DBus channel (accepting packet): ", call.Err) + policy.removePending(pc) + pc.accept() + saveChannel(callChan, false, true) + time.Sleep(1 * time.Second) + return } - return - } + if len(call.Body) != 2 { + log.Warning("SGFW got back response in unrecognized format, len = ", len(call.Body)) + saveChannel(callChan, false, true) - fmt.Printf("DBUS GOT BACK: %v, %v\n", call.Body[0], call.Body[1]) - scope = call.Body[0].(int32) - rule = call.Body[1].(string) - } + if (len(call.Body) == 3) && (call.Body[2] == 666) { + fmt.Printf("+++++++++ AWESOME: %v | %v | %v\n", call.Body[0], call.Body[1], call.Body[2]) + scope = call.Body[0].(int32) + rule = call.Body[1].(string) + } - saveChannel(callChan, false, true) + return + } - // Try alerting every other channel - promptData := make([]interface{}, 3) - promptData[0] = scope - promptData[1] = rule - promptData[2] = 666 - promptChanLock.Lock() - fmt.Println("# channels to alert: ", len(outstandingPromptChans)) + fmt.Printf("DBUS GOT BACK: %v, %v\n", call.Body[0], call.Body[1]) + scope = call.Body[0].(int32) + rule = call.Body[1].(string) + } - for chidx, _ := range outstandingPromptChans { - alertChannel(chidx, scope, rule) - // ch <- &dbus.Call{Body: promptData} - } + saveChannel(callChan, false, true) - promptChanLock.Unlock() + // Try alerting every other channel + promptData := make([]interface{}, 3) + promptData[0] = scope + promptData[1] = rule + promptData[2] = 666 + promptChanLock.Lock() + fmt.Println("# channels to alert: ", len(outstandingPromptChans)) + + for chidx, _ := range outstandingPromptChans { + alertChannel(chidx, scope, rule) + // ch <- &dbus.Call{Body: promptData} + } + + promptChanLock.Unlock() */ /* err := call.Store(&scope, &rule) if err != nil { @@ -341,9 +309,64 @@ func (p *prompter) nextConnection() (pendingConnection, bool) { if pc == nil && qempty { p.removePolicy(policy) } else { - if pc == nil && !qempty { - log.Errorf("FIX ME: I NEED TO SLEEP ON A WAKEABLE CONDITION PROPERLY!!") - time.Sleep(time.Millisecond * 300) + // 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 { + log.Errorf("FIX ME: I NEED TO SLEEP ON A WAKEABLE CONDITION PROPERLY!!") + time.Sleep(time.Millisecond * 300) + } + } return pc, qempty } @@ -353,14 +376,15 @@ func (p *prompter) nextConnection() (pendingConnection, bool) { func (p *prompter) removePolicy(policy *Policy) { var newQueue []*Policy = nil - if DoMultiPrompt { - if len(p.policyQueue) == 0 { - log.Debugf("Skipping over zero length policy queue") - newQueue = make([]*Policy, 0, 0) - } + // if DoMultiPrompt { + if len(p.policyQueue) == 0 { + log.Debugf("Skipping over zero length policy queue") + newQueue = make([]*Policy, 0, 0) } + // } - if !DoMultiPrompt || newQueue == nil { + // if !DoMultiPrompt || newQueue == nil { + if newQueue == nil { newQueue = make([]*Policy, 0, len(p.policyQueue)-1) } for _, pol := range p.policyQueue { @@ -374,11 +398,17 @@ func (p *prompter) removePolicy(policy *Policy) { var userMap = make(map[int]string) var groupMap = make(map[int]string) +var userMapLock = &sync.Mutex{} +var groupMapLock = &sync.Mutex{} func lookupUser(uid int) string { if uid == -1 { return "[unknown]" } + + userMapLock.Lock() + defer userMapLock.Unlock() + u, err := user.LookupId(strconv.Itoa(uid)) if err != nil { return fmt.Sprintf("%d", uid) @@ -390,6 +420,10 @@ func lookupGroup(gid int) string { if gid == -1 { return "[unknown]" } + + groupMapLock.Lock() + defer groupMapLock.Unlock() + g, err := user.LookupGroupId(strconv.Itoa(gid)) if err != nil { return fmt.Sprintf("%d", gid)