gitee.com/mysnapcore/mysnapd@v0.1.0/interfaces/policy/helpers.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2016-2017 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 policy 21 22 import ( 23 "fmt" 24 "strings" 25 26 "gitee.com/mysnapcore/mysnapd/asserts" 27 "gitee.com/mysnapcore/mysnapd/release" 28 "gitee.com/mysnapcore/mysnapd/snap" 29 ) 30 31 // check helpers 32 33 func checkSnapType(snapInfo *snap.Info, types []string) error { 34 if len(types) == 0 { 35 return nil 36 } 37 snapType := snapInfo.Type() 38 s := string(snapType) 39 if snapType == snap.TypeOS || snapType == snap.TypeSnapd { 40 // we use "core" in the assertions and we need also to 41 // allow for the "snapd" snap 42 s = "core" 43 } 44 for _, t := range types { 45 if t == s { 46 return nil 47 } 48 } 49 return fmt.Errorf("snap type does not match") 50 } 51 52 func checkID(kind, id string, ids []string, special map[string]string) error { 53 if len(ids) == 0 { 54 return nil 55 } 56 if id == "" { // unset values never match 57 return fmt.Errorf("%s does not match", kind) 58 } 59 for _, cand := range ids { 60 if strings.HasPrefix(cand, "$") { 61 cand = special[cand] 62 if cand == "" { // we ignore unknown special "ids" 63 continue 64 } 65 } 66 if id == cand { 67 return nil 68 } 69 } 70 return fmt.Errorf("%s does not match", kind) 71 } 72 73 func checkOnClassic(c *asserts.OnClassicConstraint) error { 74 if c == nil { 75 return nil 76 } 77 if c.Classic != release.OnClassic { 78 return fmt.Errorf("on-classic mismatch") 79 } 80 if c.Classic && len(c.SystemIDs) != 0 { 81 return checkID("operating system ID", release.ReleaseInfo.ID, c.SystemIDs, nil) 82 } 83 return nil 84 } 85 86 func checkDeviceScope(c *asserts.DeviceScopeConstraint, model *asserts.Model, store *asserts.Store) error { 87 if c == nil { 88 return nil 89 } 90 opts := asserts.DeviceScopeConstraintCheckOptions{ 91 UseFriendlyStores: true, 92 } 93 return c.Check(model, store, &opts) 94 } 95 96 func checkNameConstraints(c *asserts.NameConstraints, iface, which, name string) error { 97 if c == nil { 98 return nil 99 } 100 special := map[string]string{ 101 "$INTERFACE": iface, 102 } 103 return c.Check(which, name, special) 104 } 105 106 func checkPlugConnectionConstraints1(connc *ConnectCandidate, constraints *asserts.PlugConnectionConstraints) error { 107 if err := checkNameConstraints(constraints.PlugNames, connc.Plug.Interface(), "plug name", connc.Plug.Name()); err != nil { 108 return err 109 } 110 if err := checkNameConstraints(constraints.SlotNames, connc.Slot.Interface(), "slot name", connc.Slot.Name()); err != nil { 111 return err 112 } 113 114 if err := constraints.PlugAttributes.Check(connc.Plug, connc); err != nil { 115 return err 116 } 117 if err := constraints.SlotAttributes.Check(connc.Slot, connc); err != nil { 118 return err 119 } 120 if err := checkSnapType(connc.Slot.Snap(), constraints.SlotSnapTypes); err != nil { 121 return err 122 } 123 if err := checkID("snap id", connc.slotSnapID(), constraints.SlotSnapIDs, nil); err != nil { 124 return err 125 } 126 err := checkID("publisher id", connc.slotPublisherID(), constraints.SlotPublisherIDs, map[string]string{ 127 "$PLUG_PUBLISHER_ID": connc.plugPublisherID(), 128 }) 129 if err != nil { 130 return err 131 } 132 if err := checkOnClassic(constraints.OnClassic); err != nil { 133 return err 134 } 135 if err := checkDeviceScope(constraints.DeviceScope, connc.Model, connc.Store); err != nil { 136 return err 137 } 138 return nil 139 } 140 141 func checkPlugConnectionAltConstraints(connc *ConnectCandidate, altConstraints []*asserts.PlugConnectionConstraints) (*asserts.PlugConnectionConstraints, error) { 142 var firstErr error 143 // OR of constraints 144 for _, constraints := range altConstraints { 145 err := checkPlugConnectionConstraints1(connc, constraints) 146 if err == nil { 147 return constraints, nil 148 } 149 if firstErr == nil { 150 firstErr = err 151 } 152 } 153 return nil, firstErr 154 } 155 156 func checkSlotConnectionConstraints1(connc *ConnectCandidate, constraints *asserts.SlotConnectionConstraints) error { 157 if err := checkNameConstraints(constraints.PlugNames, connc.Plug.Interface(), "plug name", connc.Plug.Name()); err != nil { 158 return err 159 } 160 if err := checkNameConstraints(constraints.SlotNames, connc.Slot.Interface(), "slot name", connc.Slot.Name()); err != nil { 161 return err 162 } 163 164 if err := constraints.PlugAttributes.Check(connc.Plug, connc); err != nil { 165 return err 166 } 167 if err := constraints.SlotAttributes.Check(connc.Slot, connc); err != nil { 168 return err 169 } 170 if err := checkSnapType(connc.Plug.Snap(), constraints.PlugSnapTypes); err != nil { 171 return err 172 } 173 if err := checkID("snap id", connc.plugSnapID(), constraints.PlugSnapIDs, nil); err != nil { 174 return err 175 } 176 err := checkID("publisher id", connc.plugPublisherID(), constraints.PlugPublisherIDs, map[string]string{ 177 "$SLOT_PUBLISHER_ID": connc.slotPublisherID(), 178 }) 179 if err != nil { 180 return err 181 } 182 if err := checkOnClassic(constraints.OnClassic); err != nil { 183 return err 184 } 185 if err := checkDeviceScope(constraints.DeviceScope, connc.Model, connc.Store); err != nil { 186 return err 187 } 188 return nil 189 } 190 191 func checkSlotConnectionAltConstraints(connc *ConnectCandidate, altConstraints []*asserts.SlotConnectionConstraints) (*asserts.SlotConnectionConstraints, error) { 192 var firstErr error 193 // OR of constraints 194 for _, constraints := range altConstraints { 195 err := checkSlotConnectionConstraints1(connc, constraints) 196 if err == nil { 197 return constraints, nil 198 } 199 if firstErr == nil { 200 firstErr = err 201 } 202 } 203 return nil, firstErr 204 } 205 206 func checkSnapTypeSlotInstallationConstraints1(slot *snap.SlotInfo, constraints *asserts.SlotInstallationConstraints) error { 207 if err := checkSnapType(slot.Snap, constraints.SlotSnapTypes); err != nil { 208 return err 209 } 210 if err := checkOnClassic(constraints.OnClassic); err != nil { 211 return err 212 } 213 return nil 214 } 215 216 func checkMinimalSlotInstallationAltConstraints(slot *snap.SlotInfo, altConstraints []*asserts.SlotInstallationConstraints) (bool, error) { 217 var firstErr error 218 var hasSnapTypeConstraints bool 219 // OR of constraints 220 for _, constraints := range altConstraints { 221 if constraints.OnClassic == nil && len(constraints.SlotSnapTypes) == 0 { 222 continue 223 } 224 hasSnapTypeConstraints = true 225 err := checkSnapTypeSlotInstallationConstraints1(slot, constraints) 226 if err == nil { 227 return true, nil 228 } 229 if firstErr == nil { 230 firstErr = err 231 } 232 } 233 return hasSnapTypeConstraints, firstErr 234 } 235 236 func checkSlotInstallationConstraints1(ic *InstallCandidate, slot *snap.SlotInfo, constraints *asserts.SlotInstallationConstraints) error { 237 if err := checkNameConstraints(constraints.SlotNames, slot.Interface, "slot name", slot.Name); err != nil { 238 return err 239 } 240 241 // TODO: allow evaluated attr constraints here too? 242 if err := constraints.SlotAttributes.Check(slot, nil); err != nil { 243 return err 244 } 245 if err := checkSnapType(slot.Snap, constraints.SlotSnapTypes); err != nil { 246 return err 247 } 248 if err := checkID("snap id", ic.snapID(), constraints.SlotSnapIDs, nil); err != nil { 249 return err 250 } 251 if err := checkOnClassic(constraints.OnClassic); err != nil { 252 return err 253 } 254 if err := checkDeviceScope(constraints.DeviceScope, ic.Model, ic.Store); err != nil { 255 return err 256 } 257 return nil 258 } 259 260 func checkSlotInstallationAltConstraints(ic *InstallCandidate, slot *snap.SlotInfo, altConstraints []*asserts.SlotInstallationConstraints) error { 261 var firstErr error 262 // OR of constraints 263 for _, constraints := range altConstraints { 264 err := checkSlotInstallationConstraints1(ic, slot, constraints) 265 if err == nil { 266 return nil 267 } 268 if firstErr == nil { 269 firstErr = err 270 } 271 } 272 return firstErr 273 } 274 275 func checkPlugInstallationConstraints1(ic *InstallCandidate, plug *snap.PlugInfo, constraints *asserts.PlugInstallationConstraints) error { 276 if err := checkNameConstraints(constraints.PlugNames, plug.Interface, "plug name", plug.Name); err != nil { 277 return err 278 } 279 280 // TODO: allow evaluated attr constraints here too? 281 if err := constraints.PlugAttributes.Check(plug, nil); err != nil { 282 return err 283 } 284 if err := checkSnapType(plug.Snap, constraints.PlugSnapTypes); err != nil { 285 return err 286 } 287 if err := checkID("snap id", ic.snapID(), constraints.PlugSnapIDs, nil); err != nil { 288 return err 289 } 290 if err := checkOnClassic(constraints.OnClassic); err != nil { 291 return err 292 } 293 if err := checkDeviceScope(constraints.DeviceScope, ic.Model, ic.Store); err != nil { 294 return err 295 } 296 return nil 297 } 298 299 func checkPlugInstallationAltConstraints(ic *InstallCandidate, plug *snap.PlugInfo, altConstraints []*asserts.PlugInstallationConstraints) error { 300 var firstErr error 301 // OR of constraints 302 for _, constraints := range altConstraints { 303 err := checkPlugInstallationConstraints1(ic, plug, constraints) 304 if err == nil { 305 return nil 306 } 307 if firstErr == nil { 308 firstErr = err 309 } 310 } 311 return firstErr 312 } 313 314 // sideArity carries relevant arity constraints for successful 315 // allow-auto-connection rules. It implements policy.SideArity. 316 // ATM only slots-per-plug might have an interesting non-default 317 // value. 318 // See: https://forum.snapcraft.io/t/plug-slot-declaration-rules-greedy-plugs/12438 319 type sideArity struct { 320 slotsPerPlug asserts.SideArityConstraint 321 } 322 323 func (a sideArity) SlotsPerPlugOne() bool { 324 return a.slotsPerPlug.N == 1 325 } 326 327 func (a sideArity) SlotsPerPlugAny() bool { 328 return a.slotsPerPlug.Any() 329 }