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