You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
fw-daemon/sgfw/prompt.go

189 lines
3.4 KiB

package sgfw
9 years ago
import (
"fmt"
"github.com/godbus/dbus"
9 years ago
"os/user"
"strconv"
"strings"
9 years ago
"sync"
)
const (
APPLY_ONCE = iota
APPLY_SESSION
APPLY_FOREVER
)
func newPrompter(conn *dbus.Conn) *prompter {
p := new(prompter)
p.cond = sync.NewCond(&p.lock)
p.dbusObj = conn.Object("com.subgraph.FirewallPrompt", "/com/subgraph/FirewallPrompt")
p.policyMap = make(map[string]*Policy)
go p.promptLoop()
return p
}
type prompter struct {
dbusObj dbus.BusObject
lock sync.Mutex
cond *sync.Cond
policyMap map[string]*Policy
policyQueue []*Policy
}
func (p *prompter) prompt(policy *Policy) {
p.lock.Lock()
defer p.lock.Unlock()
_, ok := p.policyMap[policy.path]
if ok {
return
}
p.policyMap[policy.path] = policy
p.policyQueue = append(p.policyQueue, policy)
p.cond.Signal()
}
func (p *prompter) promptLoop() {
p.lock.Lock()
for {
for p.processNextPacket() {
}
p.cond.Wait()
}
}
func (p *prompter) processNextPacket() bool {
pc := p.nextConnection()
if pc == nil {
9 years ago
return false
}
p.lock.Unlock()
defer p.lock.Lock()
p.processConnection(pc)
9 years ago
return true
}
func printScope(scope int32) string {
switch scope {
case APPLY_SESSION:
return "SESSION"
9 years ago
case APPLY_ONCE:
return "ONCE"
case APPLY_FOREVER:
return "FOREVER"
default:
return "SESSION"
}
}
func valueScope(scope string) int32 {
scope = strings.ToUpper(scope)
switch scope {
case "SESSION":
return APPLY_SESSION
case "ONCE":
return APPLY_ONCE
case "FOREVER":
return APPLY_FOREVER
9 years ago
default:
return APPLY_SESSION
9 years ago
}
}
func (p *prompter) processConnection(pc pendingConnection) {
9 years ago
var scope int32
var rule string
addr := pc.hostname()
9 years ago
if addr == "" {
addr = pc.dst().String()
9 years ago
}
policy := pc.policy()
9 years ago
call := p.dbusObj.Call("com.subgraph.FirewallPrompt.RequestPrompt", 0,
policy.application,
policy.icon,
policy.path,
9 years ago
addr,
int32(pc.dstPort()),
pc.dst().String(),
uidToUser(pc.procInfo().UID),
int32(pc.procInfo().Pid),
FirewallConfig.PromptExpanded,
FirewallConfig.PromptExpert,
FirewallConfig.DefaultActionId)
9 years ago
err := call.Store(&scope, &rule)
if err != nil {
log.Warningf("Error sending dbus RequestPrompt message: %v", err)
policy.removePending(pc)
pc.drop()
9 years ago
return
}
r, err := policy.parseRule(rule, false)
9 years ago
if err != nil {
log.Warningf("Error parsing rule string returned from dbus RequestPrompt: %v", err)
policy.removePending(pc)
pc.drop()
9 years ago
return
}
if scope == APPLY_SESSION {
r.mode = RULE_MODE_SESSION
9 years ago
}
if !policy.processNewRule(r, scope) {
9 years ago
p.lock.Lock()
defer p.lock.Unlock()
p.removePolicy(pc.policy())
9 years ago
}
if scope == APPLY_FOREVER {
policy.fw.saveRules()
9 years ago
}
}
func (p *prompter) nextConnection() pendingConnection {
9 years ago
for {
if len(p.policyQueue) == 0 {
return nil
}
policy := p.policyQueue[0]
pc := policy.nextPending()
if pc == nil {
9 years ago
p.removePolicy(policy)
} else {
return pc
9 years ago
}
}
}
func (p *prompter) removePolicy(policy *Policy) {
newQueue := make([]*Policy, 0, len(p.policyQueue)-1)
for _, pol := range p.policyQueue {
if pol != policy {
newQueue = append(newQueue, pol)
}
}
p.policyQueue = newQueue
delete(p.policyMap, policy.path)
}
var userMap = make(map[int]string)
func lookupUser(uid int) string {
u, err := user.LookupId(strconv.Itoa(uid))
if err != nil {
return fmt.Sprintf("%d", uid)
}
return u.Name
}
func uidToUser(uid int) string {
uname, ok := userMap[uid]
if ok {
return uname
}
uname = lookupUser(uid)
userMap[uid] = uname
return uname
}