Authorize enabling insecure mode with PolicyKit on Linux

This commit is contained in:
世界
2026-09-08 23:05:12 +08:00
parent 046c46eacb
commit 6d1fc214c1
6 changed files with 60 additions and 56 deletions
@@ -7,6 +7,7 @@ import (
"crypto/rand"
"encoding/hex"
"math"
"os"
"strconv"
E "github.com/sagernet/sing/common/exceptions"
@@ -17,11 +18,12 @@ import (
)
const (
policyKitService = "org.freedesktop.PolicyKit1"
policyKitAuthorityPath = dbus.ObjectPath("/org/freedesktop/PolicyKit1/Authority")
policyKitAuthorityInterface = "org.freedesktop.PolicyKit1.Authority"
policyKitTakeOverAction = "io.nekohasekai.sfl.take-over-service"
policyKitAllowUserInteraction = uint32(1)
policyKitService = "org.freedesktop.PolicyKit1"
policyKitAuthorityPath = dbus.ObjectPath("/org/freedesktop/PolicyKit1/Authority")
policyKitAuthorityInterface = "org.freedesktop.PolicyKit1.Authority"
policyKitTakeOverAction = "io.nekohasekai.sfl.take-over-service"
policyKitSetInsecureModeAction = "io.nekohasekai.sfl.set-insecure-mode"
policyKitAllowUserInteraction = uint32(1)
)
type policyKitSubject struct {
@@ -36,6 +38,27 @@ type policyKitAuthorizationResult struct {
}
func authorizeTakeOver(ctx context.Context, identity peerIdentity) error {
return checkPolicyKitAuthorization(ctx, identity, policyKitTakeOverAction)
}
func authorizeSetInsecureMode(ctx context.Context, identity peerIdentity, enabled bool) error {
if enabled {
return checkPolicyKitAuthorization(ctx, identity, policyKitSetInsecureModeAction)
}
ownerUserID, err := loadOwner()
if err != nil {
if os.IsNotExist(err) {
return status.Error(codes.PermissionDenied, "the service has no owner")
}
return err
}
if ownerUserID != identity.UserID {
return status.Error(codes.PermissionDenied, "the service is owned by another user")
}
return nil
}
func checkPolicyKitAuthorization(ctx context.Context, identity peerIdentity, action string) error {
if listenAddress != "" {
return nil
}
@@ -72,7 +95,7 @@ func authorizeTakeOver(ctx context.Context, identity peerIdentity) error {
0,
resultChannel,
subject,
policyKitTakeOverAction,
action,
map[string]string{},
policyKitAllowUserInteraction,
cancellationID,
@@ -88,7 +111,10 @@ func authorizeTakeOver(ctx context.Context, identity peerIdentity) error {
return E.Cause(err, "read PolicyKit authorization result")
}
if !result.Authorized {
return status.Error(codes.PermissionDenied, "take over authorization was denied")
if result.Challenge {
return status.Error(codes.Unauthenticated, "no authentication agent is available")
}
return status.Error(codes.PermissionDenied, "authorization was denied")
}
return nil
case <-ctx.Done():
@@ -97,6 +123,6 @@ func authorizeTakeOver(ctx context.Context, identity peerIdentity) error {
0,
cancellationID,
).Err
return status.Error(codes.Canceled, "take over authorization was canceled")
return status.Error(codes.Canceled, "authorization was canceled")
}
}
+21
View File
@@ -0,0 +1,21 @@
//go:build !linux
package main
import (
"context"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
func authorizeTakeOver(ctx context.Context, identity peerIdentity) error {
return nil
}
func authorizeSetInsecureMode(ctx context.Context, identity peerIdentity, enabled bool) error {
if enabled {
return status.Error(codes.PermissionDenied, "enabling insecure mode requires an elevated service command")
}
return nil
}
@@ -1,9 +0,0 @@
//go:build !linux
package main
import "context"
func authorizeTakeOver(ctx context.Context, identity peerIdentity) error {
return nil
}
+5 -8
View File
@@ -247,26 +247,23 @@ func (s *desktopService) SetInsecureModeEnabled(ctx context.Context, request *Se
if !insecureModeAvailable() {
return nil, status.Error(codes.FailedPrecondition, "insecure mode is not available on this platform")
}
if request.Enabled {
return nil, status.Error(codes.PermissionDenied, "enabling insecure mode requires an elevated service command")
err = authorizeSetInsecureMode(ctx, identity, request.Enabled)
if err != nil {
return nil, err
}
s.daemon.lifecycleAccess.Lock()
defer s.daemon.lifecycleAccess.Unlock()
if s.daemon.closed {
return nil, os.ErrClosed
}
err = authorizeDisableInsecureMode(identity)
if err != nil {
return nil, err
}
wasEnabled := s.daemon.insecureModeEnabled()
err = updateDaemonSettings(workingDirectory, func(settings *daemonSettings) {
settings.InsecureModeEnabled = false
settings.InsecureModeEnabled = request.Enabled
})
if err != nil {
return nil, err
}
if wasEnabled && s.daemon.startedService.Instance() != nil {
if wasEnabled && !request.Enabled && s.daemon.startedService.Instance() != nil {
var ownerUserID string
ownerUserID, err = loadOwner()
if err != nil {
@@ -1,24 +0,0 @@
//go:build linux
package main
import (
"os"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
func authorizeDisableInsecureMode(identity peerIdentity) error {
ownerUserID, err := loadOwner()
if err != nil {
if os.IsNotExist(err) {
return status.Error(codes.PermissionDenied, "the service has no owner")
}
return err
}
if ownerUserID != identity.UserID {
return status.Error(codes.PermissionDenied, "the service is owned by another user")
}
return nil
}
@@ -1,7 +0,0 @@
//go:build !linux
package main
func authorizeDisableInsecureMode(identity peerIdentity) error {
return nil
}