arblant
firefox-vpn-client / core / internal / tunservice / client_linux.go
client_linux.go53 lines · 1.4 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
package tunservice

import (
	"errors"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

// pkexec's exit statuses for the prompt (pkexec(1)).
const (
	pkexecDismissed     = 126
	pkexecNotAuthorized = 127
)

// runElevated runs this executable with args as root through pkexec,
// whose polkit prompt asks for the permission, and waits for it. polkit's
// prompt names the program, so prompt (macOS') is not used.
func runElevated(_ string, args ...string) error {
	self, err := os.Executable()
	if err != nil {
		return err
	}
	pkexec, err := exec.LookPath("pkexec")
	if err != nil {
		return errors.New("asking for the administrator permission needs pkexec (polkit), which is not found")
	}
	report, remove, err := reportFile()
	if err != nil {
		return err
	}
	defer remove()
	out, err := exec.Command(pkexec, append(append([]string{self}, args...), "-report", report)...).CombinedOutput()
	var exit *exec.ExitError
	if !errors.As(err, &exit) {
		return err
	}
	switch exit.ExitCode() {
	case pkexecDismissed:
		return ErrCancelled
	case pkexecNotAuthorized:
		if text := strings.TrimSpace(string(out)); text != "" {
			return fmt.Errorf("the administrator permission was refused: %s", text)
		}
		return errors.New("the administrator permission was refused")
	}
	if text := readReport(report); text != "" {
		return errors.New(text)
	}
	return fmt.Errorf("%s failed with exit code %d", filepath.Base(self), exit.ExitCode())
}