gitee.com/mysnapcore/mysnapd@v0.1.0/interfaces/dbus/backend.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2016 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 dbus implements interaction between snappy and dbus. 21 // 22 // Snappy creates dbus configuration files that describe how various 23 // services on the system bus can communicate with other peers. 24 // 25 // Each configuration is an XML file containing <busconfig>...</busconfig>. 26 // Particular security snippets define whole <policy>...</policy> entires. 27 // This is explained in detail in https://dbus.freedesktop.org/doc/dbus-daemon.1.html 28 package dbus 29 30 import ( 31 "bytes" 32 "fmt" 33 "os" 34 "path/filepath" 35 36 "gitee.com/mysnapcore/mysnapd/dirs" 37 "gitee.com/mysnapcore/mysnapd/interfaces" 38 "gitee.com/mysnapcore/mysnapd/logger" 39 "gitee.com/mysnapcore/mysnapd/osutil" 40 "gitee.com/mysnapcore/mysnapd/release" 41 "gitee.com/mysnapcore/mysnapd/snap" 42 "gitee.com/mysnapcore/mysnapd/snapdtool" 43 "gitee.com/mysnapcore/mysnapd/timings" 44 "gitee.com/mysnapcore/mysnapd/wrappers" 45 ) 46 47 // Backend is responsible for maintaining DBus policy files. 48 type Backend struct{} 49 50 // Initialize does nothing. 51 func (b *Backend) Initialize(*interfaces.SecurityBackendOptions) error { 52 return nil 53 } 54 55 // Name returns the name of the backend. 56 func (b *Backend) Name() interfaces.SecuritySystem { 57 return "dbus" 58 } 59 60 func shouldCopyConfigFiles(snapInfo *snap.Info) bool { 61 // Only copy config files on classic distros 62 if !release.OnClassic { 63 return false 64 } 65 // Only copy config files if we have been reexecuted 66 if reexecd, _ := snapdtool.IsReexecd(); !reexecd { 67 return false 68 } 69 switch snapInfo.Type() { 70 case snap.TypeOS: 71 // XXX: ugly but we need to make sure that the content 72 // of the "snapd" snap wins 73 // 74 // TODO: this is also racy but the content of the 75 // files in core and snapd is identical. Cleanup 76 // after link-snap and setup-profiles are unified 77 return !osutil.FileExists(filepath.Join(snapInfo.MountDir(), "../..", "snapd/current")) 78 case snap.TypeSnapd: 79 return true 80 default: 81 return false 82 } 83 } 84 85 // setupDbusServiceForUserd will setup the service file for the new 86 // `snap userd` instance on re-exec 87 func setupDbusServiceForUserd(snapInfo *snap.Info) error { 88 coreOrSnapdRoot := snapInfo.MountDir() 89 90 for _, srv := range []string{ 91 "io.snapcraft.Launcher.service", 92 "io.snapcraft.Prompt.service", 93 "io.snapcraft.Settings.service", 94 } { 95 dst := filepath.Join("/usr/share/dbus-1/services/", srv) 96 src := filepath.Join(coreOrSnapdRoot, dst) 97 98 // we only need the GlobalRootDir for testing 99 dst = filepath.Join(dirs.GlobalRootDir, dst) 100 if !osutil.FilesAreEqual(src, dst) { 101 if err := osutil.CopyFile(src, dst, osutil.CopyFlagPreserveAll); err != nil { 102 return err 103 } 104 } 105 } 106 return nil 107 } 108 109 func setupHostDBusConf(snapInfo *snap.Info) error { 110 sessionContent, systemContent, err := wrappers.DeriveSnapdDBusConfig(snapInfo) 111 if err != nil { 112 return err 113 } 114 115 // We don't use `dirs.SnapDBusSessionPolicyDir because we want 116 // to match the path the package on the host system uses. 117 dest := filepath.Join(dirs.GlobalRootDir, "/usr/share/dbus-1/session.d") 118 if err = os.MkdirAll(dest, 0755); err != nil { 119 return err 120 } 121 _, _, err = osutil.EnsureDirState(dest, "snapd.*.conf", sessionContent) 122 if err != nil { 123 return err 124 } 125 126 dest = filepath.Join(dirs.GlobalRootDir, "/usr/share/dbus-1/system.d") 127 if err = os.MkdirAll(dest, 0755); err != nil { 128 return err 129 } 130 _, _, err = osutil.EnsureDirState(dest, "snapd.*.conf", systemContent) 131 if err != nil { 132 return err 133 } 134 135 return nil 136 } 137 138 // Setup creates dbus configuration files specific to a given snap. 139 // 140 // DBus has no concept of a complain mode so confinment type is ignored. 141 func (b *Backend) Setup(snapInfo *snap.Info, opts interfaces.ConfinementOptions, repo *interfaces.Repository, tm timings.Measurer) error { 142 snapName := snapInfo.InstanceName() 143 // Get the snippets that apply to this snap 144 spec, err := repo.SnapSpecification(b.Name(), snapName) 145 if err != nil { 146 return fmt.Errorf("cannot obtain dbus specification for snap %q: %s", snapName, err) 147 } 148 149 // copy some config files when installing core/snapd if we reexec 150 if shouldCopyConfigFiles(snapInfo) { 151 if err := setupDbusServiceForUserd(snapInfo); err != nil { 152 logger.Noticef("cannot create host `snap userd` dbus service file: %s", err) 153 } 154 // TODO: Make this conditional on the dbus-activation 155 // feature flag. 156 if err := setupHostDBusConf(snapInfo); err != nil { 157 logger.Noticef("cannot create host dbus config: %s", err) 158 } 159 } 160 161 // Get the files that this snap should have 162 content := b.deriveContent(spec.(*Specification), snapInfo) 163 164 glob := fmt.Sprintf("%s.conf", interfaces.SecurityTagGlob(snapName)) 165 dir := dirs.SnapDBusSystemPolicyDir 166 if err := os.MkdirAll(dir, 0755); err != nil { 167 return fmt.Errorf("cannot create directory for DBus configuration files %q: %s", dir, err) 168 } 169 _, _, err = osutil.EnsureDirState(dir, glob, content) 170 if err != nil { 171 return fmt.Errorf("cannot synchronize DBus configuration files for snap %q: %s", snapName, err) 172 } 173 return nil 174 } 175 176 // Remove removes dbus configuration files of a given snap. 177 // 178 // This method should be called after removing a snap. 179 func (b *Backend) Remove(snapName string) error { 180 glob := fmt.Sprintf("%s.conf", interfaces.SecurityTagGlob(snapName)) 181 _, _, err := osutil.EnsureDirState(dirs.SnapDBusSystemPolicyDir, glob, nil) 182 if err != nil { 183 return fmt.Errorf("cannot synchronize DBus configuration files for snap %q: %s", snapName, err) 184 } 185 return nil 186 } 187 188 // deriveContent combines security snippets collected from all the interfaces 189 // affecting a given snap into a content map applicable to EnsureDirState. 190 func (b *Backend) deriveContent(spec *Specification, snapInfo *snap.Info) (content map[string]osutil.FileState) { 191 for _, appInfo := range snapInfo.Apps { 192 securityTag := appInfo.SecurityTag() 193 appSnippets := spec.SnippetForTag(securityTag) 194 if appSnippets == "" { 195 continue 196 } 197 if content == nil { 198 content = make(map[string]osutil.FileState) 199 } 200 201 addContent(securityTag, appSnippets, content) 202 } 203 204 for _, hookInfo := range snapInfo.Hooks { 205 securityTag := hookInfo.SecurityTag() 206 hookSnippets := spec.SnippetForTag(securityTag) 207 if hookSnippets == "" { 208 continue 209 } 210 if content == nil { 211 content = make(map[string]osutil.FileState) 212 } 213 214 addContent(securityTag, hookSnippets, content) 215 } 216 217 return content 218 } 219 220 func addContent(securityTag string, snippet string, content map[string]osutil.FileState) { 221 var buffer bytes.Buffer 222 buffer.Write(xmlHeader) 223 buffer.WriteString(snippet) 224 buffer.Write(xmlFooter) 225 226 content[fmt.Sprintf("%s.conf", securityTag)] = &osutil.MemoryFileState{ 227 Content: buffer.Bytes(), 228 Mode: 0644, 229 } 230 } 231 232 func (b *Backend) NewSpecification() interfaces.Specification { 233 return &Specification{} 234 } 235 236 // SandboxFeatures returns list of features supported by snapd for dbus communication. 237 func (b *Backend) SandboxFeatures() []string { 238 return []string{"mediated-bus-access"} 239 }