github.com/rigado/snapd@v2.42.5-go-mod+incompatible/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 "github.com/snapcore/snapd/asserts" 27 "github.com/snapcore/snapd/release" 28 "github.com/snapcore/snapd/snap" 29 "github.com/snapcore/snapd/strutil" 30 ) 31 32 // check helpers 33 34 func checkSnapType(snapInfo *snap.Info, types []string) error { 35 if len(types) == 0 { 36 return nil 37 } 38 snapType := snapInfo.GetType() 39 s := string(snapType) 40 if snapType == snap.TypeOS || snapType == snap.TypeSnapd { 41 // we use "core" in the assertions and we need also to 42 // allow for the "snapd" snap 43 s = "core" 44 } 45 for _, t := range types { 46 if t == s { 47 return nil 48 } 49 } 50 return fmt.Errorf("snap type does not match") 51 } 52 53 func checkID(kind, id string, ids []string, special map[string]string) error { 54 if len(ids) == 0 { 55 return nil 56 } 57 if id == "" { // unset values never match 58 return fmt.Errorf("%s does not match", kind) 59 } 60 for _, cand := range ids { 61 if strings.HasPrefix(cand, "$") { 62 cand = special[cand] 63 if cand == "" { // we ignore unknown special "ids" 64 continue 65 } 66 } 67 if id == cand { 68 return nil 69 } 70 } 71 return fmt.Errorf("%s does not match", kind) 72 } 73 74 func checkOnClassic(c *asserts.OnClassicConstraint) error { 75 if c == nil { 76 return nil 77 } 78 if c.Classic != release.OnClassic { 79 return fmt.Errorf("on-classic mismatch") 80 } 81 if c.Classic && len(c.SystemIDs) != 0 { 82 return checkID("operating system ID", release.ReleaseInfo.ID, c.SystemIDs, nil) 83 } 84 return nil 85 } 86 87 func checkDeviceScope(c *asserts.DeviceScopeConstraint, model *asserts.Model, store *asserts.Store) error { 88 if c == nil { 89 return nil 90 } 91 if model == nil { 92 return fmt.Errorf("cannot match on-store/on-brand/on-model without model") 93 } 94 if store != nil && store.Store() != model.Store() { 95 return fmt.Errorf("store assertion and model store must match") 96 } 97 if len(c.Store) != 0 { 98 if !strutil.ListContains(c.Store, model.Store()) { 99 mismatch := true 100 if store != nil { 101 for _, sto := range c.Store { 102 if strutil.ListContains(store.FriendlyStores(), sto) { 103 mismatch = false 104 break 105 } 106 } 107 } 108 if mismatch { 109 return fmt.Errorf("on-store mismatch") 110 } 111 } 112 } 113 if len(c.Brand) != 0 { 114 if !strutil.ListContains(c.Brand, model.BrandID()) { 115 return fmt.Errorf("on-brand mismatch") 116 } 117 } 118 if len(c.Model) != 0 { 119 brandModel := fmt.Sprintf("%s/%s", model.BrandID(), model.Model()) 120 if !strutil.ListContains(c.Model, brandModel) { 121 return fmt.Errorf("on-model mismatch") 122 } 123 } 124 return nil 125 } 126 127 func checkPlugConnectionConstraints1(connc *ConnectCandidate, cstrs *asserts.PlugConnectionConstraints) error { 128 if err := cstrs.PlugAttributes.Check(connc.Plug, connc); err != nil { 129 return err 130 } 131 if err := cstrs.SlotAttributes.Check(connc.Slot, connc); err != nil { 132 return err 133 } 134 if err := checkSnapType(connc.Slot.Snap(), cstrs.SlotSnapTypes); err != nil { 135 return err 136 } 137 if err := checkID("snap id", connc.slotSnapID(), cstrs.SlotSnapIDs, nil); err != nil { 138 return err 139 } 140 err := checkID("publisher id", connc.slotPublisherID(), cstrs.SlotPublisherIDs, map[string]string{ 141 "$PLUG_PUBLISHER_ID": connc.plugPublisherID(), 142 }) 143 if err != nil { 144 return err 145 } 146 if err := checkOnClassic(cstrs.OnClassic); err != nil { 147 return err 148 } 149 if err := checkDeviceScope(cstrs.DeviceScope, connc.Model, connc.Store); err != nil { 150 return err 151 } 152 return nil 153 } 154 155 func checkPlugConnectionConstraints(connc *ConnectCandidate, cstrs []*asserts.PlugConnectionConstraints) error { 156 var firstErr error 157 // OR of constraints 158 for _, cstrs1 := range cstrs { 159 err := checkPlugConnectionConstraints1(connc, cstrs1) 160 if err == nil { 161 return nil 162 } 163 if firstErr == nil { 164 firstErr = err 165 } 166 } 167 return firstErr 168 } 169 170 func checkSlotConnectionConstraints1(connc *ConnectCandidate, cstrs *asserts.SlotConnectionConstraints) error { 171 if err := cstrs.PlugAttributes.Check(connc.Plug, connc); err != nil { 172 return err 173 } 174 if err := cstrs.SlotAttributes.Check(connc.Slot, connc); err != nil { 175 return err 176 } 177 if err := checkSnapType(connc.Plug.Snap(), cstrs.PlugSnapTypes); err != nil { 178 return err 179 } 180 if err := checkID("snap id", connc.plugSnapID(), cstrs.PlugSnapIDs, nil); err != nil { 181 return err 182 } 183 err := checkID("publisher id", connc.plugPublisherID(), cstrs.PlugPublisherIDs, map[string]string{ 184 "$SLOT_PUBLISHER_ID": connc.slotPublisherID(), 185 }) 186 if err != nil { 187 return err 188 } 189 if err := checkOnClassic(cstrs.OnClassic); err != nil { 190 return err 191 } 192 if err := checkDeviceScope(cstrs.DeviceScope, connc.Model, connc.Store); err != nil { 193 return err 194 } 195 return nil 196 } 197 198 func checkSlotConnectionConstraints(connc *ConnectCandidate, cstrs []*asserts.SlotConnectionConstraints) error { 199 var firstErr error 200 // OR of constraints 201 for _, cstrs1 := range cstrs { 202 err := checkSlotConnectionConstraints1(connc, cstrs1) 203 if err == nil { 204 return nil 205 } 206 if firstErr == nil { 207 firstErr = err 208 } 209 } 210 return firstErr 211 } 212 213 func checkSnapTypeSlotInstallationConstraints1(ic *InstallCandidateMinimalCheck, slot *snap.SlotInfo, cstrs *asserts.SlotInstallationConstraints) error { 214 if err := checkSnapType(slot.Snap, cstrs.SlotSnapTypes); err != nil { 215 return err 216 } 217 if err := checkOnClassic(cstrs.OnClassic); err != nil { 218 return err 219 } 220 return nil 221 } 222 223 func checkMinimalSlotInstallationConstraints(ic *InstallCandidateMinimalCheck, slot *snap.SlotInfo, cstrs []*asserts.SlotInstallationConstraints) (bool, error) { 224 var firstErr error 225 var hasSnapTypeConstraints bool 226 // OR of constraints 227 for _, cstrs1 := range cstrs { 228 if cstrs1.OnClassic == nil && len(cstrs1.SlotSnapTypes) == 0 { 229 continue 230 } 231 hasSnapTypeConstraints = true 232 err := checkSnapTypeSlotInstallationConstraints1(ic, slot, cstrs1) 233 if err == nil { 234 return true, nil 235 } 236 if firstErr == nil { 237 firstErr = err 238 } 239 } 240 return hasSnapTypeConstraints, firstErr 241 } 242 243 func checkSlotInstallationConstraints1(ic *InstallCandidate, slot *snap.SlotInfo, cstrs *asserts.SlotInstallationConstraints) error { 244 // TODO: allow evaluated attr constraints here too? 245 if err := cstrs.SlotAttributes.Check(slot, nil); err != nil { 246 return err 247 } 248 if err := checkSnapType(slot.Snap, cstrs.SlotSnapTypes); err != nil { 249 return err 250 } 251 if err := checkOnClassic(cstrs.OnClassic); err != nil { 252 return err 253 } 254 if err := checkDeviceScope(cstrs.DeviceScope, ic.Model, ic.Store); err != nil { 255 return err 256 } 257 return nil 258 } 259 260 func checkSlotInstallationConstraints(ic *InstallCandidate, slot *snap.SlotInfo, cstrs []*asserts.SlotInstallationConstraints) error { 261 var firstErr error 262 // OR of constraints 263 for _, cstrs1 := range cstrs { 264 err := checkSlotInstallationConstraints1(ic, slot, cstrs1) 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, cstrs *asserts.PlugInstallationConstraints) error { 276 // TODO: allow evaluated attr constraints here too? 277 if err := cstrs.PlugAttributes.Check(plug, nil); err != nil { 278 return err 279 } 280 if err := checkSnapType(plug.Snap, cstrs.PlugSnapTypes); err != nil { 281 return err 282 } 283 if err := checkOnClassic(cstrs.OnClassic); err != nil { 284 return err 285 } 286 if err := checkDeviceScope(cstrs.DeviceScope, ic.Model, ic.Store); err != nil { 287 return err 288 } 289 return nil 290 } 291 292 func checkPlugInstallationConstraints(ic *InstallCandidate, plug *snap.PlugInfo, cstrs []*asserts.PlugInstallationConstraints) error { 293 var firstErr error 294 // OR of constraints 295 for _, cstrs1 := range cstrs { 296 err := checkPlugInstallationConstraints1(ic, plug, cstrs1) 297 if err == nil { 298 return nil 299 } 300 if firstErr == nil { 301 firstErr = err 302 } 303 } 304 return firstErr 305 }