github.com/hugh712/snapd@v0.0.0-20200910133618-1a99902bd583/overlord/configstate/configcore/services.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 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 configcore 21 22 import ( 23 "fmt" 24 "io/ioutil" 25 "os" 26 "path/filepath" 27 "time" 28 29 "github.com/snapcore/snapd/dirs" 30 "github.com/snapcore/snapd/osutil" 31 "github.com/snapcore/snapd/overlord/configstate/config" 32 "github.com/snapcore/snapd/systemd" 33 ) 34 35 var services = []struct{ configName, systemdName string }{ 36 {"ssh", "ssh.service"}, 37 {"rsyslog", "rsyslog.service"}, 38 {"console-conf", "console-conf@*"}, 39 } 40 41 func init() { 42 for _, service := range services { 43 s := fmt.Sprintf("core.service.%s.disable", service.configName) 44 supportedConfigurations[s] = true 45 } 46 } 47 48 type sysdLogger struct{} 49 50 func (l *sysdLogger) Notify(status string) { 51 fmt.Fprintf(Stderr, "sysd: %s\n", status) 52 } 53 54 // switchDisableSSHService handles the special case of disabling/enabling ssh 55 // service on core devices. 56 func switchDisableSSHService(sysd systemd.Systemd, serviceName string, disabled bool, opts *fsOnlyContext) error { 57 rootDir := dirs.GlobalRootDir 58 if opts != nil { 59 rootDir = opts.RootDir 60 if err := os.MkdirAll(filepath.Join(rootDir, "/etc/ssh"), 0755); err != nil { 61 return err 62 } 63 } 64 65 sshCanary := filepath.Join(rootDir, "/etc/ssh/sshd_not_to_be_run") 66 67 if disabled { 68 if err := ioutil.WriteFile(sshCanary, []byte("SSH has been disabled by snapd system configuration\n"), 0644); err != nil { 69 return err 70 } 71 if opts == nil { 72 return sysd.Stop(serviceName, 5*time.Minute) 73 } 74 } else { 75 err := os.Remove(sshCanary) 76 if err != nil && !os.IsNotExist(err) { 77 return err 78 } 79 // Unmask both sshd.service and ssh.service and ignore the 80 // errors, if any. This undoes the damage done by earlier 81 // versions of snapd. 82 sysd.Unmask("sshd.service") 83 sysd.Unmask("ssh.service") 84 if opts == nil { 85 return sysd.Start(serviceName) 86 } 87 } 88 return nil 89 } 90 91 // switchDisableConsoleConfService handles the special case of 92 // disabling/enabling console-conf on core devices. 93 // 94 // Note that this option can only be changed via gadget defaults. 95 // It is not possible to tune this at runtime 96 func switchDisableConsoleConfService(sysd systemd.Systemd, serviceName string, disabled bool, opts *fsOnlyContext) error { 97 consoleConfDisabled := "/var/lib/console-conf/complete" 98 99 // at runtime we can not change this setting 100 if opts == nil { 101 hasDisabledFile := osutil.FileExists(filepath.Join(dirs.GlobalRootDir, consoleConfDisabled)) 102 if disabled != hasDisabledFile { 103 return fmt.Errorf("cannot toggle console-conf at runtime, but only initially via gadget defaults") 104 } 105 return nil 106 } 107 108 if !disabled { 109 return nil 110 } 111 112 // disable console-conf at the gadget-defaults time 113 consoleConfDisabled = filepath.Join(opts.RootDir, consoleConfDisabled) 114 if err := os.MkdirAll(filepath.Dir(consoleConfDisabled), 0755); err != nil { 115 return err 116 } 117 if err := ioutil.WriteFile(consoleConfDisabled, []byte("console-conf has been disabled by the snapd system configuration\n"), 0644); err != nil { 118 return err 119 } 120 121 return nil 122 } 123 124 // switchDisableTypicalService switches a service in/out of disabled state 125 // where "true" means disabled and "false" means enabled. 126 func switchDisableService(serviceName string, disabled bool, opts *fsOnlyContext) error { 127 var sysd systemd.Systemd 128 if opts != nil { 129 sysd = systemd.NewEmulationMode(opts.RootDir) 130 } else { 131 sysd = systemd.New(dirs.GlobalRootDir, systemd.SystemMode, &sysdLogger{}) 132 } 133 134 // some services are special 135 switch serviceName { 136 case "ssh.service": 137 return switchDisableSSHService(sysd, serviceName, disabled, opts) 138 case "console-conf@*": 139 return switchDisableConsoleConfService(sysd, serviceName, disabled, opts) 140 } 141 142 if disabled { 143 if opts == nil { 144 if err := sysd.Disable(serviceName); err != nil { 145 return err 146 } 147 } 148 if err := sysd.Mask(serviceName); err != nil { 149 return err 150 } 151 if opts == nil { 152 return sysd.Stop(serviceName, 5*time.Minute) 153 } 154 } else { 155 if err := sysd.Unmask(serviceName); err != nil { 156 return err 157 } 158 if opts == nil { 159 if err := sysd.Enable(serviceName); err != nil { 160 return err 161 } 162 } 163 if opts == nil { 164 return sysd.Start(serviceName) 165 } 166 } 167 return nil 168 } 169 170 // services that can be disabled 171 func handleServiceDisableConfiguration(tr config.ConfGetter, opts *fsOnlyContext) error { 172 for _, service := range services { 173 optionName := fmt.Sprintf("service.%s.disable", service.configName) 174 outputStr, err := coreCfg(tr, optionName) 175 if err != nil { 176 return err 177 } 178 if outputStr != "" { 179 var disabled bool 180 switch outputStr { 181 case "true": 182 disabled = true 183 case "false": 184 disabled = false 185 default: 186 return fmt.Errorf("option %q has invalid value %q", optionName, outputStr) 187 } 188 189 if err := switchDisableService(service.systemdName, disabled, opts); err != nil { 190 return err 191 } 192 } 193 } 194 195 return nil 196 }