// 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/+/master/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
}
