diff --git a/cmd/cmd.go b/cmd/cmd.go index 9b9401d..c916b38 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -1,4 +1,4 @@ -// Copyright © 2018 Intel Corporation +// Copyright © 2019 Intel Corporation // // SPDX-License-Identifier: GPL-3.0-only @@ -13,6 +13,7 @@ import ( "strings" "github.com/clearlinux/clr-installer/log" + "github.com/clearlinux/clr-installer/proxy" ) // Output interface allows implementors to process the output from a @@ -23,15 +24,6 @@ type Output interface { type runLogger struct{} -var ( - httpsProxy string -) - -// SetHTTPSProxy defines the HTTPS_PROXY env var value for all the cmd executions -func SetHTTPSProxy(addr string) { - httpsProxy = addr -} - func (rl runLogger) Write(p []byte) (n int, err error) { for _, curr := range strings.Split(string(p), "\n") { if curr == "" { @@ -87,9 +79,11 @@ func run(sw func(cmd *exec.Cmd) error, writer io.Writer, env map[string]string, cmd := exec.Command(exe, cmdArgs...) - if httpsProxy != "" { - cmd.Env = append(cmd.Env, fmt.Sprintf("https_proxy=%s", httpsProxy)) + // Add any proxy environment variables + for _, pvar := range proxy.GetProxyValues() { + cmd.Env = append(cmd.Env, pvar) } + log.Debug("cmd.Env: %+v", cmd.Env) if sw != nil { if err := sw(cmd); err != nil { @@ -139,9 +133,11 @@ func RunAndProcessOutput(output Output, args ...string) error { cmd := exec.Command(exe, cmdArgs...) - if httpsProxy != "" { - cmd.Env = append(cmd.Env, fmt.Sprintf("https_proxy=%s", httpsProxy)) + // Add any proxy environment variables + for _, pvar := range proxy.GetProxyValues() { + cmd.Env = append(cmd.Env, pvar) } + log.Debug("cmd.Env: %+v", cmd.Env) stdout, err := cmd.StdoutPipe() if err != nil { diff --git a/controller/controller.go b/controller/controller.go index cd3945c..c3f080b 100644 --- a/controller/controller.go +++ b/controller/controller.go @@ -27,6 +27,7 @@ import ( "github.com/clearlinux/clr-installer/model" "github.com/clearlinux/clr-installer/network" "github.com/clearlinux/clr-installer/progress" + "github.com/clearlinux/clr-installer/proxy" "github.com/clearlinux/clr-installer/storage" "github.com/clearlinux/clr-installer/swupd" "github.com/clearlinux/clr-installer/telemetry" @@ -546,7 +547,7 @@ func ConfigureNetwork(model *model.SystemInstall) error { } func configureNetwork(model *model.SystemInstall) (progress.Progress, error) { - cmd.SetHTTPSProxy(model.HTTPSProxy) + proxy.SetHTTPSProxy(model.HTTPSProxy) if len(model.NetworkInterfaces) > 0 { msg := "Applying network settings" diff --git a/gui/gui.go b/gui/gui.go index 8330739..6533a92 100644 --- a/gui/gui.go +++ b/gui/gui.go @@ -93,6 +93,9 @@ func (gui *Gui) Run(md *model.SystemInstall, rootDir string, options args.Args) } gui.window = win + // Configure the Gnome proxy function + SetupGnomeProxy() + // Main loop gtk.Main() diff --git a/gui/proxy.go b/gui/proxy.go new file mode 100644 index 0000000..689dcc3 --- /dev/null +++ b/gui/proxy.go @@ -0,0 +1,162 @@ +// Copyright © 2019 Intel Corporation +// +// SPDX-License-Identifier: GPL-3.0-only + +package gui + +import ( + "fmt" + "io" + "os" + "os/exec" + "strings" + + "github.com/gotk3/gotk3/glib" + + "github.com/clearlinux/clr-installer/log" + "github.com/clearlinux/clr-installer/proxy" +) + +const ( + gProxySchema = "org.gnome.system.proxy" + dconfProxyDir = "/system/proxy/" + installerDefaultUID = "1000" +) + +// SetupGnomeProxy configures the Gnome proxy function +// in the proxy package +func SetupGnomeProxy() { + proxy.SetGetProxyValueFunc(GnomeGetProxyValue) + proxy.SetPreProxyFunc(SyncNetworkProxies) +} + +// GnomeGetProxyValue first check the Gnome network settings for +// proxy settings, then falls back to Bash environment variables +func GnomeGetProxyValue(prefix string) string { + result := "" + + gProxy := glib.SettingsNew(gProxySchema) + if gProxy != nil { + proxyMode := gProxy.GetString("mode") + log.Debug("Gnome Proxy Mode: %s", proxyMode) + + // TODO: Consider transferring these settings to the + // target install system + // dbus-run-session dconf dump /system/proxy/ > file_for_target + // Since these are user specific settings, we would need to find + // as way to import them for each interactive user created on + // the target system using some post installation hook + switch proxyMode { + case "none": + // No value to pull + case "manual": + if prefix == "no" { + noHosts := []string{} + hosts := gProxy.GetStrv("ignore-hosts") + if len(hosts) > 1 { + for _, host := range hosts { + if strings.Contains(host, "/") { + log.Debug("Skipping no_proxy hosts %q, no CIDR support", host) + } else { + noHosts = append(noHosts, host) + } + } + result = strings.Join(noHosts, ",") + } + } else { + gProxyPrefix := glib.SettingsNew(gProxySchema + "." + prefix) + if gProxyPrefix != nil { + host := gProxyPrefix.GetString("host") + if host != "" { + result = host + port := gProxyPrefix.GetInt("port") + if port != 0 { + result = result + fmt.Sprintf(":%d", port) + } + } + } + } + case "auto": + if prefix == "no" { + // no_proxy is handle by the wpad.dat script with + // connections which are DIRECT + } else { + autoProxyURL := gProxy.GetString("autoconfig-url") + if autoProxyURL != "" { + log.Debug("We should probably download and use %q", autoProxyURL) + // TODO: + // Overwrite the value from pacdiscovery? + // /run/pacrunner/wpad.dat + // Restart pacrunner? + } + } + default: + log.Warning("Unknown Gnome Proxy Mode: ", proxyMode) + } + } + + if result == "" { + value := os.Getenv(prefix + "_proxy") + if value != "" { + result = value + } + } + + return result +} + +// SyncNetworkProxies copies the current values from the Network Proxy +// for the non-privileged user to the root Gnome environment +func SyncNetworkProxies() { + // To avoid recursion, since this function is called as part of the standard + // cmd run, we have our only customer local exec function. + sudoUser := os.Getenv("SUDO_USER") // launched by sudo + tag := "sudo_user" + if sudoUser == "" { // no SUDO_USER defined + sudoUser = "#" + os.Getenv("PKEXEC_UID") // launched by pkexec (polkit) + tag = "PKEXEC_UID" + } + if sudoUser == "#" { // no PKEXEC_UID defined + sudoUser = "#" + installerDefaultUID // fallback + tag = "fallback UID" + } + log.Debug("sync user is %s=%s", tag, sudoUser) + + dumpCmd := exec.Command( + "sudo", fmt.Sprintf("--user=%s", sudoUser), + "dbus-run-session", "dconf", "dump", dconfProxyDir, + ) + loadCmd := exec.Command( + "dbus-run-session", "dconf", "load", dconfProxyDir, + ) + + reader, writer := io.Pipe() + + dumpCmd.Stdout = writer + loadCmd.Stdin = reader + + var err error + if err = dumpCmd.Start(); err == nil { + if err = loadCmd.Start(); err != nil { + log.Warning("Error starting dconf load: %v", err) + } + } else { + log.Warning("Error starting dconf dump: %v", err) + } + + if err = dumpCmd.Wait(); err == nil { + if err = writer.Close(); err != nil { + log.Warning("Error closing writer for dconf dump: %v", err) + } + } else { + log.Warning("Error waiting for dconf dump: %v", err) + } + + if err = loadCmd.Wait(); err == nil { + if err = reader.Close(); err != nil { + log.Warning("Error closing reader for dconf load: %v", err) + } + } else { + log.Warning("Error waiting for dconf load: %v", err) + } +} diff --git a/proxy/proxy.go b/proxy/proxy.go new file mode 100644 index 0000000..d923b52 --- /dev/null +++ b/proxy/proxy.go @@ -0,0 +1,85 @@ +// Copyright © 2019 Intel Corporation +// +// SPDX-License-Identifier: GPL-3.0-only + +package proxy + +import ( + "fmt" + "os" + "strings" + + "github.com/clearlinux/clr-installer/log" +) + +// GetProxyValueFunc is the type of the GetProxyValue function +type GetProxyValueFunc func(prefix string) string + +var ( + proxyPrefixes = [...]string{"ftp", "http", "https", "socks", "no"} + httpsProxy string + getProxyValueFunc GetProxyValueFunc + preProxyFunc func() +) + +// SetHTTPSProxy defines the HTTPS_PROXY env var value for all the cmd executions +func SetHTTPSProxy(addr string) { + log.Debug("proxy.SetHTTPSProxy = %s", addr) + httpsProxy = addr +} + +// SetPreProxyFunc save the function used to run before processing proxies +// This is currently used by Gnome UI to copy Network Proxy from install user +func SetPreProxyFunc(f func()) { + preProxyFunc = f +} + +// SetGetProxyValueFunc save the function used to return a string value +// for a Proxy based on the string prefix passed +func SetGetProxyValueFunc(f GetProxyValueFunc) { + getProxyValueFunc = f +} + +// GetProxyValues returns a set of environment variable for a Bash shell command +func GetProxyValues() []string { + values := []string{} + + if preProxyFunc != nil { + preProxyFunc() + } + + myGetProxyValueFunc := getProxyValueFunc + if myGetProxyValueFunc == nil { + myGetProxyValueFunc = DefaultGetProxyValue + } + + var value string + for _, prefix := range proxyPrefixes { + + if prefix == "https" && httpsProxy != "" { + value = httpsProxy + } else { + value = myGetProxyValueFunc(prefix) + } + + if value != "" { + values = append(values, fmt.Sprintf("%s_proxy=%s", prefix, value)) + + upperValue := os.Getenv(strings.ToUpper(prefix) + "_PROXY") + if upperValue != "" { + values = append(values, fmt.Sprintf("%s_PROXY=%s", strings.ToUpper(prefix), upperValue)) + } else { + values = append(values, fmt.Sprintf("%s_PROXY=%s", strings.ToUpper(prefix), value)) + } + } + } + + return values +} + +// DefaultGetProxyValue default implementation which only pulls from +// the current environment variables +func DefaultGetProxyValue(prefix string) string { + log.Debug("Using default shellProxy.DefaultGetProxyValue") + return os.Getenv(prefix + "_proxy") +}