@ -4,6 +4,7 @@ import (
"encoding/json"
"encoding/json"
"errors"
"errors"
"fmt"
"fmt"
"github.com/gotk3/gotk3/gdk"
"github.com/gotk3/gotk3/glib"
"github.com/gotk3/gotk3/glib"
"github.com/gotk3/gotk3/gtk"
"github.com/gotk3/gotk3/gtk"
"io/ioutil"
"io/ioutil"
@ -25,14 +26,6 @@ type fpPreferences struct {
Winleft uint
Winleft uint
}
}
type decisionWaiter struct {
Cond * sync . Cond
Lock sync . Locker
Ready bool
Scope int
Rule string
}
type ruleColumns struct {
type ruleColumns struct {
nrefs int
nrefs int
Path string
Path string
@ -54,36 +47,63 @@ type ruleColumns struct {
Scope int
Scope int
}
}
const (
COL_NO_NREFS = iota
COL_NO_ICON_PIXBUF
COL_NO_GUID
COL_NO_PATH
COL_NO_ICON
COL_NO_PROTO
COL_NO_PID
COL_NO_DSTIP
COL_NO_HOSTNAME
COL_NO_PORT
COL_NO_UID
COL_NO_GID
COL_NO_ORIGIN
COL_NO_TIMESTAMP
COL_NO_IS_SOCKS
COL_NO_OPTSTRING
COL_NO_ACTION
COL_NO_LAST
)
var dbuso * dbusObject
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
var globalLS * gtk . ListStore = nil
var global TS * gtk . Tree Store = nil
var globalTV * gtk . TreeView
var globalTV * gtk . TreeView
var globalPromptLock = & sync . Mutex { }
var globalPromptLock = & sync . Mutex { }
var recentLock = & sync . Mutex { }
var globalIcon * gtk . Image
var globalIcon * gtk . Image
var decisionWaiters [ ] * decisionWaiter
var editApp , editTarget , editPort , editUser , editGroup * gtk . Entry
var editApp , editTarget , editPort , editUser , editGroup * gtk . Entry
var comboProto * gtk . ComboBoxText
var comboProto * gtk . ComboBoxText
var radioOnce , radioProcess , radioParent , radioSession , radioPermanent * gtk . RadioButton
var radioOnce , radioProcess , radioParent , radioSession , radioPermanent * gtk . RadioButton
var btnApprove , btnDeny , btnIgnore * gtk . Button
var btnApprove , btnDeny , btnIgnore * gtk . Button
var chkTLS , chkUser , chkGroup * gtk . CheckButton
var chkTLS , chkUser , chkGroup * gtk . CheckButton
var recentlyRemoved = [ ] string { }
func dumpDecisions ( ) {
func wasRecentlyRemoved ( guid string ) bool {
return
recentLock . Lock ( )
fmt . Println ( "XXX Total of decisions pending: " , len ( decisionWaiters ) )
defer recentLock . Unlock ( )
for i := 0 ; i < len ( decisionWaiters ) ; i ++ {
fmt . Printf ( "XXX %d ready = %v, rule = %v\n" , i + 1 , decisionWaiters [ i ] . Ready , decisionWaiters [ i ] . Rule )
for gind , g := range recentlyRemoved {
if g == guid {
recentlyRemoved = append ( recentlyRemoved [ : gind ] , recentlyRemoved [ gind + 1 : ] ... )
return true
}
}
}
return false
}
}
func addDecision ( ) * decisionWaiter {
func addRecentlyRemoved ( guid string ) {
return nil
recentLock . Lock ( )
decision := decisionWaiter { Lock : & sync . Mutex { } , Ready : false , Scope : int ( sgfw . APPLY_ONCE ) , Rule : "" }
defer recentLock . Unlock ( )
decision . Cond = sync . NewCond ( decision . Lock )
fmt . Println ( "RECENTLY REMOVED: " , guid )
decisionWaiters = append ( decisionWaiters , & decision )
recentlyRemoved = append ( recentlyRemoved , guid )
return & decision
}
}
func promptInfo ( msg string ) {
func promptInfo ( msg string ) {
@ -298,15 +318,27 @@ func get_label(text string) *gtk.Label {
return label
return label
}
}
func createColumn ( title string , id int ) * gtk . TreeViewColumn {
func createColumnImg ( title string , id int ) * gtk . TreeViewColumn {
cellRenderer , err := gtk . CellRendererTextNew ( )
cellRenderer , err := gtk . CellRendererPixbufNew ( )
if err != nil {
log . Fatal ( "Unable to create image cell renderer:" , err )
}
column , err := gtk . TreeViewColumnNewWithAttribute ( title , cellRenderer , "pixbuf" , id )
if err != nil {
log . Fatal ( "Unable to create cell column:" , err )
}
return column
}
func createColumnText ( title string , id int ) * gtk . TreeViewColumn {
cellRenderer , err := gtk . CellRendererTextNew ( )
if err != nil {
if err != nil {
log . Fatal ( "Unable to create text cell renderer:" , err )
log . Fatal ( "Unable to create text cell renderer:" , err )
}
}
column , err := gtk . TreeViewColumnNewWithAttribute ( title , cellRenderer , "text" , id )
column , err := gtk . TreeViewColumnNewWithAttribute ( title , cellRenderer , "text" , id )
if err != nil {
if err != nil {
log . Fatal ( "Unable to create cell column:" , err )
log . Fatal ( "Unable to create cell column:" , err )
}
}
@ -316,33 +348,57 @@ func createColumn(title string, id int) *gtk.TreeViewColumn {
return column
return column
}
}
func create ListStore( general bool ) * gtk . List Store {
func create TreeStore( general bool ) * gtk . Tree Store {
colData := [ ] glib . Type { glib . TYPE_INT , glib . TYPE_ STRING, glib . TYPE_STRING , glib . TYPE_STRING , glib . TYPE_STRING , glib . TYPE_INT , glib . TYPE_STRING ,
colData := [ ] glib . Type { glib . TYPE_INT , glib . TYPE_ OBJECT, glib . TYPE_ STRING, glib . TYPE_STRING , glib . TYPE_STRING , glib . TYPE_STRING , glib . TYPE_INT , glib . TYPE_STRING ,
glib . TYPE_STRING , glib . TYPE_INT , glib . TYPE_INT , glib . TYPE_INT , glib . TYPE_STRING , glib . TYPE_STRING , glib . TYPE_INT , glib . TYPE_STRING , glib . TYPE_INT }
glib . TYPE_STRING , glib . TYPE_INT , glib . TYPE_INT , glib . TYPE_INT , glib . TYPE_STRING , glib . TYPE_STRING , glib . TYPE_INT , glib . TYPE_STRING , glib . TYPE_INT }
listStore , err := gtk . ListStoreNew ( colData ... )
treeStore , err := gtk . TreeStoreNew ( colData ... )
if err != nil {
if err != nil {
log . Fatal ( "Unable to create list store:" , err )
log . Fatal ( "Unable to create list store:" , err )
}
}
return lis tStore
return tree Store
}
}
func removeRequest ( listStore * gtk . ListStore , guid string ) {
func removeRequest ( treeStore * gtk . TreeStore , guid string ) {
if wasRecentlyRemoved ( guid ) {
fmt . Printf ( "Entry for %s was recently removed; deleting from cache\n" , guid )
return
}
removed := false
removed := false
if globalTS == nil {
return
}
globalPromptLock . Lock ( )
globalPromptLock . Lock ( )
defer globalPromptLock . Unlock ( )
defer globalPromptLock . Unlock ( )
/* XXX: This is horrible. Figure out how to do this properly. */
remove_outer :
for ridx := 0 ; ridx < globalLS . IterNChildren ( nil ) ; ridx ++ {
for ridx := 0 ; ridx < global T S. IterNChildren ( nil ) ; ridx ++ {
nchildren := 0
rule, _ , err := getRuleByIdx ( ridx )
this_iter, err := globalTS . GetIterFromString ( fmt . Sprintf ( "%d" , ridx ) )
if err != nil {
if err != nil {
break
log . Println ( "Strange condition; couldn't get iter of known tree index:" , err )
} else if rule . GUID == guid {
} else {
removeSelectedRule ( ridx , true )
nchildren = globalTS . IterNChildren ( this_iter )
removed = true
}
break
for cidx := 0 ; cidx < nchildren - 1 ; cidx ++ {
sidx := cidx
if cidx == nchildren {
cidx = - 1
}
rule , _ , err := getRuleByIdx ( ridx , sidx )
if err != nil {
break remove_outer
} else if rule . GUID == guid {
removeSelectedRule ( ridx , sidx )
removed = true
break
}
}
}
}
}
@ -353,17 +409,104 @@ func removeRequest(listStore *gtk.ListStore, guid string) {
}
}
func addRequestInc ( listStore * gtk . ListStore , guid , path , icon , proto string , pid int , ipaddr , hostname string , port , uid , gid int ,
// Needs to be locked by caller
origin string , is_socks bool , optstring string , sandbox string , action int ) bool {
func storeNewEntry ( ts * gtk . TreeStore , iter * gtk . TreeIter , guid , path , icon , proto string , pid int , ipaddr , hostname string , port , uid , gid int , origin ,
timestamp string , is_socks bool , optstring , sandbox string , action int ) {
var colVals = [ COL_NO_LAST ] interface { } { }
if is_socks {
if ( optstring != "" ) && ( strings . Index ( optstring , "SOCKS" ) == - 1 ) {
optstring = "SOCKS5 / " + optstring
} else if optstring == "" {
optstring = "SOCKS5"
}
}
colVals [ COL_NO_NREFS ] = 1
colVals [ COL_NO_ICON_PIXBUF ] = nil
colVals [ COL_NO_GUID ] = guid
colVals [ COL_NO_PATH ] = path
colVals [ COL_NO_ICON ] = icon
colVals [ COL_NO_PROTO ] = proto
colVals [ COL_NO_PID ] = pid
if ipaddr == "" {
colVals [ COL_NO_DSTIP ] = "---"
} else {
colVals [ COL_NO_DSTIP ] = ipaddr
}
colVals [ COL_NO_HOSTNAME ] = hostname
colVals [ COL_NO_PORT ] = port
colVals [ COL_NO_UID ] = uid
colVals [ COL_NO_GID ] = gid
colVals [ COL_NO_ORIGIN ] = origin
colVals [ COL_NO_TIMESTAMP ] = timestamp
colVals [ COL_NO_IS_SOCKS ] = 0
if is_socks {
colVals [ COL_NO_IS_SOCKS ] = 1
}
colVals [ COL_NO_OPTSTRING ] = optstring
colVals [ COL_NO_ACTION ] = action
itheme , err := gtk . IconThemeGetDefault ( )
if err != nil {
log . Fatal ( "Could not load default icon theme:" , err )
}
make_blank := false
if icon != "" {
pb , err := itheme . LoadIcon ( icon , 24 , gtk . ICON_LOOKUP_GENERIC_FALLBACK )
if err != nil {
log . Println ( "Could not load icon:" , err )
make_blank = true
} else {
colVals [ COL_NO_ICON_PIXBUF ] = pb
}
} else {
make_blank = true
}
if make_blank {
pb , err := gdk . PixbufNew ( gdk . COLORSPACE_RGB , true , 8 , 24 , 24 )
if err != nil {
log . Println ( "Error creating blank icon:" , err )
} else {
colVals [ COL_NO_ICON_PIXBUF ] = pb
img , err := gtk . ImageNewFromPixbuf ( pb )
if err != nil {
log . Println ( "Error creating image from pixbuf:" , err )
} else {
img . Clear ( )
pb = img . GetPixbuf ( )
colVals [ COL_NO_ICON_PIXBUF ] = pb
}
}
}
for n := 0 ; n < len ( colVals ) ; n ++ {
err := ts . SetValue ( iter , n , colVals [ n ] )
if err != nil {
log . Fatal ( "Unable to add row:" , err )
}
}
return
}
func addRequestInc ( treeStore * gtk . TreeStore , guid , path , icon , proto string , pid int , ipaddr , hostname string , port , uid , gid int ,
origin , timestamp string , is_socks bool , optstring string , sandbox string , action int ) bool {
duplicated := false
duplicated := false
globalPromptLock . Lock ( )
globalPromptLock . Lock ( )
defer globalPromptLock . Unlock ( )
defer globalPromptLock . Unlock ( )
for ridx := 0 ; ridx < globalLS . IterNChildren ( nil ) ; ridx ++ {
for ridx := 0 ; ridx < globalTS . IterNChildren ( nil ) ; ridx ++ {
rule , iter , err := getRuleByIdx ( ridx , - 1 )
/* XXX: This is horrible. Figure out how to do this properly. */
rule , iter , err := getRuleByIdx ( ridx )
if err != nil {
if err != nil {
break
break
// XXX: not compared: optstring/sandbox
// XXX: not compared: optstring/sandbox
@ -371,14 +514,15 @@ func addRequestInc(listStore *gtk.ListStore, guid, path, icon, proto string, pid
( rule . Port == port ) && ( rule . UID == uid ) && ( rule . GID == gid ) && ( rule . Origin == origin ) && ( rule . IsSocks == is_socks ) {
( rule . Port == port ) && ( rule . UID == uid ) && ( rule . GID == gid ) && ( rule . Origin == origin ) && ( rule . IsSocks == is_socks ) {
rule . nrefs ++
rule . nrefs ++
err := global L S. SetValue ( iter , 0 , rule . nrefs )
err := global T S. SetValue ( iter , 0 , rule . nrefs )
if err != nil {
if err != nil {
log . Println ( "Error creating duplicate firewall prompt entry:" , err )
log . Println ( "Error creating duplicate firewall prompt entry:" , err )
break
break
}
}
fmt . Println ( "YES REALLY DUPLICATE: " , rule . nrefs )
duplicated = true
duplicated = true
subiter := globalTS . Append ( iter )
storeNewEntry ( globalTS , subiter , guid , path , icon , proto , pid , ipaddr , hostname , port , uid , gid , origin , timestamp , is_socks , optstring , sandbox , action )
break
break
}
}
@ -387,27 +531,27 @@ func addRequestInc(listStore *gtk.ListStore, guid, path, icon, proto string, pid
return duplicated
return duplicated
}
}
func addRequestAsync ( listStore * gtk . List Store, guid , path , icon , proto string , pid int , ipaddr , hostname string , port , uid , gid int ,
func addRequestAsync ( treeStore * gtk . Tree Store, guid , path , icon , proto string , pid int , ipaddr , hostname string , port , uid , gid int ,
origin , timestamp string , is_socks bool , optstring string , sandbox string , action int ) bool {
origin , timestamp string , is_socks bool , optstring string , sandbox string , action int ) bool {
addRequest ( lis tStore, guid , path , icon , proto , pid , ipaddr , hostname , port , uid , gid , origin , timestamp , is_socks ,
addRequest ( tree Store, guid , path , icon , proto , pid , ipaddr , hostname , port , uid , gid , origin , timestamp , is_socks ,
optstring , sandbox , action )
optstring , sandbox , action )
return true
return true
}
}
func addRequest ( listStore * gtk . List Store, guid , path , icon , proto string , pid int , ipaddr , hostname string , port , uid , gid int ,
func addRequest ( treeStore * gtk . Tree Store, guid , path , icon , proto string , pid int , ipaddr , hostname string , port , uid , gid int ,
origin , timestamp string , is_socks bool , optstring string , sandbox string , action int ) * decisionWaiter {
origin , timestamp string , is_socks bool , optstring string , sandbox string , action int ) bool {
if lis tStore == nil {
if tree Store == nil {
listStore = globalL S
treeStore = globalT S
waitTimes := [ ] int { 1 , 2 , 5 , 10 }
waitTimes := [ ] int { 1 , 2 , 5 , 10 }
if lis tStore == nil {
if tree Store == nil {
log . Println ( "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 {
for _ , wtime := range waitTimes {
time . Sleep ( time . Duration ( wtime ) * time . Second )
time . Sleep ( time . Duration ( wtime ) * time . Second )
listStore = globalL S
treeStore = globalT S
if lis tStore != nil {
if tree Store != nil {
break
break
}
}
@ -418,78 +562,26 @@ func addRequest(listStore *gtk.ListStore, guid, path, icon, proto string, pid in
}
}
if lis tStore == nil {
if tree Store == nil {
log . Fatal ( "SGFW prompter GUI failed to load for unknown reasons" )
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 , action ) {
if addRequestInc ( treeStore , guid , path , icon , proto , pid , ipaddr , hostname , port , uid , gid , origin , timestamp , is_socks , optstring , sandbox , action ) {
fmt . Println ( "REQUEST WAS DUPLICATE" )
fmt . Println ( "Request was duplicate: " , guid )
decision := addDecision ( )
globalPromptLock . Lock ( )
globalPromptLock . Lock ( )
toggleHover ( )
toggleHover ( )
globalPromptLock . Unlock ( )
globalPromptLock . Unlock ( )
return decision
return true
} else {
fmt . Println ( "NOT DUPLICATE" )
}
}
globalPromptLock . Lock ( )
globalPromptLock . Lock ( )
iter := listStore . Append ( )
defer globalPromptLock . Unlock ( )
if is_socks {
if ( optstring != "" ) && ( strings . Index ( optstring , "SOCKS" ) == - 1 ) {
optstring = "SOCKS5 / " + optstring
} else if optstring == "" {
optstring = "SOCKS5"
}
}
colVals := make ( [ ] interface { } , 16 )
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 ] = timestamp
colVals [ 13 ] = 0
if is_socks {
colVals [ 13 ] = 1
}
colVals [ 14 ] = optstring
colVals [ 15 ] = action
colNums := make ( [ ] int , len ( colVals ) )
for n := 0 ; n < len ( colVals ) ; n ++ {
colNums [ n ] = n
}
err := listStore . Set ( iter , colNums , colVals )
if err != nil {
iter := treeStore . Append ( nil )
log . Fatal ( "Unable to add row:" , err )
storeNewEntry ( treeStore , iter , guid , path , icon , proto , pid , ipaddr , hostname , port , uid , gid , origin , timestamp , is_socks , optstring , sandbox , action )
}
decision := addDecision ( )
dumpDecisions ( )
toggleHover ( )
toggleHover ( )
globalPromptLock . Unlock ( )
return true
return decision
}
}
func setup_settings ( ) {
func setup_settings ( ) {
@ -554,8 +646,8 @@ func setup_settings() {
Notebook . AppendPage ( scrollbox , hLabel )
Notebook . AppendPage ( scrollbox , hLabel )
}
}
func lsGetStr ( ls * gtk . List Store, iter * gtk . TreeIter , idx int ) ( string , error ) {
func lsGetStr ( ls * gtk . Tree Store, iter * gtk . TreeIter , idx int ) ( string , error ) {
val , err := global L S. GetValue ( iter , idx )
val , err := global T S. GetValue ( iter , idx )
if err != nil {
if err != nil {
return "" , err
return "" , err
}
}
@ -568,8 +660,8 @@ func lsGetStr(ls *gtk.ListStore, iter *gtk.TreeIter, idx int) (string, error) {
return sval , nil
return sval , nil
}
}
func lsGetInt ( ls * gtk . List Store, iter * gtk . TreeIter , idx int ) ( int , error ) {
func lsGetInt ( ls * gtk . Tree Store, iter * gtk . TreeIter , idx int ) ( int , error ) {
val , err := global L S. GetValue ( iter , idx )
val , err := global T S. GetValue ( iter , idx )
if err != nil {
if err != nil {
return 0 , err
return 0 , err
}
}
@ -582,9 +674,9 @@ 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 ) error {
func makeDecision ( rule string , scope int , guid string ) error {
var dres bool
var dres bool
call := dbuso . Call ( "AddRuleAsync" , 0 , uint32 ( scope ) , rule , "*" )
call := dbuso . Call ( "AddRuleAsync" , 0 , uint32 ( scope ) , rule , "*" , guid )
err := call . Store ( & dres )
err := call . Store ( & dres )
if err != nil {
if err != nil {
@ -593,20 +685,12 @@ func makeDecision(idx int, rule string, scope int) error {
}
}
fmt . Println ( "makeDecision remote result:" , dres )
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
return nil
}
}
/* Do we need to hold the lock while this is called? Stay safe... */
/* Do we need to hold the lock while this is called? Stay safe... */
func toggleHover ( ) {
func toggleHover ( ) {
nitems := global L S. IterNChildren ( nil )
nitems := globalTS . IterNChildren ( nil )
mainWin . SetKeepAbove ( nitems > 0 )
mainWin . SetKeepAbove ( nitems > 0 )
}
}
@ -730,120 +814,187 @@ func clearEditor() {
chkTLS . SetActive ( false )
chkTLS . SetActive ( false )
}
}
func removeSelectedRule ( idx int , rmdecision bool ) error {
func removeSelectedRule ( idx , subidx int ) error {
fmt . Println ( "XXX: attempting to remove idx = " , idx )
fmt . Printf ( "XXX: attempting to remove idx = %v, %v\n" , idx , subidx )
ppathstr := fmt . Sprintf ( "%d" , idx )
pathstr := ppathstr
path , err := gtk . TreePathNewFromString ( fmt . Sprintf ( "%d" , idx ) )
if subidx > - 1 {
if err != nil {
pathstr = fmt . Sprintf ( "%d:%d" , idx , subidx )
return err
}
}
iter , err := global LS. GetIter ( path )
iter , err := global TS. GetIterFromString ( pathstr )
if err != nil {
if err != nil {
return err
return err
}
}
globalLS . Remove ( iter )
nchildren := globalTS . IterNChildren ( iter )
if nchildren >= 1 {
firstpath := fmt . Sprintf ( "%d:0" , idx )
citer , err := globalTS . GetIterFromString ( firstpath )
if err != nil {
return err
}
gnrefs , err := globalTS . GetValue ( iter , COL_NO_NREFS )
if err != nil {
return err
}
vnrefs , err := gnrefs . GoValue ( )
if err != nil {
return err
}
nrefs := vnrefs . ( int ) - 1
for n := 0 ; n < COL_NO_LAST ; n ++ {
val , err := globalTS . GetValue ( citer , n )
if err != nil {
return err
}
if n == COL_NO_NREFS {
err = globalTS . SetValue ( iter , n , nrefs )
} else {
err = globalTS . SetValue ( iter , n , val )
}
if err != nil {
return err
}
}
globalTS . Remove ( citer )
return nil
}
globalTS . Remove ( iter )
if subidx > - 1 {
ppath , err := gtk . TreePathNewFromString ( ppathstr )
if err != nil {
return err
}
piter , err := globalTS . GetIter ( ppath )
if err != nil {
return err
}
nrefs , err := lsGetInt ( globalTS , piter , COL_NO_NREFS )
if err != nil {
return err
}
if rmdecision {
err = globalTS . SetValue ( piter , COL_NO_NREFS , nrefs - 1 )
// decisionWaiters = append(decisionWaiters[:idx], decisionWaiters[idx+1:]...)
if err != nil {
return err
}
}
}
toggleHover ( )
toggleHover ( )
return nil
return nil
}
}
// Needs to be locked by the caller
func numSelections ( ) int {
func numSelections ( ) int {
sel , err := globalTV . GetSelection ( )
sel , err := globalTV . GetSelection ( )
if err != nil {
if err != nil {
return - 1
return - 1
}
}
rows := sel . GetSelectedRows ( globalLS )
rows := sel . GetSelectedRows ( global T S)
return int ( rows . Length ( ) )
return int ( rows . Length ( ) )
}
}
// Needs to be locked by the caller
// Needs to be locked by the caller
func getRuleByIdx ( idx int ) ( ruleColumns , * gtk . TreeIter , error ) {
func getRuleByIdx ( idx , subidx int ) ( ruleColumns , * gtk . TreeIter , error ) {
rule := ruleColumns { }
rule := ruleColumns { }
tpath := fmt . Sprintf ( "%d" , idx )
if subidx != - 1 {
tpath = fmt . Sprintf ( "%d:%d" , idx , subidx )
}
path , err := gtk . TreePathNewFromString ( fmt . Sprintf ( "%d" , idx ) )
path , err := gtk . TreePathNewFromString ( tpath )
if err != nil {
if err != nil {
return rule , nil , err
return rule , nil , err
}
}
iter , err := globalLS . GetIter ( path )
iter , err := global T S. GetIter ( path )
if err != nil {
if err != nil {
return rule , nil , err
return rule , nil , err
}
}
rule . nrefs , err = lsGetInt ( globalLS , iter , 0 )
rule . nrefs , err = lsGetInt ( global TS, iter , COL_NO_NREFS )
if err != nil {
if err != nil {
return rule , nil , err
return rule , nil , err
}
}
rule . GUID , err = lsGetStr ( globalLS , iter , 1 )
rule . GUID , err = lsGetStr ( global TS, iter , COL_NO_GUID )
if err != nil {
if err != nil {
return rule , nil , err
return rule , nil , err
}
}
rule . Path , err = lsGetStr ( globalLS , iter , 2 )
rule . Path , err = lsGetStr ( global TS, iter , COL_NO_PATH )
if err != nil {
if err != nil {
return rule , nil , err
return rule , nil , err
}
}
rule . Icon , err = lsGetStr ( globalLS , iter , 3 )
rule . Icon , err = lsGetStr ( global TS, iter , COL_NO_ICON )
if err != nil {
if err != nil {
return rule , nil , err
return rule , nil , err
}
}
rule . Proto , err = lsGetStr ( globalLS , iter , 4 )
rule . Proto , err = lsGetStr ( global TS, iter , COL_NO_PROTO )
if err != nil {
if err != nil {
return rule , nil , err
return rule , nil , err
}
}
rule . Pid , err = lsGetInt ( global LS, iter , 5 )
rule . Pid , err = lsGetInt ( global TS, iter , COL_NO_PID )
if err != nil {
if err != nil {
return rule , nil , err
return rule , nil , err
}
}
rule . Target , err = lsGetStr ( global LS, iter , 6 )
rule . Target , err = lsGetStr ( global TS, iter , COL_NO_DSTIP )
if err != nil {
if err != nil {
return rule , nil , err
return rule , nil , err
}
}
rule . Hostname , err = lsGetStr ( global LS, iter , 7 )
rule . Hostname , err = lsGetStr ( global TS, iter , COL_NO_HOSTNAME )
if err != nil {
if err != nil {
return rule , nil , err
return rule , nil , err
}
}
rule . Port , err = lsGetInt ( global LS, iter , 8 )
rule . Port , err = lsGetInt ( global TS, iter , COL_NO_PORT )
if err != nil {
if err != nil {
return rule , nil , err
return rule , nil , err
}
}
rule . UID , err = lsGetInt ( global LS, iter , 9 )
rule . UID , err = lsGetInt ( global TS, iter , COL_NO_UID )
if err != nil {
if err != nil {
return rule , nil , err
return rule , nil , err
}
}
rule . GID , err = lsGetInt ( global LS, iter , 10 )
rule . GID , err = lsGetInt ( global TS, iter , COL_NO_GID )
if err != nil {
if err != nil {
return rule , nil , err
return rule , nil , err
}
}
rule . Origin , err = lsGetStr ( global LS, iter , 11 )
rule . Origin , err = lsGetStr ( global TS, iter , COL_NO_ORIGIN )
if err != nil {
if err != nil {
return rule , nil , err
return rule , nil , err
}
}
rule . Timestamp , err = lsGetStr ( global LS, iter , 12 )
rule . Timestamp , err = lsGetStr ( global TS, iter , COL_NO_TIMESTAMP )
if err != nil {
if err != nil {
return rule , nil , err
return rule , nil , err
}
}
rule . IsSocks = false
rule . IsSocks = false
is_socks , err := lsGetInt ( global LS, iter , 13 )
is_socks , err := lsGetInt ( global TS, iter , COL_NO_IS_SOCKS )
if err != nil {
if err != nil {
return rule , nil , err
return rule , nil , err
}
}
@ -852,7 +1003,7 @@ func getRuleByIdx(idx int) (ruleColumns, *gtk.TreeIter, error) {
rule . IsSocks = true
rule . IsSocks = true
}
}
rule . Scope , err = lsGetInt ( global LS, iter , 15 )
rule . Scope , err = lsGetInt ( global TS, iter , COL_NO_ACTION )
if err != nil {
if err != nil {
return rule , nil , err
return rule , nil , err
}
}
@ -861,116 +1012,78 @@ func getRuleByIdx(idx int) (ruleColumns, *gtk.TreeIter, error) {
}
}
// Needs to be locked by the caller
// Needs to be locked by the caller
func getSelectedRule ( ) ( ruleColumns , int , error) {
func getSelectedRule ( ) ( ruleColumns , int , int, error) {
rule := ruleColumns { }
rule := ruleColumns { }
sel , err := globalTV . GetSelection ( )
sel , err := globalTV . GetSelection ( )
if err != nil {
if err != nil {
return rule , - 1 , err
return rule , - 1 , - 1 , err
}
}
rows := sel . GetSelectedRows ( global L S)
rows := sel . GetSelectedRows ( global T S)
if rows . Length ( ) <= 0 {
if rows . Length ( ) <= 0 {
return rule , - 1 , errors . New ( " N o selection was made")
return rule , - 1 , - 1 , errors . New ( " n o selection was made")
}
}
rdata := rows . NthData ( 0 )
rdata := rows . NthData ( 0 )
lIndex , err := strconv . Atoi ( rdata . ( * gtk . TreePath ) . String ( ) )
tpath := rdata . ( * gtk . TreePath ) . String ( )
if err != nil {
return rule , - 1 , err
}
fmt . Println ( "lindex = " , lIndex )
rule , _ , err = getRuleByIdx ( lIndex )
if err != nil {
return rule , - 1 , err
}
return rule , lIndex , nil
}
func addPendingPrompts ( rules [ ] string ) {
for _ , rule := range rules {
fields := strings . Split ( rule , "|" )
if len ( fields ) != 19 {
log . Printf ( "Got saved prompt message with strange data: \"%s\"" , rule )
continue
}
guid := fields [ 0 ]
subidx := - 1
icon := fields [ 2 ]
ptoks := strings . Split ( tpath , ":" )
path := fields [ 3 ]
address := fields [ 4 ]
port , err := strconv . Atoi ( fields [ 5 ] )
if len ( ptoks ) > 2 {
return rule , - 1 , - 1 , errors . New ( "internal error parsing selected item tree path" )
} else if len ( ptoks ) == 2 {
subidx , err = strconv . Atoi ( ptoks [ 1 ] )
if err != nil {
if err != nil {
log . Println ( "Error converting port in pending prompt message to integer:" , err )
return rule , - 1 , - 1 , err
continue
}
}
tpath = ptoks [ 0 ]
}
ip := fields [ 6 ]
lIndex , err := strconv . Atoi ( tpath )
origin := fields [ 7 ]
if err != nil {
proto := fields [ 8 ]
return rule , - 1 , - 1 , err
}
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
}
timestamp := fields [ 16 ]
optstring := fields [ 17 ]
action , err := strconv . Atoi ( fields [ 18 ] )
if err != nil {
log . Println ( "Error converting action in pending prompt message to integer:" , err )
continue
}
addRequestAsync ( nil , guid , path , icon , proto , int ( pid ) , ip , address , int ( port ) , int ( uid ) , int ( gid ) , origin , timestamp , is_socks , optstring , sandbox , action )
// fmt.Printf("lindex = %d : %d\n", lIndex, subidx)
rule , _ , err = getRuleByIdx ( lIndex , subidx )
if err != nil {
return rule , - 1 , - 1 , err
}
}
return rule , lIndex , subidx , nil
}
}
func buttonAction ( action string ) {
func buttonAction ( action string ) {
globalPromptLock . Lock ( )
globalPromptLock . Lock ( )
rule , idx , err := getSelectedRule ( )
rule , idx , subidx , 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 ( )
urule , 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
}
}
// Overlay the rules
rule . Scope = urule . Scope
//rule.Path = urule.Path
rule . Port = urule . Port
rule . Target = urule . Target
rule . Proto = urule . Proto
// rule.UID = urule.UID
// rule.GID = urule.GID
// rule.Uname = urule.Uname
// rule.Gname = urule.Gname
rule . ForceTLS = urule . ForceTLS
fmt . Println ( "rule = " , rule )
fmt . Println ( "rule = " , rule )
rulestr := action
rulestr := action
@ -981,9 +1094,9 @@ func buttonAction(action string) {
rulestr += "|" + rule . Proto + ":" + rule . Target + ":" + strconv . Itoa ( rule . Port )
rulestr += "|" + rule . Proto + ":" + rule . Target + ":" + strconv . Itoa ( rule . Port )
rulestr += "|" + sgfw . RuleModeString [ sgfw . RuleMode ( rule . Scope ) ]
rulestr += "|" + sgfw . RuleModeString [ sgfw . RuleMode ( rule . Scope ) ]
fmt . Println ( "RULESTR = " , rulestr )
fmt . Println ( "RULESTR = " , rulestr )
makeDecision ( idx, rulestr, int ( rule . Scope ) )
makeDecision ( rulestr, int ( rule . Scope ) , rule . GUID )
fmt. Println ( "Decision made." )
err = removeSelectedRule ( idx , subidx )
err = removeSelectedRule ( idx , true )
addRecentlyRemoved ( rule . GUID )
globalPromptLock . Unlock ( )
globalPromptLock . Unlock ( )
if err == nil {
if err == nil {
clearEditor ( )
clearEditor ( )
@ -994,7 +1107,6 @@ func buttonAction(action string) {
}
}
func main ( ) {
func main ( ) {
decisionWaiters = make ( [ ] * decisionWaiter , 0 )
_ , err := newDbusServer ( )
_ , err := newDbusServer ( )
if err != nil {
if err != nil {
log . Fatal ( "Error:" , err )
log . Fatal ( "Error:" , err )
@ -1104,6 +1216,7 @@ func main() {
// globalIcon.SetFromIconName("firefox", gtk.ICON_SIZE_DND)
// globalIcon.SetFromIconName("firefox", gtk.ICON_SIZE_DND)
editApp = get_entry ( "" )
editApp = get_entry ( "" )
editApp . SetEditable ( false )
editApp . Connect ( "changed" , toggleValidRuleState )
editApp . Connect ( "changed" , toggleValidRuleState )
hbox . PackStart ( lbl , false , false , 10 )
hbox . PackStart ( lbl , false , false , 10 )
hbox . PackStart ( editApp , true , true , 10 )
hbox . PackStart ( editApp , true , true , 10 )
@ -1166,42 +1279,43 @@ func main() {
// box.PackStart(tv, false, true, 5)
// box.PackStart(tv, false, true, 5)
box . PackStart ( scrollbox , false , true , 5 )
box . PackStart ( scrollbox , false , true , 5 )
tv . AppendColumn ( createColumn ( "#" , 0 ) )
tv . AppendColumn ( createColumnText ( "#" , COL_NO_NREFS ) )
tv . AppendColumn ( createColumnImg ( "" , COL_NO_ICON_PIXBUF ) )
guidcol := createColumn ( "GUID" , 1 )
guidcol := createColumn Text( "GUID" , COL_NO_GUID )
guidcol . SetVisible ( false )
guidcol . SetVisible ( false )
tv . AppendColumn ( guidcol )
tv . AppendColumn ( guidcol )
tv . AppendColumn ( createColumn ( "Path" , 2 ) )
tv . AppendColumn ( createColumn Text( "Path" , COL_NO_PATH ) )
icol := createColumn ( "Icon" , 3 )
icol := createColumn Text( "Icon" , COL_NO_ICON )
icol . SetVisible ( false )
icol . SetVisible ( false )
tv . AppendColumn ( icol )
tv . AppendColumn ( icol )
tv . AppendColumn ( createColumn ( "Protocol" , 4 ) )
tv . AppendColumn ( createColumn Text( "Protocol" , COL_NO_PROTO ) )
tv . AppendColumn ( createColumn ( "PID" , 5 ) )
tv . AppendColumn ( createColumn Text( "PID" , COL_NO_PID ) )
tv . AppendColumn ( createColumn ( "IP Address" , 6 ) )
tv . AppendColumn ( createColumn Text( "IP Address" , COL_NO_DSTIP ) )
tv . AppendColumn ( createColumn ( "Hostname" , 7 ) )
tv . AppendColumn ( createColumn Text( "Hostname" , COL_NO_HOSTNAME ) )
tv . AppendColumn ( createColumn ( "Port" , 8 ) )
tv . AppendColumn ( createColumn Text( "Port" , COL_NO_PORT ) )
tv . AppendColumn ( createColumn ( "UID" , 9 ) )
tv . AppendColumn ( createColumn Text( "UID" , COL_NO_UID ) )
tv . AppendColumn ( createColumn ( "GID" , 10 ) )
tv . AppendColumn ( createColumn Text( "GID" , COL_NO_GID ) )
tv . AppendColumn ( createColumn ( "Origin" , 11 ) )
tv . AppendColumn ( createColumn Text( "Origin" , COL_NO_ORIGIN ) )
tv . AppendColumn ( createColumn ( "Timestamp" , 12 ) )
tv . AppendColumn ( createColumn Text( "Timestamp" , COL_NO_TIMESTAMP ) )
scol := createColumn ( "Is SOCKS" , 13 )
scol := createColumn Text( "Is SOCKS" , COL_NO_IS_SOCKS )
scol . SetVisible ( false )
scol . SetVisible ( false )
tv . AppendColumn ( scol )
tv . AppendColumn ( scol )
tv . AppendColumn ( createColumn ( "Details" , 14 ) )
tv . AppendColumn ( createColumn Text( "Details" , COL_NO_OPTSTRING ) )
acol := createColumn ( "Scope" , 15 )
acol := createColumn Text( "Scope" , COL_NO_ACTION )
acol . SetVisible ( false )
acol . SetVisible ( false )
tv . AppendColumn ( acol )
tv . AppendColumn ( acol )
listStore := createList Store( true )
treeStore := createTree Store( true )
global LS = list Store
global TS = tree Store
tv . SetModel ( lis tStore)
tv . SetModel ( tree Store)
btnApprove . Connect ( "clicked" , func ( ) {
btnApprove . Connect ( "clicked" , func ( ) {
buttonAction ( "ALLOW" )
buttonAction ( "ALLOW" )
@ -1214,7 +1328,7 @@ 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 ( )
globalPromptLock . Unlock ( )
if err != nil {
if err != nil {
promptError ( "Unexpected error reading selected rule: " + err . Error ( ) )
promptError ( "Unexpected error reading selected rule: " + err . Error ( ) )
@ -1237,7 +1351,7 @@ func main() {
editPort . SetText ( strconv . Itoa ( seldata . Port ) )
editPort . SetText ( strconv . Itoa ( seldata . Port ) )
radioOnce . SetActive ( seldata . Scope == int ( sgfw . APPLY_ONCE ) )
radioOnce . SetActive ( seldata . Scope == int ( sgfw . APPLY_ONCE ) )
radioProcess . SetSensitive ( seldata . Pid > 0 )
radioProcess . SetSensitive ( seldata . Scope == int ( sgfw . APPLY_PROCESS ) )
radioParent . SetActive ( false )
radioParent . SetActive ( false )
radioSession . SetActive ( seldata . Scope == int ( sgfw . APPLY_SESSION ) )
radioSession . SetActive ( seldata . Scope == int ( sgfw . APPLY_SESSION ) )
radioPermanent . SetActive ( seldata . Scope == int ( sgfw . APPLY_FOREVER ) )
radioPermanent . SetActive ( seldata . Scope == int ( sgfw . APPLY_FOREVER ) )
@ -1286,14 +1400,14 @@ func main() {
mainWin . ShowAll ( )
mainWin . ShowAll ( )
// mainWin.SetKeepAbove(true)
// mainWin.SetKeepAbove(true)
var dres = [ ] string { }
var dres bool
call := dbuso . Call ( "GetPendingRequests" , 0 , "*" )
call := dbuso . Call ( "GetPendingRequests" , 0 , "*" )
err = call . Store ( & dres )
err = call . Store ( & dres )
if err != nil {
if err != nil {
errmsg := "Could not query running SGFW instance (maybe it's not running?): " + err . Error ( )
errmsg := "Could not query running SGFW instance (maybe it's not running?): " + err . Error ( )
promptError ( errmsg )
promptError ( errmsg )
} else {
} else if ! dres {
addPendingPrompts( dres )
promptError( "Call to sgfw did not succeed; fw-prompt may have loaded without retrieving all pending connections" )
}
}
gtk . Main ( )
gtk . Main ( )