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  }