gitee.com/mysnapcore/mysnapd@v0.1.0/interfaces/policy/policy.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 implements the declaration based policy checks for 21 // connecting or permitting installation of snaps based on their slots 22 // and plugs. 23 package policy 24 25 import ( 26 "fmt" 27 28 "gitee.com/mysnapcore/mysnapd/asserts" 29 "gitee.com/mysnapcore/mysnapd/interfaces" 30 "gitee.com/mysnapcore/mysnapd/snap" 31 ) 32 33 // InstallCandidate represents a candidate snap for installation. 34 type InstallCandidate struct { 35 Snap *snap.Info 36 SnapDeclaration *asserts.SnapDeclaration 37 38 BaseDeclaration *asserts.BaseDeclaration 39 40 Model *asserts.Model 41 Store *asserts.Store 42 } 43 44 func (ic *InstallCandidate) snapID() string { 45 if ic.SnapDeclaration != nil { 46 return ic.SnapDeclaration.SnapID() 47 } 48 return "" // never a valid snap-id 49 } 50 51 func (ic *InstallCandidate) checkSlotRule(slot *snap.SlotInfo, rule *asserts.SlotRule, snapRule bool) error { 52 context := "" 53 if snapRule { 54 context = fmt.Sprintf(" for %q snap", ic.SnapDeclaration.SnapName()) 55 } 56 if checkSlotInstallationAltConstraints(ic, slot, rule.DenyInstallation) == nil { 57 return fmt.Errorf("installation denied by %q slot rule of interface %q%s", slot.Name, slot.Interface, context) 58 } 59 if checkSlotInstallationAltConstraints(ic, slot, rule.AllowInstallation) != nil { 60 return fmt.Errorf("installation not allowed by %q slot rule of interface %q%s", slot.Name, slot.Interface, context) 61 } 62 return nil 63 } 64 65 func (ic *InstallCandidate) checkPlugRule(plug *snap.PlugInfo, rule *asserts.PlugRule, snapRule bool) error { 66 context := "" 67 if snapRule { 68 context = fmt.Sprintf(" for %q snap", ic.SnapDeclaration.SnapName()) 69 } 70 if checkPlugInstallationAltConstraints(ic, plug, rule.DenyInstallation) == nil { 71 return fmt.Errorf("installation denied by %q plug rule of interface %q%s", plug.Name, plug.Interface, context) 72 } 73 if checkPlugInstallationAltConstraints(ic, plug, rule.AllowInstallation) != nil { 74 return fmt.Errorf("installation not allowed by %q plug rule of interface %q%s", plug.Name, plug.Interface, context) 75 } 76 return nil 77 } 78 79 func (ic *InstallCandidate) checkSlot(slot *snap.SlotInfo) error { 80 iface := slot.Interface 81 if snapDecl := ic.SnapDeclaration; snapDecl != nil { 82 if rule := snapDecl.SlotRule(iface); rule != nil { 83 return ic.checkSlotRule(slot, rule, true) 84 } 85 } 86 if rule := ic.BaseDeclaration.SlotRule(iface); rule != nil { 87 return ic.checkSlotRule(slot, rule, false) 88 } 89 return nil 90 } 91 92 func (ic *InstallCandidate) checkPlug(plug *snap.PlugInfo) error { 93 iface := plug.Interface 94 if snapDecl := ic.SnapDeclaration; snapDecl != nil { 95 if rule := snapDecl.PlugRule(iface); rule != nil { 96 return ic.checkPlugRule(plug, rule, true) 97 } 98 } 99 if rule := ic.BaseDeclaration.PlugRule(iface); rule != nil { 100 return ic.checkPlugRule(plug, rule, false) 101 } 102 return nil 103 } 104 105 // Check checks whether the installation is allowed. 106 func (ic *InstallCandidate) Check() error { 107 if ic.BaseDeclaration == nil { 108 return fmt.Errorf("internal error: improperly initialized InstallCandidate") 109 } 110 111 for _, slot := range ic.Snap.Slots { 112 err := ic.checkSlot(slot) 113 if err != nil { 114 return err 115 } 116 } 117 118 for _, plug := range ic.Snap.Plugs { 119 err := ic.checkPlug(plug) 120 if err != nil { 121 return err 122 } 123 } 124 125 return nil 126 } 127 128 // ConnectCandidate represents a candidate connection. 129 type ConnectCandidate struct { 130 Plug *interfaces.ConnectedPlug 131 PlugSnapDeclaration *asserts.SnapDeclaration 132 133 Slot *interfaces.ConnectedSlot 134 SlotSnapDeclaration *asserts.SnapDeclaration 135 136 BaseDeclaration *asserts.BaseDeclaration 137 138 Model *asserts.Model 139 Store *asserts.Store 140 } 141 142 func nestedGet(which string, attrs interfaces.Attrer, path string) (interface{}, error) { 143 val, ok := attrs.Lookup(path) 144 if !ok { 145 return nil, fmt.Errorf("%s attribute %q not found", which, path) 146 } 147 return val, nil 148 } 149 150 func (connc *ConnectCandidate) PlugAttr(arg string) (interface{}, error) { 151 return nestedGet("plug", connc.Plug, arg) 152 } 153 154 func (connc *ConnectCandidate) SlotAttr(arg string) (interface{}, error) { 155 return nestedGet("slot", connc.Slot, arg) 156 } 157 158 func (connc *ConnectCandidate) plugSnapID() string { 159 if connc.PlugSnapDeclaration != nil { 160 return connc.PlugSnapDeclaration.SnapID() 161 } 162 return "" // never a valid snap-id 163 } 164 165 func (connc *ConnectCandidate) slotSnapID() string { 166 if connc.SlotSnapDeclaration != nil { 167 return connc.SlotSnapDeclaration.SnapID() 168 } 169 return "" // never a valid snap-id 170 } 171 172 func (connc *ConnectCandidate) plugPublisherID() string { 173 if connc.PlugSnapDeclaration != nil { 174 return connc.PlugSnapDeclaration.PublisherID() 175 } 176 return "" // never a valid publisher-id 177 } 178 179 func (connc *ConnectCandidate) slotPublisherID() string { 180 if connc.SlotSnapDeclaration != nil { 181 return connc.SlotSnapDeclaration.PublisherID() 182 } 183 return "" // never a valid publisher-id 184 } 185 186 func (connc *ConnectCandidate) checkPlugRule(kind string, rule *asserts.PlugRule, snapRule bool) (interfaces.SideArity, error) { 187 context := "" 188 if snapRule { 189 context = fmt.Sprintf(" for %q snap", connc.PlugSnapDeclaration.SnapName()) 190 } 191 denyConst := rule.DenyConnection 192 allowConst := rule.AllowConnection 193 if kind == "auto-connection" { 194 denyConst = rule.DenyAutoConnection 195 allowConst = rule.AllowAutoConnection 196 } 197 if _, err := checkPlugConnectionAltConstraints(connc, denyConst); err == nil { 198 return nil, fmt.Errorf("%s denied by plug rule of interface %q%s", kind, connc.Plug.Interface(), context) 199 } 200 201 allowedConstraints, err := checkPlugConnectionAltConstraints(connc, allowConst) 202 if err != nil { 203 return nil, fmt.Errorf("%s not allowed by plug rule of interface %q%s", kind, connc.Plug.Interface(), context) 204 } 205 return sideArity{allowedConstraints.SlotsPerPlug}, nil 206 } 207 208 func (connc *ConnectCandidate) checkSlotRule(kind string, rule *asserts.SlotRule, snapRule bool) (interfaces.SideArity, error) { 209 context := "" 210 if snapRule { 211 context = fmt.Sprintf(" for %q snap", connc.SlotSnapDeclaration.SnapName()) 212 } 213 denyConst := rule.DenyConnection 214 allowConst := rule.AllowConnection 215 if kind == "auto-connection" { 216 denyConst = rule.DenyAutoConnection 217 allowConst = rule.AllowAutoConnection 218 } 219 if _, err := checkSlotConnectionAltConstraints(connc, denyConst); err == nil { 220 return nil, fmt.Errorf("%s denied by slot rule of interface %q%s", kind, connc.Plug.Interface(), context) 221 } 222 223 allowedConstraints, err := checkSlotConnectionAltConstraints(connc, allowConst) 224 if err != nil { 225 return nil, fmt.Errorf("%s not allowed by slot rule of interface %q%s", kind, connc.Plug.Interface(), context) 226 } 227 return sideArity{allowedConstraints.SlotsPerPlug}, nil 228 } 229 230 func (connc *ConnectCandidate) check(kind string) (interfaces.SideArity, error) { 231 baseDecl := connc.BaseDeclaration 232 if baseDecl == nil { 233 return nil, fmt.Errorf("internal error: improperly initialized ConnectCandidate") 234 } 235 236 iface := connc.Plug.Interface() 237 238 if connc.Slot.Interface() != iface { 239 return nil, fmt.Errorf("cannot connect mismatched plug interface %q to slot interface %q", iface, connc.Slot.Interface()) 240 } 241 242 if plugDecl := connc.PlugSnapDeclaration; plugDecl != nil { 243 if rule := plugDecl.PlugRule(iface); rule != nil { 244 return connc.checkPlugRule(kind, rule, true) 245 } 246 } 247 if slotDecl := connc.SlotSnapDeclaration; slotDecl != nil { 248 if rule := slotDecl.SlotRule(iface); rule != nil { 249 return connc.checkSlotRule(kind, rule, true) 250 } 251 } 252 if rule := baseDecl.PlugRule(iface); rule != nil { 253 return connc.checkPlugRule(kind, rule, false) 254 } 255 if rule := baseDecl.SlotRule(iface); rule != nil { 256 return connc.checkSlotRule(kind, rule, false) 257 } 258 return nil, nil 259 } 260 261 // Check checks whether the connection is allowed. 262 func (connc *ConnectCandidate) Check() error { 263 _, err := connc.check("connection") 264 return err 265 } 266 267 // CheckAutoConnect checks whether the connection is allowed to auto-connect. 268 func (connc *ConnectCandidate) CheckAutoConnect() (interfaces.SideArity, error) { 269 arity, err := connc.check("auto-connection") 270 if err != nil { 271 return nil, err 272 } 273 if arity == nil { 274 // shouldn't happen but be safe, the callers should be able 275 // to assume arity to be non nil 276 arity = sideArity{asserts.SideArityConstraint{N: 1}} 277 } 278 return arity, nil 279 } 280 281 // InstallCandidateMinimalCheck represents a candidate snap installed with --dangerous flag that should pass minimum checks 282 // against snap type (if present). It doesn't check interface attributes. 283 type InstallCandidateMinimalCheck struct { 284 Snap *snap.Info 285 BaseDeclaration *asserts.BaseDeclaration 286 Model *asserts.Model 287 Store *asserts.Store 288 } 289 290 func (ic *InstallCandidateMinimalCheck) checkSlotRule(slot *snap.SlotInfo, rule *asserts.SlotRule) error { 291 if hasConstraints, err := checkMinimalSlotInstallationAltConstraints(slot, rule.DenyInstallation); hasConstraints && err == nil { 292 return fmt.Errorf("installation denied by %q slot rule of interface %q", slot.Name, slot.Interface) 293 } 294 295 // TODO check that the snap is an app or gadget if allow-installation had no slot-snap-type constraints 296 if _, err := checkMinimalSlotInstallationAltConstraints(slot, rule.AllowInstallation); err != nil { 297 return fmt.Errorf("installation not allowed by %q slot rule of interface %q", slot.Name, slot.Interface) 298 } 299 return nil 300 } 301 302 func (ic *InstallCandidateMinimalCheck) checkSlot(slot *snap.SlotInfo) error { 303 iface := slot.Interface 304 if rule := ic.BaseDeclaration.SlotRule(iface); rule != nil { 305 return ic.checkSlotRule(slot, rule) 306 } 307 return nil 308 } 309 310 // Check checks whether the installation is allowed. 311 func (ic *InstallCandidateMinimalCheck) Check() error { 312 if ic.BaseDeclaration == nil { 313 return fmt.Errorf("internal error: improperly initialized InstallCandidateMinimalCheck") 314 } 315 316 for _, slot := range ic.Snap.Slots { 317 err := ic.checkSlot(slot) 318 if err != nil { 319 return err 320 } 321 } 322 323 return nil 324 }