gitee.com/mysnapcore/mysnapd@v0.1.0/interfaces/builtin/polkit.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2021 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package builtin 21 22 import ( 23 "bytes" 24 "fmt" 25 "io/ioutil" 26 "path/filepath" 27 "strings" 28 29 "gitee.com/mysnapcore/mysnapd/interfaces" 30 "gitee.com/mysnapcore/mysnapd/interfaces/polkit" 31 "gitee.com/mysnapcore/mysnapd/osutil" 32 "gitee.com/mysnapcore/mysnapd/polkit/validate" 33 "gitee.com/mysnapcore/mysnapd/snap" 34 ) 35 36 const polkitSummary = `allows access to polkitd to check authorisation` 37 38 const polkitBaseDeclarationPlugs = ` 39 polkit: 40 allow-installation: false 41 deny-auto-connection: true 42 ` 43 44 const polkitBaseDeclarationSlots = ` 45 polkit: 46 allow-installation: 47 slot-snap-type: 48 - core 49 deny-auto-connection: true 50 ` 51 52 const polkitConnectedPlugAppArmor = ` 53 # Description: Can talk to polkitd's CheckAuthorization API 54 55 #include <abstractions/dbus-strict> 56 57 dbus (send) 58 bus=system 59 path="/org/freedesktop/PolicyKit1/Authority" 60 interface="org.freedesktop.PolicyKit1.Authority" 61 member="{,Cancel}CheckAuthorization" 62 peer=(name="org.freedesktop.PolicyKit1", label=unconfined), 63 dbus (send) 64 bus=system 65 path="/org/freedesktop/PolicyKit1/Authority" 66 interface="org.freedesktop.DBus.Properties" 67 peer=(name="org.freedesktop.PolicyKit1", label=unconfined), 68 dbus (send) 69 bus=system 70 path="/org/freedesktop/PolicyKit1/Authority" 71 interface="org.freedesktop.DBus.Introspectable" 72 member="Introspect" 73 peer=(name="org.freedesktop.PolicyKit1", label=unconfined), 74 ` 75 76 type polkitInterface struct { 77 commonInterface 78 } 79 80 func (iface *polkitInterface) getActionPrefix(attribs interfaces.Attrer) (string, error) { 81 var prefix string 82 if err := attribs.Attr("action-prefix", &prefix); err != nil { 83 return "", err 84 } 85 if err := interfaces.ValidateDBusBusName(prefix); err != nil { 86 return "", fmt.Errorf("plug has invalid action-prefix: %q", prefix) 87 } 88 return prefix, nil 89 } 90 91 func loadPolkitPolicy(filename, actionPrefix string) (polkit.Policy, error) { 92 content, err := ioutil.ReadFile(filename) 93 if err != nil { 94 return nil, fmt.Errorf(`cannot read file %q: %v`, filename, err) 95 } 96 97 // Check that the file content is a valid polkit policy file 98 actionIDs, err := validate.ValidatePolicy(bytes.NewReader(content)) 99 if err != nil { 100 return nil, fmt.Errorf(`cannot validate policy file %q: %v`, filename, err) 101 } 102 103 // Check that the action IDs in the policy file match the action prefix 104 for _, id := range actionIDs { 105 if id != actionPrefix && !strings.HasPrefix(id, actionPrefix+".") { 106 return nil, fmt.Errorf(`policy file %q contains unexpected action ID %q`, filename, id) 107 } 108 } 109 110 return polkit.Policy(content), nil 111 } 112 113 func (iface *polkitInterface) PolkitConnectedPlug(spec *polkit.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error { 114 actionPrefix, err := iface.getActionPrefix(plug) 115 if err != nil { 116 return err 117 } 118 119 mountDir := plug.Snap().MountDir() 120 policyFiles, err := filepath.Glob(filepath.Join(mountDir, "meta", "polkit", plug.Name()+".*.policy")) 121 if err != nil { 122 return err 123 } 124 if len(policyFiles) == 0 { 125 return fmt.Errorf("cannot find any policy files for plug %q", plug.Name()) 126 } 127 for _, filename := range policyFiles { 128 suffix := strings.TrimSuffix(filepath.Base(filename), ".policy") 129 policy, err := loadPolkitPolicy(filename, actionPrefix) 130 if err != nil { 131 return err 132 } 133 if err := spec.AddPolicy(suffix, policy); err != nil { 134 return err 135 } 136 } 137 return nil 138 } 139 140 func (iface *polkitInterface) BeforePreparePlug(plug *snap.PlugInfo) error { 141 _, err := iface.getActionPrefix(plug) 142 return err 143 } 144 145 func init() { 146 registerIface(&polkitInterface{ 147 commonInterface{ 148 name: "polkit", 149 summary: polkitSummary, 150 implicitOnCore: osutil.IsExecutable("/usr/libexec/polkitd"), 151 implicitOnClassic: true, 152 baseDeclarationPlugs: polkitBaseDeclarationPlugs, 153 baseDeclarationSlots: polkitBaseDeclarationSlots, 154 connectedPlugAppArmor: polkitConnectedPlugAppArmor, 155 }, 156 }) 157 }