diff --git a/bin/dde-system-daemon/power.go b/bin/dde-system-daemon/power.go index 528697af6..47d940218 100644 --- a/bin/dde-system-daemon/power.go +++ b/bin/dde-system-daemon/power.go @@ -28,6 +28,10 @@ const ( dsettingsPowerName = "org.deepin.dde.daemon.power" dsettingsIdleStatePath = "idleStatePath" dsettingsIdleScreenStatePath = "idleScreenStatePath" + + // polkit action ids used by checkAuth for SetIdleState / SetScreenState + actionSetIdleState = "org.deepin.dde.daemon.set-idle-state" + actionSetScreenState = "org.deepin.dde.daemon.set-screen-state" ) func isStrInList(item string, items []string) bool { @@ -172,12 +176,20 @@ func (d *Daemon) setState(file string, state bool) error { return nil } -func (d *Daemon) SetIdleState(state bool) *dbus.Error { +func (d *Daemon) SetIdleState(sender dbus.Sender, state bool) *dbus.Error { + err := checkAuth(actionSetIdleState, string(sender)) + if err != nil { + return dbusutil.ToError(err) + } logger.Infof("SetIdleState %s try set state: %v", d.idleStatePath, state) return dbusutil.ToError(d.setState(d.idleStatePath, state)) } -func (d *Daemon) SetScreenState(state bool) *dbus.Error { +func (d *Daemon) SetScreenState(sender dbus.Sender, state bool) *dbus.Error { + err := checkAuth(actionSetScreenState, string(sender)) + if err != nil { + return dbusutil.ToError(err) + } logger.Infof("SetScreenState %s try set state: %v", d.idleScreenStatePath, state) return dbusutil.ToError(d.setState(d.idleScreenStatePath, state)) } diff --git a/misc/polkit-action/org.deepin.dde.daemon.system.policy.in b/misc/polkit-action/org.deepin.dde.daemon.system.policy.in index e12eecb97..bda2ac11b 100644 --- a/misc/polkit-action/org.deepin.dde.daemon.system.policy.in +++ b/misc/polkit-action/org.deepin.dde.daemon.system.policy.in @@ -24,5 +24,23 @@ auth_admin + + Set short idle state + Authentication is required to set the short idle state + + no + no + yes + + + + Set screen idle state + Authentication is required to set the screen idle state + + no + no + yes + + diff --git a/misc/polkit-action/org.deepin.dde.inputdevices.policy b/misc/polkit-action/org.deepin.dde.inputdevices.policy new file mode 100644 index 000000000..e8523c759 --- /dev/null +++ b/misc/polkit-action/org.deepin.dde.inputdevices.policy @@ -0,0 +1,19 @@ + + + + LinuxDeepin + https://www.deepin.com/ + + + Enable or disable the touchpad + Authentication is required to enable or disable the touchpad + + no + no + yes + + + + diff --git a/misc/polkit-action/org.deepin.dde.power.policy b/misc/polkit-action/org.deepin.dde.power.policy index 418e0aff4..5ecaf5b12 100644 --- a/misc/polkit-action/org.deepin.dde.power.policy +++ b/misc/polkit-action/org.deepin.dde.power.policy @@ -27,4 +27,22 @@ Check Authentication Tämän toiminnon suorittaminen edellyttää todennusta + + Set short idle state + Authentication is required to set the short idle state + + no + no + yes + + + + Set TLP power mode + Authentication is required to set the TLP power mode + + no + no + yes + + diff --git a/misc/polkit-rules/org.deepin.dde.inputdevices.rules b/misc/polkit-rules/org.deepin.dde.inputdevices.rules new file mode 100644 index 000000000..a026c88b1 --- /dev/null +++ b/misc/polkit-rules/org.deepin.dde.inputdevices.rules @@ -0,0 +1,12 @@ +polkit.addRule(function(action, subject) { + // Allow root internal callers (e.g. keyevent1 running inside + // dde-system-daemon invoking org.deepin.dde.InputDevices1.Touchpad + // .SetTouchpadEnable over the system bus) to toggle the touchpad. + // Root has no active local session, so the allow_active:yes default in + // the .policy does not match and would otherwise fall back to + // allow_any:no and silently deny the call. + if (action.id === "org.deepin.dde.inputdevices.set-touchpad-enable" && + subject.user === "root") { + return polkit.Result.YES; + } +}); diff --git a/misc/polkit-rules/org.deepin.dde.power.rules b/misc/polkit-rules/org.deepin.dde.power.rules new file mode 100644 index 000000000..44e620ea6 --- /dev/null +++ b/misc/polkit-rules/org.deepin.dde.power.rules @@ -0,0 +1,11 @@ +polkit.addRule(function(action, subject) { + // Allow root internal callers (e.g. dde-system-daemon invoking + // org.deepin.dde.Power1.SetShortIdleState over the system bus) to set + // the short idle state. Root has no active local session, so the + // allow_active:yes default in the .policy does not match and would + // otherwise fall back to allow_any:no and silently deny the call. + if (action.id === "org.deepin.dde.power.set-short-idle-state" && + subject.user === "root") { + return polkit.Result.YES; + } +}); diff --git a/system/inputdevices1/daemon.go b/system/inputdevices1/daemon.go index 364e4f47f..2edb7d451 100644 --- a/system/inputdevices1/daemon.go +++ b/system/inputdevices1/daemon.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2018 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -16,6 +16,9 @@ const ( dbusServiceName = "org.deepin.dde.InputDevices1" dbusPath = "/org/deepin/dde/InputDevices1" dbusInterface = dbusServiceName + + // polkit action id used by checkAuthorization for SetTouchpadEnable + actionSetTouchpadEnable = "org.deepin.dde.inputdevices.set-touchpad-enable" ) func init() { diff --git a/system/inputdevices1/inputdevices_ifc.go b/system/inputdevices1/inputdevices_ifc.go index 2e13291fb..6d4e96372 100644 --- a/system/inputdevices1/inputdevices_ifc.go +++ b/system/inputdevices1/inputdevices_ifc.go @@ -1,11 +1,14 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2018 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later package inputdevices1 import ( + "errors" + "github.com/godbus/dbus/v5" + polkit "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.policykit1" "github.com/linuxdeepin/go-lib/dbusutil" ) @@ -13,3 +16,27 @@ func (m *InputDevices) SetWakeupDevices(sender dbus.Sender, path string, value s err := m.setWakeupDevices(path, value) return dbusutil.ToError(err) } + +// checkAuthorization verifies that the caller identified by sysBusName is +// allowed to perform the polkit action identified by actionId. It mirrors +// the pattern used by system/airplane_mode1 so that active local users are +// allowed without an authentication dialog (allow_active: yes). +func checkAuthorization(actionId string, sysBusName string) error { + systemBus, err := dbus.SystemBus() + if err != nil { + return err + } + authority := polkit.NewAuthority(systemBus) + subject := polkit.MakeSubject(polkit.SubjectKindSystemBusName) + subject.SetDetail("name", sysBusName) + + ret, err := authority.CheckAuthorization(0, subject, actionId, + nil, polkit.CheckAuthorizationFlagsAllowUserInteraction, "") + if err != nil { + return err + } + if !ret.IsAuthorized { + return errors.New("not authorized") + } + return nil +} diff --git a/system/inputdevices1/touchpad.go b/system/inputdevices1/touchpad.go index 6f1a77993..5d4329522 100644 --- a/system/inputdevices1/touchpad.go +++ b/system/inputdevices1/touchpad.go @@ -79,8 +79,13 @@ func (t *Touchpad) handleDeviceChange(devices []string) { logger.Infof("touchpad devices updated: %d device(s)", len(devices)) } -func (t *Touchpad) SetTouchpadEnable(enabled bool) *dbus.Error { - err := t.setTouchpadEnable(enabled) +func (t *Touchpad) SetTouchpadEnable(sender dbus.Sender, enabled bool) *dbus.Error { + err := checkAuthorization(actionSetTouchpadEnable, string(sender)) + if err != nil { + logger.Warningf("checkAuthorization failed, err: %v, actionId=%v", err, actionSetTouchpadEnable) + return dbusutil.ToError(err) + } + err = t.setTouchpadEnable(enabled) return dbusutil.ToError(err) } diff --git a/system/power1/manager_ifc.go b/system/power1/manager_ifc.go index 4e663d136..9ff425ee7 100644 --- a/system/power1/manager_ifc.go +++ b/system/power1/manager_ifc.go @@ -9,6 +9,7 @@ import ( "fmt" dbus "github.com/godbus/dbus/v5" + polkit "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.policykit1" "github.com/linuxdeepin/go-lib/dbusutil" ) @@ -16,6 +17,10 @@ const ( dbusServiceName = "org.deepin.dde.Power1" dbusPath = "/org/deepin/dde/Power1" dbusInterface = dbusServiceName + + // polkit action ids used by checkAuthorization for the Power1 setters + actionSetTlpMode = "org.deepin.dde.power.set-tlp-mode" + actionSetShortIdleState = "org.deepin.dde.power.set-short-idle-state" ) func (*Manager) GetInterfaceName() string { @@ -106,13 +111,23 @@ func (m *Manager) SetMode(mode string) *dbus.Error { return nil } -func (m *Manager) SetTlpMode(mode string) *dbus.Error { +func (m *Manager) SetTlpMode(sender dbus.Sender, mode string) *dbus.Error { logger.Info("SetTlpMode : ", mode) + err := checkAuthorization(actionSetTlpMode, string(sender)) + if err != nil { + logger.Warningf("checkAuthorization failed, err: %v, actionId=%v", err, actionSetTlpMode) + return dbusutil.ToError(err) + } return dbusutil.ToError(m.setTlpMode(mode)) } -func (m *Manager) SetShortIdleState(state bool) *dbus.Error { +func (m *Manager) SetShortIdleState(sender dbus.Sender, state bool) *dbus.Error { logger.Info(" SetShortIdleState : ", state) + err := checkAuthorization(actionSetShortIdleState, string(sender)) + if err != nil { + logger.Warningf("checkAuthorization failed, err: %v, actionId=%v", err, actionSetShortIdleState) + return dbusutil.ToError(err) + } m.setShortIdleState(state) return nil } @@ -141,3 +156,27 @@ func (m *Manager) LockCpuFreq(governor string, lockTime int32) *dbus.Error { return nil } + +// checkAuthorization verifies that the caller identified by sysBusName is +// allowed to perform the polkit action identified by actionId. It mirrors +// the pattern used by system/airplane_mode1 so that active local users are +// allowed without an authentication dialog (allow_active: yes). +func checkAuthorization(actionId string, sysBusName string) error { + systemBus, err := dbus.SystemBus() + if err != nil { + return err + } + authority := polkit.NewAuthority(systemBus) + subject := polkit.MakeSubject(polkit.SubjectKindSystemBusName) + subject.SetDetail("name", sysBusName) + + ret, err := authority.CheckAuthorization(0, subject, actionId, + nil, polkit.CheckAuthorizationFlagsAllowUserInteraction, "") + if err != nil { + return err + } + if !ret.IsAuthorized { + return errors.New("not authorized") + } + return nil +}