// Copyright 2018 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// This tool tries to prohibit access to tools on the system on which the build
// is run.
//
// The rationale is that if the build uses a binary that is not shipped in the
// source tree, it is unknowable which version of that binary will be installed
// and therefore the output of the build will be unpredictable. Therefore, we
// should make every effort to use only tools under our control.
//
// This is currently implemented by a "sandbox" that sets $PATH to a specific,
// single directory and creates a symlink for every binary in $PATH in it. That
// symlink will point to path_interposer, which then uses an embedded
// configuration to determine whether to allow access to the binary (in which
// case it calls the original executable) or not (in which case it fails). It
// can also optionally log invocations.
//
// This, of course, does not help if one invokes the tool in question with its
// full path.
package main

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"syscall"

	"android/soong/ui/build/paths"
)

func main() {
	interposer, err := os.Executable()
	if err != nil {
		fmt.Fprintln(os.Stderr, "Unable to locate interposer executable:", err)
		os.Exit(1)
	}

	if fi, err := os.Lstat(interposer); err == nil {
		if fi.Mode()&os.ModeSymlink != 0 {
			link, err := os.Readlink(interposer)
			if err != nil {
				fmt.Fprintln(os.Stderr, "Unable to read link to interposer executable:", err)
				os.Exit(1)
			}
			if filepath.IsAbs(link) {
				interposer = link
			} else {
				interposer = filepath.Join(filepath.Dir(interposer), link)
			}
		}
	} else {
		fmt.Fprintln(os.Stderr, "Unable to stat interposer executable:", err)
		os.Exit(1)
	}

	exitCode, err := Main(os.Stdout, os.Stderr, interposer, os.Args, mainOpts{
		sendLog:       paths.SendLog,
		config:        paths.GetConfig,
		lookupParents: lookupParents,
	})
	if err != nil {
		fmt.Fprintln(os.Stderr, err.Error())
	}
	os.Exit(exitCode)
}

var usage = fmt.Errorf(`To use the PATH interposer:
 * Write the original PATH variable to <interposer>_origpath
 * Set up a directory of symlinks to the PATH interposer, and use that in PATH

If a tool isn't in the allowed list, a log will be posted to the unix domain
socket at <interposer>_log.`)

type mainOpts struct {
	sendLog       func(logSocket string, entry *paths.LogEntry, done chan interface{})
	config        func(name string) paths.PathConfig
	lookupParents func() []paths.LogProcess
}

func Main(stdout, stderr io.Writer, interposer string, args []string, opts mainOpts) (int, error) {
	base := filepath.Base(args[0])

	origPathFile := interposer + "_origpath"
	if base == filepath.Base(interposer) {
		return 1, usage
	}

	origPath, err := ioutil.ReadFile(origPathFile)
	if err != nil {
		if os.IsNotExist(err) {
			return 1, usage
		} else {
			return 1, fmt.Errorf("Failed to read original PATH: %v", err)
		}
	}

	cmd := &exec.Cmd{
		Args: args,
		Env:  os.Environ(),

		Stdin:  os.Stdin,
		Stdout: stdout,
		Stderr: stderr,
	}

	if err := os.Setenv("PATH", string(origPath)); err != nil {
		return 1, fmt.Errorf("Failed to set PATH env: %v", err)
	}

	if config := opts.config(base); config.Log || config.Error {
		var procs []paths.LogProcess
		if opts.lookupParents != nil {
			procs = opts.lookupParents()
		}

		if opts.sendLog != nil {
			waitForLog := make(chan interface{})
			opts.sendLog(interposer+"_log", &paths.LogEntry{
				Basename: base,
				Args:     args,
				Parents:  procs,
			}, waitForLog)
			defer func() { <-waitForLog }()
		}
		if config.Error {
			return 1, fmt.Errorf("%q is not allowed to be used. See https://android.googlesource.com/platform/build/+/main/Changes.md#PATH_Tools for more information.", base)
		}
	}

	cmd.Path, err = exec.LookPath(base)
	if err != nil {
		return 1, err
	}

	if err = cmd.Run(); err != nil {
		if exitErr, ok := err.(*exec.ExitError); ok {
			if status, ok := exitErr.Sys().(syscall.WaitStatus); ok {
				if status.Exited() {
					return status.ExitStatus(), nil
				} else if status.Signaled() {
					exitCode := 128 + int(status.Signal())
					return exitCode, nil
				} else {
					return 1, exitErr
				}
			} else {
				return 1, nil
			}
		}
	}

	return 0, nil
}

type procEntry struct {
	Pid     int
	Ppid    int
	Command string
}

func readProcs() map[int]procEntry {
	cmd := exec.Command("ps", "-o", "pid,ppid,command")
	data, err := cmd.Output()
	if err != nil {
		return nil
	}

	return parseProcs(data)
}

func parseProcs(data []byte) map[int]procEntry {
	lines := bytes.Split(data, []byte("\n"))
	if len(lines) < 2 {
		return nil
	}
	// Remove the header
	lines = lines[1:]

	ret := make(map[int]procEntry, len(lines))
	for _, line := range lines {
		fields := bytes.SplitN(line, []byte(" "), 2)
		if len(fields) != 2 {
			continue
		}

		pid, err := strconv.Atoi(string(fields[0]))
		if err != nil {
			continue
		}

		line = bytes.TrimLeft(fields[1], " ")

		fields = bytes.SplitN(line, []byte(" "), 2)
		if len(fields) != 2 {
			continue
		}

		ppid, err := strconv.Atoi(string(fields[0]))
		if err != nil {
			continue
		}

		ret[pid] = procEntry{
			Pid:     pid,
			Ppid:    ppid,
			Command: string(bytes.TrimLeft(fields[1], " ")),
		}
	}

	return ret
}

func lookupParents() []paths.LogProcess {
	procs := readProcs()
	if procs == nil {
		return nil
	}

	list := []paths.LogProcess{}
	pid := os.Getpid()
	for {
		entry, ok := procs[pid]
		if !ok {
			break
		}

		list = append([]paths.LogProcess{
			{
				Pid:     pid,
				Command: entry.Command,
			},
		}, list...)

		pid = entry.Ppid
	}

	return list
}
