From 1c7606cea18e908cf76201ce1534b0afdc04cc89 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Fri, 13 Nov 2020 03:10:00 +0100 Subject: manager: allow S-1-5-32-556 users to launch a limited UI I still have serious security reservations about this, both conceptually -- should users be allowed to do this stuff? -- and pratically -- there are issues with this implementation that need some examination. TODO: - Is that registry key a secure path? Should we double check it? - Are we leaking handles to the unpriv'd process from the manager? Audit this too. - IPC notifications are blocking. Should we move this to a go routine to mitigate DoS potential? - Is GOB deserialization secure? Can an NCO user crash or RCE the manager? Signed-off-by: Jason A. Donenfeld --- ui/confview.go | 14 +++++++++++--- ui/tray.go | 4 ++-- ui/tunnelspage.go | 9 +++++++++ ui/ui.go | 1 + 4 files changed, 23 insertions(+), 5 deletions(-) (limited to 'ui') diff --git a/ui/confview.go b/ui/confview.go index e34d81b1..089f6572 100644 --- a/ui/confview.go +++ b/ui/confview.go @@ -364,7 +364,11 @@ func (iv *interfaceView) widgetsLines() []widgetsLine { } func (iv *interfaceView) apply(c *conf.Interface) { - iv.publicKey.show(c.PrivateKey.Public().String()) + if IsAdmin { + iv.publicKey.show(c.PrivateKey.Public().String()) + } else { + iv.publicKey.hide() + } if c.ListenPort > 0 { iv.listenPort.show(strconv.Itoa(int(c.ListenPort))) @@ -405,9 +409,13 @@ func (pv *peerView) widgetsLines() []widgetsLine { } func (pv *peerView) apply(c *conf.Peer) { - pv.publicKey.show(c.PublicKey.String()) + if IsAdmin { + pv.publicKey.show(c.PublicKey.String()) + } else { + pv.publicKey.hide() + } - if !c.PresharedKey.IsZero() { + if !c.PresharedKey.IsZero() && IsAdmin { pv.presharedKey.show(l18n.Sprintf("enabled")) } else { pv.presharedKey.hide() diff --git a/ui/tray.go b/ui/tray.go index 768d72a3..006e20a5 100644 --- a/ui/tray.go +++ b/ui/tray.go @@ -82,10 +82,10 @@ func (tray *Tray) setup() error { {separator: true}, {separator: true}, {label: l18n.Sprintf("&Manage tunnels…"), handler: tray.onManageTunnels, enabled: true, defawlt: true}, - {label: l18n.Sprintf("&Import tunnel(s) from file…"), handler: tray.onImport, enabled: true}, + {label: l18n.Sprintf("&Import tunnel(s) from file…"), handler: tray.onImport, enabled: true, hidden: !IsAdmin}, {separator: true}, {label: l18n.Sprintf("&About WireGuard…"), handler: tray.onAbout, enabled: true}, - {label: l18n.Sprintf("E&xit"), handler: onQuit, enabled: true}, + {label: l18n.Sprintf("E&xit"), handler: onQuit, enabled: true, hidden: !IsAdmin}, } { var action *walk.Action if item.separator { diff --git a/ui/tunnelspage.go b/ui/tunnelspage.go index 791007cf..e59e8166 100644 --- a/ui/tunnelspage.go +++ b/ui/tunnelspage.go @@ -76,6 +76,7 @@ func NewTunnelsPage() (*TunnelsPage, error) { tp.fillerContainer.SetLayout(hlayout) tp.fillerButton, _ = walk.NewPushButton(tp.fillerContainer) tp.fillerButton.SetMinMaxSize(walk.Size{200, 0}, walk.Size{200, 0}) + tp.fillerButton.SetVisible(IsAdmin) tp.fillerButton.Clicked().Attach(func() { if tp.fillerHandler != nil { tp.fillerHandler() @@ -105,6 +106,7 @@ func NewTunnelsPage() (*TunnelsPage, error) { }) editTunnel.SetText(l18n.Sprintf("&Edit")) editTunnel.Clicked().Attach(tp.onEditTunnel) + editTunnel.SetVisible(IsAdmin) disposables.Spare() @@ -133,6 +135,7 @@ func (tp *TunnelsPage) CreateToolbar() error { hlayout := walk.NewHBoxLayout() hlayout.SetMargins(walk.Margins{}) toolBarContainer.SetLayout(hlayout) + toolBarContainer.SetVisible(IsAdmin) if tp.listToolbar, err = walk.NewToolBarWithOrientationAndButtonStyle(toolBarContainer, walk.Horizontal, walk.ToolBarButtonImageBeforeText); err != nil { return err @@ -206,34 +209,40 @@ func (tp *TunnelsPage) CreateToolbar() error { importAction2.SetText(l18n.Sprintf("&Import tunnel(s) from file…")) importAction2.SetShortcut(walk.Shortcut{walk.ModControl, walk.KeyO}) importAction2.Triggered().Attach(tp.onImport) + importAction2.SetVisible(IsAdmin) contextMenu.Actions().Add(importAction2) tp.ShortcutActions().Add(importAction2) addAction2 := walk.NewAction() addAction2.SetText(l18n.Sprintf("Add &empty tunnel…")) addAction2.SetShortcut(walk.Shortcut{walk.ModControl, walk.KeyN}) addAction2.Triggered().Attach(tp.onAddTunnel) + addAction2.SetVisible(IsAdmin) contextMenu.Actions().Add(addAction2) tp.ShortcutActions().Add(addAction2) exportAction2 := walk.NewAction() exportAction2.SetText(l18n.Sprintf("Export all tunnels to &zip…")) exportAction2.Triggered().Attach(tp.onExportTunnels) + exportAction2.SetVisible(IsAdmin) contextMenu.Actions().Add(exportAction2) contextMenu.Actions().Add(walk.NewSeparatorAction()) editAction := walk.NewAction() editAction.SetText(l18n.Sprintf("Edit &selected tunnel…")) editAction.SetShortcut(walk.Shortcut{walk.ModControl, walk.KeyE}) + editAction.SetVisible(IsAdmin) editAction.Triggered().Attach(tp.onEditTunnel) contextMenu.Actions().Add(editAction) tp.ShortcutActions().Add(editAction) deleteAction2 := walk.NewAction() deleteAction2.SetText(l18n.Sprintf("&Remove selected tunnel(s)")) deleteAction2.SetShortcut(walk.Shortcut{0, walk.KeyDelete}) + deleteAction2.SetVisible(IsAdmin) deleteAction2.Triggered().Attach(tp.onDelete) contextMenu.Actions().Add(deleteAction2) tp.listView.ShortcutActions().Add(deleteAction2) selectAllAction := walk.NewAction() selectAllAction.SetText(l18n.Sprintf("Select &all")) selectAllAction.SetShortcut(walk.Shortcut{walk.ModControl, walk.KeyA}) + selectAllAction.SetVisible(IsAdmin) selectAllAction.Triggered().Attach(tp.onSelectAll) contextMenu.Actions().Add(selectAllAction) tp.listView.ShortcutActions().Add(selectAllAction) diff --git a/ui/ui.go b/ui/ui.go index 0279a8dd..637a1848 100644 --- a/ui/ui.go +++ b/ui/ui.go @@ -23,6 +23,7 @@ import ( var noTrayAvailable = false var shouldQuitManagerWhenExiting = false var startTime = time.Now() +var IsAdmin = false // A global, because this really is global for the process func RunUI() { runtime.LockOSThread() -- cgit v1.2.3-59-g8ed1b