gitee.com/mysnapcore/mysnapd@v0.1.0/interfaces/builtin/daemon_notify.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2018 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 builtin 21 22 import ( 23 "fmt" 24 "os" 25 "strings" 26 27 "gitee.com/mysnapcore/mysnapd/interfaces" 28 "gitee.com/mysnapcore/mysnapd/interfaces/apparmor" 29 apparmor_sandbox "gitee.com/mysnapcore/mysnapd/sandbox/apparmor" 30 ) 31 32 const daemonNotifySummary = `allows sending daemon status changes to service manager` 33 34 const daemonNotifyBaseDeclarationSlots = ` 35 daemon-notify: 36 allow-installation: 37 slot-snap-type: 38 - core 39 deny-auto-connection: true 40 ` 41 42 const daemonNotifyConnectedPlugAppArmorTemplate = ` 43 # Allow sending notification messages to systemd through the notify socket 44 {{notify-socket-rule}}, 45 46 # Allow using systemd-notify in shell scripts. 47 /{,usr/}bin/systemd-notify ixr, 48 ` 49 50 type daemoNotifyInterface struct { 51 commonInterface 52 } 53 54 var osGetenv = os.Getenv 55 56 func (iface *daemoNotifyInterface) AppArmorConnectedPlug(spec *apparmor.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error { 57 // If the system has defined it, use NOTIFY_SOCKET from the environment. Note 58 // this is safe because it is examined on snapd start and snaps cannot manipulate 59 // the environment of snapd. 60 notifySocket := osGetenv("NOTIFY_SOCKET") 61 if notifySocket == "" { 62 notifySocket = "/run/systemd/notify" 63 } 64 if !strings.HasPrefix(notifySocket, "/") && !strings.HasPrefix(notifySocket, "@") { 65 // must be an absolute path or an abstract socket path 66 return fmt.Errorf("cannot use %q as notify socket path: not absolute", notifySocket) 67 } 68 if err := apparmor_sandbox.ValidateNoAppArmorRegexp(notifySocket); err != nil { 69 return fmt.Errorf("cannot use %q as notify socket path: %s", notifySocket, err) 70 } 71 72 var rule string 73 74 switch { 75 case strings.HasPrefix(notifySocket, "/"): 76 rule = fmt.Sprintf(`"%s" w`, notifySocket) 77 case strings.HasPrefix(notifySocket, "@/org/freedesktop/systemd1/notify/"): 78 // special case for Ubuntu 14.04 where the manpage states that 79 // /run/systemd/notify is used, but in fact the services get an 80 // abstract socket path such as 81 // @/org/freedesktop/systemd1/notify/13334051644891137417, the 82 // last part changing with each reboot 83 rule = `unix (connect, send) type=dgram peer=(label=unconfined,addr="@/org/freedesktop/systemd1/notify/[0-9]*")` 84 case strings.HasPrefix(notifySocket, "@"): 85 rule = fmt.Sprintf(`unix (connect, send) type=dgram peer=(label=unconfined,addr="%s")`, notifySocket) 86 default: 87 return fmt.Errorf("cannot use %q as notify socket path", notifySocket) 88 } 89 90 snippet := strings.Replace(daemonNotifyConnectedPlugAppArmorTemplate, 91 "{{notify-socket-rule}}", rule, 1) 92 spec.AddSnippet(snippet) 93 return nil 94 } 95 96 func init() { 97 registerIface(&daemoNotifyInterface{commonInterface: commonInterface{ 98 name: "daemon-notify", 99 summary: daemonNotifySummary, 100 implicitOnCore: true, 101 implicitOnClassic: true, 102 baseDeclarationSlots: daemonNotifyBaseDeclarationSlots, 103 }}) 104 }