Ejemplo n.º 1
0
func main() {
	flag.Parse()

	// Check to see if we are running in Docker mode with linked containers.
	// If so, then there will be an environment variable SERVER_PORT that
	// will contain a value of the form tcp://<ip>:<port>
	serverEnvVar := os.Getenv("SERVER_PORT")
	if serverEnvVar == "" {
		serverAddr = net.JoinHostPort(*serverHost, *serverPort)
	} else {
		serverAddr = strings.TrimPrefix(serverEnvVar, "tcp://")
		if serverAddr == serverEnvVar {
			options.Usage("client: invalid SERVER_PORT environment variable value '%s'\n", serverEnvVar)
		}
	}

	switch *demoAuth {
	case "tcp", "tls", "tao":
	default:
		options.Usage("unrecognized authentication mode: %s\n", *demoAuth)
	}

	fmt.Println("Go Tao Demo Client")

	if tao.Parent() == nil {
		options.Fail(nil, "can't continue: No host Tao available")
	}

	domain, err := tao.LoadDomain(configPath(), nil)
	options.FailIf(err, "error: couldn't load the tao domain from %s\n", configPath())

	doClient(domain)
	fmt.Println("Client Done")
}
Ejemplo n.º 2
0
// Update configuration based on command-line options. Does very little sanity checking.
func configureFromOptions(cfg *tao.LinuxHostConfig) {
	if *options.Bool["root"] && *options.Bool["stacked"] {
		options.Usage("Can supply only one of -root and -stacked")
	} else if *options.Bool["root"] {
		cfg.Type = proto.String("root")
	} else if *options.Bool["stacked"] {
		cfg.Type = proto.String("stacked")
	} else if cfg.Type == nil {
		options.Usage("Must supply one of -root and -stacked")
	}
	if s := *options.String["hosting"]; s != "" {
		cfg.Hosting = proto.String(s)
	}
	if s := *options.String["parent_type"]; s != "" {
		cfg.ParentType = proto.String(s)
	}
	if s := *options.String["parent_spec"]; s != "" {
		cfg.ParentSpec = proto.String(s)
	}
	if s := *options.String["socket_dir"]; s != "" {
		cfg.SocketDir = proto.String(s)
	}
	if s := *options.String["kvm_coreos_img"]; s != "" {
		cfg.KvmCoreosImg = proto.String(s)
	}
	if i := *options.Int["kvm_coreos_vm_memory"]; i != 0 {
		cfg.KvmCoreosVmMemory = proto.Int32(int32(i))
	}
	if s := *options.String["kvm_coreos_ssh_auth_keys"]; s != "" {
		cfg.KvmCoreosSshAuthKeys = proto.String(s)
	}
}
Ejemplo n.º 3
0
func main() {
	options.Help = "Usage: %s [options] (get|post ...)"
	options.Parse()

	srv := netlog.DefaultServer
	if *options.String["addr"] != "" {
		srv = &netlog.Server{Addr: *options.String["addr"]}
	}

	fmt.Printf("# connecting to netlog server %s using tao authentication.\n", srv.Addr)
	err := srv.Connect()
	options.FailIf(err, "couldn't connect to netlog server")

	args := options.Args()
	if len(args) == 1 && args[0] == "get" {
		log, err := srv.Entries()
		options.FailIf(err, "couldn't get netlog entries")
		fmt.Printf("# %d entries\n", len(log))
		for i, e := range log {
			fmt.Printf("%d %q %s\n", i, e.Prin, e.Msg)
		}
	} else if len(args) > 1 && args[0] == "post" {
		msg := strings.Join(args[1:], " ")
		err := srv.Log(msg)
		options.FailIf(err, "couldn't post netlog entry")
	} else {
		options.Usage("Unrecognized command: %s\n", args[0])
	}
}
Ejemplo n.º 4
0
func main() {
	flag.Usage = help

	// Get options before the command verb
	flag.Parse()
	// Get command verb
	cmd := "help"
	if flag.NArg() > 0 {
		cmd = flag.Arg(0)
	}
	// Get options after the command verb
	if flag.NArg() > 1 {
		flag.CommandLine.Parse(flag.Args()[1:])
	}

	switch cmd {
	case "help":
		help()
	case "newsoft":
		createSoftTaoKeys()
	case "init":
		createDomain()
	case "policy":
		managePolicy()
	case "user":
		createUserKeys()
	case "principal":
		outputPrincipal()
	default:
		options.Usage("Unrecognized command: %s", cmd)
	}
}
Ejemplo n.º 5
0
func createDomain() {
	dt := template()
	if dt.Config.DomainInfo.GetPolicyKeysPath() == "" {
		options.Usage("Must supply a policy_keys_path in the domain configuration")
	}

	pwd := getKey("domain policy key password", "pass")

	domain, err := tao.CreateDomain(*dt.Config, configPath(), pwd)
	options.FailIf(err, "Can't create domain")

	if domain.Config.DomainInfo.GetGuardType() == "Datalog" {
		// Add any rules specified in the domain template.
		for _, rule := range dt.DatalogRules {
			err := domain.Guard.AddRule(rule)
			options.FailIf(err, "Can't add rule to domain")
		}
	} else if domain.Config.DomainInfo.GetGuardType() == "ACLs" {
		for _, rule := range dt.AclRules {
			err := domain.Guard.AddRule(rule)
			options.FailIf(err, "Can't add rule to domain")
		}
	}

	err = domain.Save()
	options.FailIf(err, "Can't save domain")

	// Optionally, create a public cached domain.
	if addr := *options.String["pub_domain_address"]; addr != "" {
		net := *options.String["pub_domain_network"]
		ttl := *options.Duration["pub_domain_ttl"]
		_, err = domain.CreatePublicCachedDomain(net, addr, int64(ttl))
		options.FailIf(err, "Can't create public cached domain")
	}
}
Ejemplo n.º 6
0
func main() {
	flag.Usage = help

	cmd := "help"
	switch av0 := path.Base(os.Args[0]); av0 {
	case "tao_run", "tao_list", "tao_stop", "tao_kill":
		cmd = av0[4:]
		flag.Parse()
	default:
		// Get options before the command verb
		flag.Parse()
		// Get command verb
		if flag.NArg() > 0 {
			cmd = flag.Arg(0)
		}
		// Get options after the command verb
		if flag.NArg() > 1 {
			flag.CommandLine.Parse(flag.Args()[1:])
		}
	}

	sockPath := path.Join(hostPath(), "admin_socket")
	conn, err := net.DialUnix("unix", nil, &net.UnixAddr{Name: sockPath, Net: "unix"})
	options.FailIf(err, "Can't connect to host admin socket")
	defer conn.Close()

	client := tao.NewLinuxHostAdminClient(conn)
	switch cmd {
	case "help":
		help()
	case "run":
		runHosted(&client, flag.Args())
	case "stop":
		for _, s := range flag.Args() {
			var subprin auth.SubPrin
			_, err := fmt.Sscanf(s, "%v", &subprin)
			options.FailIf(err, "Not a subprin: %s", s)
			err = client.StopHostedProgram(subprin)
			options.FailIf(err, "Could not stop %s", s)
		}
	case "kill":
		for _, s := range flag.Args() {
			var subprin auth.SubPrin
			options.FailIf(err, "Not a subprin: %s", s)
			err = client.KillHostedProgram(subprin)
			options.FailIf(err, "Could not kill %s", s)
		}
	case "list":
		names, pids, err := client.ListHostedPrograms()
		options.FailIf(err, "Can't list hosted programs")
		for i, p := range pids {
			fmt.Printf("pid=%d subprin=%v\n", p, names[i])
		}
		fmt.Printf("%d hosted programs\n", len(pids))
	default:
		options.Usage("Unrecognized command: %s", cmd)
	}

	return
}
Ejemplo n.º 7
0
func makeHostPrin(host string) auth.Prin {
	if host == "" {
		options.Usage("The domain template must contain a Tao host in host_name")
	}
	var prin auth.Prin
	_, err := fmt.Sscanf(host, "%v", &prin)
	options.FailIf(err, "Can't create host principal")
	return prin
}
Ejemplo n.º 8
0
func startHost(domain *tao.Domain) {

	if *options.Bool["daemon"] && *options.Bool["foreground"] {
		options.Usage("Can supply only one of -daemon and -foreground")
	}
	if *options.Bool["daemon"] {
		daemonize()
	}

	cfg := configureFromFile()
	configureFromOptions(cfg)
	host, err := loadHost(domain, cfg)
	options.FailIf(err, "Can't create host")

	sockPath := path.Join(hostPath(), "admin_socket")
	// Set the socketPath directory go+rx so tao_launch can access sockPath and
	// connect to this linux host, even when tao_launch is run as non-root.
	err = os.Chmod(path.Dir(sockPath), 0755)
	options.FailIf(err, "Can't change permissions")
	uaddr, err := net.ResolveUnixAddr("unix", sockPath)
	options.FailIf(err, "Can't resolve unix socket")
	sock, err := net.ListenUnix("unix", uaddr)
	options.FailIf(err, "Can't create admin socket")
	defer sock.Close()
	err = os.Chmod(sockPath, 0666)
	if err != nil {
		sock.Close()
		options.Fail(err, "Can't change permissions on admin socket")
	}

	go func() {
		verbose.Printf("Linux Tao Service (%s) started and waiting for requests\n", host.HostName())
		err = tao.NewLinuxHostAdminServer(host).Serve(sock)
		verbose.Printf("Linux Tao Service finished\n")
		sock.Close()
		options.FailIf(err, "Error serving admin requests")
		os.Exit(0)
	}()

	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill, syscall.SIGTERM)
	<-c
	verbose.Printf("Linux Tao Service shutting down\n")
	err = shutdown()
	if err != nil {
		sock.Close()
		options.Fail(err, "Can't shut down admin socket")
	}

	// The above goroutine will normally end by calling os.Exit(), so we
	// can block here indefinitely. But if we get a second kill signal,
	// let's abort.
	verbose.Printf("Waiting for shutdown....\n")
	<-c
	options.Fail(nil, "Could not shut down linux_host")
}
Ejemplo n.º 9
0
func domainPath() string {
	if path := *options.String["tao_domain"]; path != "" {
		return path
	}
	if path := os.Getenv("TAO_DOMAIN"); path != "" {
		return path
	}
	options.Usage("Must supply -tao_domain or set $TAO_DOMAIN")
	return ""
}
Ejemplo n.º 10
0
// ConfigVal returns a value taken from an option (-name), environment variable
// ($NAME), or a default, whichever one is not empty. If all are empty, it
// prints the usage message and exits.
func ConfigVal(name, defval string) string {
	if path := *options.String[name]; path != "" {
		return path
	} else if path := os.Getenv(strings.ToUpper(name)); path != "" {
		return path
	} else if defval != "" {
		return defval
	} else {
		options.Usage("Must supply -%s or set $%s", name, strings.ToUpper(name))
		return "" // not reached
	}
}
Ejemplo n.º 11
0
func template() *tao.DomainTemplate {
	if savedTemplate == nil {
		configTemplate := *options.String["config_template"]
		if configTemplate == "" {
			options.Usage("Must supply -config_template")
		}
		savedTemplate = new(tao.DomainTemplate)
		pbtext, err := ioutil.ReadFile(configTemplate)
		options.FailIf(err, "Can't read config template")
		err = proto.UnmarshalText(string(pbtext), savedTemplate)
		options.FailIf(err, "Can't parse config template: %s", configTemplate)
	}
	return savedTemplate
}
Ejemplo n.º 12
0
func createSoftTaoKeys() {
	dt := template()

	args := flag.Args()
	if len(args) != 1 {
		options.Usage("Must supply a path for the new key set")
	}
	keypath := args[0]

	pwd := getKey("soft tao key password", "soft_pass")

	k, err := tao.NewOnDiskPBEKeys(tao.Signing|tao.Crypting|tao.Deriving, pwd, keypath, tao.NewX509Name(dt.Config.X509Info))
	options.FailIf(err, "Can't create keys")

	fmt.Println(k.VerifyingKey.ToPrincipal())
}
Ejemplo n.º 13
0
func main() {
	flag.Parse()
	serverAddr = net.JoinHostPort(*serverHost, *serverPort)
	switch *demoAuth {
	case "tcp", "tls", "tao":
	default:
		options.Usage("unrecognized authentication mode: %s\n", *demoAuth)
		return
	}

	fmt.Println("Go Tao Demo Server")

	if tao.Parent() == nil {
		options.Fail(nil, "can't continue: No host Tao available")
	}

	doServer()
	fmt.Println("Server Done")
}
Ejemplo n.º 14
0
// Main provides the main functionality of linux_host. This is provided as a
// separate function to allow other code to register other Tao implementations
// (with tao.Register) before starting the code.
func Main() {
	flag.Usage = help

	// Get options before the command verb
	flag.Parse()
	// Get command verb
	cmd := "help"
	if flag.NArg() > 0 {
		cmd = flag.Arg(0)
	}
	// Get options after the command verb
	if flag.NArg() > 1 {
		flag.CommandLine.Parse(flag.Args()[1:])
	}

	if !*options.Bool["quiet"] {
		noise = os.Stdout
	}

	// Load the domain.
	domain, err := tao.LoadDomain(domainConfigPath(), nil)
	options.FailIf(err, "Can't load domain")

	// Set $TAO_DOMAIN so it will be inherited by hosted programs
	os.Unsetenv("TAO_DOMAIN")
	err = os.Setenv("TAO_DOMAIN", domainPath())
	options.FailIf(err, "Can't set $TAO_DOMAIN")

	switch cmd {
	case "help":
		help()
	case "init":
		initHost(domain)
	case "show":
		showHost(domain)
	case "start":
		startHost(domain)
	case "stop", "shutdown":
		stopHost(domain)
	default:
		options.Usage("Unrecognized command: %s", cmd)
	}
}
Ejemplo n.º 15
0
func Main() {
	flag.Usage = help
	verbose.Set(true)

	// Get options before the command verb
	flag.Parse()
	// Get command verb
	cmd := "help"
	if flag.NArg() > 0 {
		cmd = flag.Arg(0)
	}
	// Get options after the command verb
	if flag.NArg() > 1 {
		flag.CommandLine.Parse(flag.Args()[1:])
	}

	// Load the domain.
	cpath := path.Join(apps.TaoDomainPath(), "tao.config")
	domain, err := tao.LoadDomain(cpath, nil)
	options.FailIf(err, "Can't load domain")

	// Set $TAO_DOMAIN so it will be inherited by hosted programs
	os.Unsetenv("TAO_DOMAIN")
	err = os.Setenv("TAO_DOMAIN", apps.TaoDomainPath())
	options.FailIf(err, "Can't set $TAO_DOMAIN")

	switch cmd {
	case "help":
		help()
	case "init":
		initHost(domain)
	case "show":
		showHost(domain)
	case "start":
		startHost(domain)
	case "stop", "shutdown":
		stopHost(domain)
	default:
		options.Usage("Unrecognized command: %s", cmd)
	}
}
Ejemplo n.º 16
0
func main() {
	// tao -help ==> show main help
	// tao ==> show main help
	// tao [commonopts] cmd [otheropts] ==> some_cmd [commonopts] [otheropts]

	boolopts := []string{"quiet", "verbose", "help"}
	valopts := []string{"tao_domain"}

	flag.VisitAll(func(f *flag.Flag) {
		type BoolFlag interface {
			IsBoolFlag() bool
		}
		if b, ok := f.Value.(BoolFlag); ok && b.IsBoolFlag() {
			boolopts = append(boolopts, f.Name)
		} else {
			valopts = append(valopts, f.Name)
		}
	})

	var args []string
	cmd := "help"
	for i := 1; i < len(os.Args); i++ {
		arg := os.Args[i]
		if arg == "help" || arg == "-?" {
			args = append(args, "-help")
			continue
		}
		if arg == "--" {
			args = append(args, os.Args[i:]...)
			break
		}
		if arg == "" || arg[0] != '-' {
			cmd = arg
			args = append(args, os.Args[i+1:]...)
			break
		}
		if e := strings.Index(arg, "="); e != -1 { // -name=val
			name := flagName(arg[0:e])
			if !match(name, boolopts...) && !match(name, valopts...) {
				options.Usage("Unrecognized option: %s", arg)
			}
			args = append(args, arg)
		} else if match(flagName(arg), boolopts...) { // -bool
			args = append(args, arg)
		} else if match(flagName(arg), valopts...) { // -name val
			if i+1 >= len(os.Args) {
				options.Usage("flag needs an argument: %s", arg)
			}
			args = append(args, arg, os.Args[i+1])
			i++
		} else {
			options.Usage("Unrecognized option: %s", arg)
		}
	}

	// Add a default --tao_domain
	// config := os.Getenv("TAO_DOMAIN")
	// if config != "" {
	// 	arg := fmt.Sprintf("--tao_domain='%s'", config)
	// 	args = append([]string{arg}, args...)
	// }

	// Add a default --log_dir
	logdir := os.TempDir() + "/tao_log"
	if err := util.MkdirAll(logdir, 0777); err != nil {
		options.FailIf(err, "Can't create log directory: %s", logdir)
	}
	arg := fmt.Sprintf("--log_dir=%s", logdir)
	args = append([]string{arg}, args...)

	// Maybe add --alsologtostderr=true too?

	switch cmd {
	case "help":
		help()
	case "domain":
		subcmd(cmd, "tao_admin", args)
	case "host":
		subcmd(cmd, "linux_host", args)
	case "run", "list", "stop", "kill":
		subcmd(cmd, "tao_launch", args)
	default:
		options.Usage("Unrecognized tao command: %s", cmd)
	}
}
Ejemplo n.º 17
0
func main() {
	verbose.Set(true)
	options.Parse()

	profiling.ProfilePath = *options.String["profile"]

	if !verbose.Enabled {
		taoca.ConfirmNames = false
	}

	if *options.String["config"] != "" && !*options.Bool["init"] {
		err := options.Load(*options.String["config"])
		options.FailIf(err, "Can't load configuration")
	}

	fmt.Println("https/tls Certificate Authority")

	manualMode = *options.Bool["manual"]
	learnMode = *options.Bool["learn"]

	if !manualMode && tao.Parent() == nil {
		options.Fail(nil, "can't continue: automatic mode, but no host Tao available")
	}

	if *options.Bool["root"] == (*options.String["subsidiary"] != "") {
		options.Usage("must supply exactly one of -root or -subsidiary options")
	}

	host := *options.String["host"]
	port := *options.String["port"]
	addr := net.JoinHostPort(host, port)

	// TODO(kwalsh) extend tao name with operating mode and policy

	cpath := *options.String["config"]
	kdir := *options.String["keys"]
	if kdir == "" && cpath != "" {
		kdir = path.Dir(cpath)
	} else if kdir == "" {
		options.Fail(nil, "Option -keys or -config is required")
	}
	ppath := path.Join(kdir, "policy")

	var err error

	if *options.Bool["init"] {
		if cpath != "" {
			err := options.Save(cpath, "HTTPS/TLS certificate authority configuration", "persistent")
			options.FailIf(err, "Can't save configuration")
		}
		fmt.Println("" +
			"Initializing fresh HTTP/TLS CA signing key. Provide the following information,\n" +
			"to be include in the CA's own x509 certificate. Leave the response blank to\n" +
			"accept the default value.\n" +
			"\n" +
			"Configuration file: " + cpath + "\n" +
			"Keys directory: " + kdir + "\n")

		var caName *pkix.Name
		if taoca.ConfirmNames {
			if *options.Bool["root"] {
				caName = taoca.ConfirmName(caRootName)
			} else {
				caName = taoca.ConfirmName(caSubsidiaryName)
			}
		} else {
			if *options.Bool["root"] {
				caName = caRootName
			} else {
				caName = caSubsidiaryName
			}
		}

		if manualMode {
			pwd := options.Password("Choose an HTTPS/TLS CA signing key password", "pass")
			caKeys, err = tao.InitOnDiskPBEKeys(tao.Signing, pwd, kdir, caName)
			tao.ZeroBytes(pwd)
		} else {
			caKeys, err = tao.InitOnDiskTaoSealedKeys(tao.Signing, caName, tao.Parent(), kdir, tao.SealPolicyDefault)
		}
		options.FailIf(err, "Can't initialize fresh HTTPS/TLS CA signing key")
		if *options.Bool["root"] {
			fmt.Printf(""+
				"Note: To install this CA's key in the Chrome browser, go to\n"+
				"  'Settings', 'Show advanced settings...', 'Manage Certificates...', 'Authorities'\n"+
				"  then import the following file:\n"+
				"     %s\n"+
				"  Select 'Trust this certificate for identifying websites' and/or other\n"+
				"  options, then click 'OK'\n", caKeys.X509Path("default"))
		} else {
			csr := taoca.NewCertificateSigningRequest(caKeys.VerifyingKey, caName)
			*csr.IsCa = true
			srv := *options.String["subsidiary"]
			taoca.DefaultServerName = srv
			taoca.SubmitAndInstall(caKeys, csr)
		}

		if !manualMode {
			f, err := os.Open(ppath)
			if err == nil {
				f.Close()
				fmt.Printf("Using existing certificate-granting policy: %s\n", ppath)
			} else {
				fmt.Printf("Creating default certificate-granting policy: %s\n", ppath)
				fmt.Printf("Edit that file to define the certificate-granting policy.\n")
				err := util.WritePath(ppath, []byte(policy.Default), 0755, 0755)
				options.FailIf(err, "Can't save policy rules")
			}
		}
	} else {
		if manualMode {
			pwd := options.Password("HTTPS/TLS CA signing key password", "pass")
			caKeys, err = tao.LoadOnDiskPBEKeys(tao.Signing, pwd, kdir)
			tao.ZeroBytes(pwd)
		} else {
			caKeys, err = tao.LoadOnDiskTaoSealedKeys(tao.Signing, tao.Parent(), kdir, tao.SealPolicyDefault)
		}
		options.FailIf(err, "Can't load HTTP/TLS CA signing key")
	}

	netlog.Log("https_ca: start")
	netlog.Log("https_ca: manual? %v", manualMode)

	if !manualMode {
		guard, err = policy.Load(ppath)
		options.FailIf(err, "Can't load certificate-granting policy")
	}

	var prin auth.Prin
	if tao.Parent() != nil {
		prin, err = tao.Parent().GetTaoName()
		options.FailIf(err, "Can't get tao name")
	} else {
		rendezvous.DefaultServer.Connect(caKeys)
		prin = caKeys.SigningKey.ToPrincipal()
	}

	name := *options.String["name"]
	if name != "" {
		err = rendezvous.Register(rendezvous.Binding{
			Name:      proto.String(name),
			Host:      proto.String(host),
			Port:      proto.String(port),
			Protocol:  proto.String("protoc/rpc/https_ca"),
			Principal: proto.String(prin.String()),
		})
		options.FailIf(err, "Can't register with rendezvous service")
	}

	statsdelay := *options.String["stats"]
	var srv *tao.Server
	if statsdelay != "" {
		go profiling.ShowStats(&stats, statsdelay, "sign certificates")
		srv = tao.NewOpenServer(tao.ConnHandlerFunc(doResponseWithStats))
	} else {
		srv = tao.NewOpenServer(tao.ConnHandlerFunc(doResponseWithoutStats))
	}

	srv.Keys = caKeys
	fmt.Printf("Listening at %s using Tao-authenticated channels\n", addr)
	err = srv.ListenAndServe(addr)
	options.FailIf(err, "server died")

	fmt.Println("Server Done")
	netlog.Log("https_ca: done")
}
Ejemplo n.º 18
0
func runHosted(client *tao.LinuxHostAdminClient, args []string) {
	var err error

	if len(args) == 0 {
		options.Usage("Missing program path and arguments")
	}

	spec := new(tao.HostedProgramSpec)

	ctype := "process"
	spec.Path = args[0]
	for _, prefix := range []string{"process", "docker", "kvm_coreos"} {
		if strings.HasPrefix(spec.Path, prefix+":") {
			ctype = prefix
			spec.Path = strings.TrimPrefix(spec.Path, prefix+":")
		}
	}

	switch ctype {
	case "process":
		dirs := util.LiberalSearchPath()
		binary := util.FindExecutable(args[0], dirs)
		if binary == "" {
			options.Fail(nil, "Can't find `%s` on path '%s'", args[0], strings.Join(dirs, ":"))
		}
		spec.ContainerArgs = []string{spec.Path}
		spec.Args = args[1:]
		spec.Path = binary
	case "docker", "kvm_coreos":
		// args contains [ "docker:argv0", docker_args..., "--", prog_args... ]
		spec.ContainerArgs, spec.Args = split(args, "--")
		// Replace docker arg 0 with valid image name constructed from // base(argv[0]).
		r, _ := regexp.Compile("[^a-zA-Z0-9_.]+")
		spec.ContainerArgs[0] = r.ReplaceAllLiteralString(path.Base(spec.Path), "_")
	}

	pidfile := *options.String["pidfile"]
	var pidOut *os.File
	if pidfile == "-" {
		pidOut = os.Stdout
	} else if pidfile != "" {
		pidOut, err = os.Create(pidfile)
		options.FailIf(err, "Can't open pid file")
	}

	namefile := *options.String["namefile"]
	var nameOut *os.File
	if namefile == "-" {
		nameOut = os.Stdout
	} else if namefile != "" {
		nameOut, err = os.Create(namefile)
		options.FailIf(err, "Can't open name file")
	}

	daemon := *options.Bool["daemon"]
	disown := *options.Bool["disown"]

	var pr, pw *os.File
	proxying := false
	tty := isCtty(int(os.Stdin.Fd()))
	if daemon {
		// stdio is nil
	} else if disown {
		// We are assuming that if stdin is a terminal, it is our controlling
		// terminal. I don't know any way to verify it, but it seems likely.
		if tty {
			// stdin is nil, else they would steal input from tty
		} else {
			spec.Stdin = os.Stdin
		}
		spec.Stdout = os.Stdout
		spec.Stderr = os.Stderr
	} else {
		// interactive
		proxying = tty
		if proxying {
			pr, pw, err = os.Pipe()
			options.FailIf(err, "Can't pipe")
			spec.Stdin = pr
		} else {
			spec.Stdin = os.Stdin
		}
		spec.Stdout = os.Stdout
		spec.Stderr = os.Stderr
		fmt.Fprintf(noise, "[proxying stdin]\n")
	}

	spec.Dir, err = os.Getwd()
	options.FailIf(err, "Can't get working directory")

	// Start catching signals early, buffering a few, so we don't miss any. We
	// don't proxy SIGTTIN. However, we do catch it and stop ourselves, rather
	// than letting the OS stop us. This is necessary so that we can send
	// SIGCONT to the child at the right times.
	// Here is the easy case
	//   we start in background
	//   we fork (output starts going)
	//   we are background, so leave SIGTTIN handling at the default
	//   we read and get SIGTTIN, so are stopped
	//   child is not stopped, it keeps outputting, as desired
	//   upon fg, we get SIGCONT, start dropping SIGTTIN and looping for input and signals
	// Here is the tricky case:
	//   we start in foreground
	//   we fork (output starts going)
	//   we are foreground, so catch and drop SIGTTIN (we use SIGTSTP instead)
	//   we get SIGTSTP via ctrl-z
	//   we send child SIGTSTP, so it stops
	//      [we are still dropping SIGTTIN]
	//   we send ourselves SIGSTOP, so we stop
	//   we get SIGCONT via either bg or fg
	//      [if bg, now furiously catching and dropping SIGTTIN]
	//      [if fg, dropping too, but there should not be any SIGTTIN]
	//   send child the SIGCONT
	//   if we are foreground, so go back to top of loop
	//   if we are background, reset SIGTTIN which causes us to stop
	//
	// The basic invariant we are trying to maintain is that when we are
	// foreground we catch and drop SIGTTIN, allowing us to properly handle
	// SIGTSTP events. There shouldn't be any SIGTTIN anyway, except for the
	// brief moments when we are transitioning to stopped.
	// And when the child is supposed to be running in the background, we should
	// leave the default SIGTTIN behavior, so that the OS will stop our read
	// loop.

	signals := make(chan os.Signal, 10) // some buffering
	signal.Notify(signals,
		syscall.SIGINT,  // Ctrl-C
		syscall.SIGTERM, // SIGINT wannabe (e.g. via kill)
		syscall.SIGQUIT, // Ctrl-\
		syscall.SIGTSTP, // Ctrl-Z
		syscall.SIGHUP,  // tty hangup (e.g. via disown)
		syscall.SIGABRT, // abort (e.g. via kill)
		syscall.SIGUSR1, // user-defined (e.g. via kill)
		syscall.SIGUSR2, // user-defined (e.g. via kill)
	)

	// Start the hosted program
	subprin, pid, err := client.StartHostedProgram(spec)
	options.FailIf(err, "Can't start hosted program")
	fmt.Fprintf(noise, "[started hosted program with pid %d]\n", pid)
	fmt.Fprintf(noise, "[subprin is %v]\n", subprin)

	if pidOut != nil {
		fmt.Fprintln(pidOut, pid)
		pidOut.Close()
	}

	if nameOut != nil {
		fmt.Fprintln(nameOut, subprin)
		nameOut.Close()
	}

	if disown || daemon {
		return
	}

	// Listen for exit status from host
	status := make(chan int, 1)
	go func() {
		s, _ := client.WaitHostedProgram(pid, subprin)
		// For short programs, we often lose the race, so
		// we get a "no such hosted program" error. Ignore it.
		status <- s
	}()

	wasForeground := false
	if proxying && isForeground() {
		fmt.Fprintf(noise, "[in foreground]\n")
		dropSIGTTIN()
		wasForeground = true
	}

	// Proxy stdin, if needed
	if proxying {
		pr.Close()
		go func() {
			_, err := io.Copy(pw, os.Stdin)
			options.WarnIf(err, "Can't copy from stdin to pipe")
			pw.Close()
		}()
	}

	// If we are proxying and (were) background, we should probably
	// have done a read() by now and gotten SIGTTIN and stopped. Let's
	// pause a moment to be sure the read() happens.
	time.Sleep(moment)

	// By this point, if we had been foreground, we might still be. Or, we might
	// have been foreground but just gotten SIGTSTP and are now madly dropping
	// SIGTTIN until we get into the loop below to handle the SIGTSTP.
	//
	// Alternatively, if we had been background, we would have been stopped by
	// the default SIGTTIN, so the only way we would be here is if we later got
	// pulled foreground via fg. We want to be dropping SIGTTIN in case we get a
	// SIGTSTP.
	if proxying && !wasForeground {
		dropSIGTTIN()
	}

	next := cont
	for next != done {
		select {
		case s := <-status:
			fmt.Fprintf(noise, "[hosted program exited, %s]\n", exitCode(s))
			next = done
		case sig := <-signals:
			next = handle(sig, pid)
		}
		if next == resumed && proxying && !isForeground() {
			// Need to toggle SIGTTIN handling and block (that's the only way to
			// stop spinning on SIGTTIN), but only after handling all pending
			// signals (e.g. SIGCONT then SIGHUP, or SIGCONT then SIGTERM).
			for next == resumed {
				select {
				case s := <-status:
					fmt.Fprintf(noise, "[hosted program exited, %s]\n", exitCode(s))
					next = done
				case sig := <-signals:
					next = handle(sig, pid)
					if next == cont {
						next = resumed
					}
				default:
					next = cont
					defaultSIGTTIN()
					time.Sleep(moment)
					dropSIGTTIN()
				}
			}
		}
	}
	signal.Stop(signals)
}
Ejemplo n.º 19
0
func stopHost(domain *tao.Domain) {
	err := shutdown()
	if err != nil {
		options.Usage("Couldn't connect to linux_host: %s", err)
	}
}
Ejemplo n.º 20
0
func loadHost(domain *tao.Domain, cfg *tao.LinuxHostConfig) (*tao.LinuxHost, error) {
	var tc tao.Config

	// Decide host type
	switch cfg.GetType() {
	case "root":
		tc.HostType = tao.Root
	case "stacked":
		tc.HostType = tao.Stacked
	case "":
		options.Usage("Must supply -hosting flag")
	default:
		options.Usage("Invalid host type: %s", cfg.GetType())
	}

	// Decide hosting type
	switch cfg.GetHosting() {
	case "process":
		tc.HostedType = tao.ProcessPipe
	case "docker":
		tc.HostedType = tao.DockerUnix
	case "kvm_coreos":
		tc.HostedType = tao.KVMCoreOSFile
	case "":
		options.Usage("Must supply -hosting flag")
	default:
		options.Usage("Invalid hosting type: %s", cfg.GetHosting())
	}

	// For stacked hosts, figure out the channel type: TPM, pipe, file, or unix
	if tc.HostType == tao.Stacked {
		switch cfg.GetParentType() {
		case "TPM":
			tc.HostChannelType = "tpm"
		case "pipe":
			tc.HostChannelType = "pipe"
		case "file":
			tc.HostChannelType = "file"
		case "unix":
			tc.HostChannelType = "unix"
		case "":
			options.Usage("Must supply -parent_type for stacked hosts")
		default:
			options.Usage("Invalid parent type: %s", cfg.GetParentType())
		}

		// For stacked hosts on anything but a TPM, we also need parent spec
		if tc.HostChannelType != "tpm" {
			tc.HostSpec = cfg.GetParentSpec()
			if tc.HostSpec == "" {
				options.Usage("Must supply -parent_spec for non-TPM stacked hosts")
			}
		} else {
			// For stacked hosts on a TPM, we also need info from domain config
			if domain.Config.TpmInfo == nil {
				options.Usage("Must provide TPM configuration in the domain to use a TPM")
			}
			tc.TPMAIKPath = path.Join(domainPath(), domain.Config.TpmInfo.GetAikPath())
			tc.TPMPCRs = domain.Config.TpmInfo.GetPcrs()
			tc.TPMDevice = domain.Config.TpmInfo.GetTpmPath()
		}
	}

	rulesPath := ""
	if p := domain.RulesPath(); p != "" {
		rulesPath = path.Join(domainPath(), p)
	}

	// Create the hosted program factory
	socketPath := hostPath()
	if subPath := cfg.GetSocketDir(); subPath != "" {
		if path.IsAbs(subPath) {
			socketPath = subPath
		} else {
			socketPath = path.Join(socketPath, subPath)
		}
	}

	// TODO(cjpatton) How do the NewLinuxDockerContainterFactory and the
	// NewLinuxKVMCoreOSFactory need to be modified to support the new
	// CachedGuard? They probably don't.
	var childFactory tao.HostedProgramFactory
	switch tc.HostedType {
	case tao.ProcessPipe:
		childFactory = tao.NewLinuxProcessFactory("pipe", socketPath)
	case tao.DockerUnix:
		childFactory = tao.NewLinuxDockerContainerFactory(socketPath, rulesPath)
	case tao.KVMCoreOSFile:
		sshFile := cfg.GetKvmCoreosSshAuthKeys()
		if sshFile == "" {
			options.Usage("Must specify -kvm_coreos_ssh_auth_keys for hosting QEMU/KVM CoreOS")
		}
		if !path.IsAbs(sshFile) {
			sshFile = path.Join(domainPath(), sshFile)
		}
		sshKeysCfg, err := tao.CloudConfigFromSSHKeys(sshFile)
		options.FailIf(err, "Can't read ssh keys")

		coreOSImage := cfg.GetKvmCoreosImg()
		if coreOSImage == "" {
			options.Usage("Must specify -kvm_coreos_image for hosting QEMU/KVM CoreOS")
		}
		if !path.IsAbs(coreOSImage) {
			coreOSImage = path.Join(domainPath(), coreOSImage)
		}

		vmMemory := cfg.GetKvmCoreosVmMemory()
		if vmMemory == 0 {
			vmMemory = 1024
		}

		cfg := &tao.CoreOSConfig{
			ImageFile:  coreOSImage,
			Memory:     int(vmMemory),
			RulesPath:  rulesPath,
			SSHKeysCfg: sshKeysCfg,
		}
		childFactory, err = tao.NewLinuxKVMCoreOSFactory(socketPath, cfg)
		options.FailIf(err, "Can't create KVM CoreOS factory")
	}

	if tc.HostType == tao.Root {
		pwd := getKey("root host key password", "pass")
		return tao.NewRootLinuxHost(hostPath(), domain.Guard, pwd, childFactory)
	} else {
		parent := tao.ParentFromConfig(tc)
		if parent == nil {
			options.Usage("No host tao available, verify -parent_type or $%s\n", tao.HostChannelTypeEnvVar)
		}
		return tao.NewStackedLinuxHost(hostPath(), domain.Guard, tao.ParentFromConfig(tc), childFactory)
	}
}
Ejemplo n.º 21
0
func loadHost(domain *tao.Domain, cfg *tao.LinuxHostConfig) (*tao.LinuxHost, error) {
	var tc tao.Config

	// Sanity check host type
	var stacked bool
	switch cfg.GetType() {
	case "root":
		stacked = false
	case "stacked":
		stacked = true
	case "":
		options.Usage("Must supply -root or -stacked flag")
	default:
		options.Usage("Invalid host type: %s", cfg.GetType())
	}

	// Sanity check hosting type
	hosting := make(map[string]bool)
	for _, h := range cfg.GetHosting() {
		switch h {
		case "process", "docker", "kvm_coreos", "kvm_coreos_linuxhost":
			hosting[h] = true
		default:
			options.Usage("Invalid hosting type: %s", cfg.GetHosting())
		}
	}
	if len(hosting) == 0 {
		options.Usage("Must supply -hosting flag")
	}

	// For stacked hosts, figure out the channel type: TPM, pipe, file, or unix
	if stacked {
		switch cfg.GetParentType() {
		case "TPM":
			tc.HostChannelType = "tpm"
		case "pipe":
			tc.HostChannelType = "pipe"
		case "file":
			tc.HostChannelType = "file"
		case "unix":
			tc.HostChannelType = "unix"
		case "":
			// leave channel type blank, tao may find it in env vars
			tc.HostChannelType = ""
		default:
			options.Usage("Invalid parent type: %s", cfg.GetParentType())
		}

		// For stacked hosts, we may also have a parent spec from command line
		tc.HostSpec = cfg.GetParentSpec()

		// For stacked hosts on a TPM, we may also have tpm info from domain config
		if domain.Config.TpmInfo != nil {
			tc.TPMAIKPath = path.Join(apps.TaoDomainPath(), domain.Config.TpmInfo.GetAikPath())
			tc.TPMPCRs = domain.Config.TpmInfo.GetPcrs()
			tc.TPMDevice = domain.Config.TpmInfo.GetTpmPath()
		}
	}

	rulesPath := ""
	if p := domain.RulesPath(); p != "" {
		rulesPath = path.Join(apps.TaoDomainPath(), p)
	}

	// Create the hosted program factory
	socketPath := hostPath()
	if subPath := cfg.GetSocketDir(); subPath != "" {
		if path.IsAbs(subPath) {
			socketPath = subPath
		} else {
			socketPath = path.Join(socketPath, subPath)
		}
	}

	// TODO(cjpatton) How do the NewLinuxDockerContainterFactory and the
	// NewLinuxKVMCoreOSHostFactory need to be modified to support the new
	// CachedGuard? They probably don't.
	childFactory := make(map[string]tao.HostedProgramFactory)
	if hosting["process"] {
		childFactory["process"] = tao.NewLinuxProcessFactory("pipe", socketPath)
	}
	if hosting["docker"] {
		childFactory["docker"] = tao.NewLinuxDockerContainerFactory(socketPath, rulesPath)
	}
	if hosting["kvm_coreos"] {
		// TODO(kwalsh) re-enable this code path in new kvm factory
		// sshFile := cfg.GetKvmCoreosSshAuthKeys()
		// if sshFile != "" {
		// if !path.IsAbs(sshFile) {
		// 	sshFile = path.Join(apps.TaoDomainPath(), sshFile)
		// }
		// sshKeysCfg, err := io.ReadFile(sshFile)
		// options.FailIf(err, "Can't read ssh authorized keys")

		coreOSImage := cfg.GetKvmCoreosImg()
		if coreOSImage == "" {
			options.Usage("Must specify -kvm_coreos_image for hosting QEMU/KVM CoreOS")
		}
		if !path.IsAbs(coreOSImage) {
			coreOSImage = path.Join(apps.TaoDomainPath(), coreOSImage)
		}

		// TODO(kwalsh) re-enable this code path in new kvm factory
		// vmMemory := cfg.GetKvmCoreosVmMemory()
		// if vmMemory == 0 {
		// 	vmMemory = 1024
		// }

		var err error
		childFactory["kvm_coreos"], err = tao.NewKVMCoreOSFactory(coreOSImage, false)
		options.FailIf(err, "Can't create KVM CoreOS factory")
	}
	if hosting["kvm_coreos_linuxhost"] {
		sshFile := cfg.GetKvmCoreosSshAuthKeys()
		if sshFile == "" {
			options.Usage("Must specify -kvm_coreos_ssh_auth_keys for hosting QEMU/KVM CoreOS")
		}
		if !path.IsAbs(sshFile) {
			sshFile = path.Join(apps.TaoDomainPath(), sshFile)
		}
		sshKeysCfg, err := tao.CloudConfigFromSSHKeys(sshFile)
		options.FailIf(err, "Can't read ssh keys")

		coreOSImage := cfg.GetKvmCoreosImg()
		if coreOSImage == "" {
			options.Usage("Must specify -kvm_coreos_image for hosting QEMU/KVM CoreOS")
		}
		if !path.IsAbs(coreOSImage) {
			coreOSImage = path.Join(apps.TaoDomainPath(), coreOSImage)
		}

		vmMemory := cfg.GetKvmCoreosVmMemory()
		if vmMemory == 0 {
			vmMemory = 1024
		}

		cfg := &tao.CoreOSLinuxhostConfig{
			ImageFile:  coreOSImage,
			Memory:     int(vmMemory),
			RulesPath:  rulesPath,
			SSHKeysCfg: sshKeysCfg,
		}

		childFactory["kvm_coreos_linuxhost"], err = tao.NewLinuxKVMCoreOSHostFactory(socketPath, cfg)
		options.FailIf(err, "Can't create KVM CoreOS LinuxHost factory")
	}

	if !stacked {
		pwd := options.Password("root host key password", "pass")
		return tao.NewRootLinuxHost(hostPath(), domain.Guard, pwd, childFactory)
	} else {
		parent := tao.ParentFromConfig(tc)
		if parent == nil {
			options.Usage("No host tao available, verify -parent_type (or $%s) and associated variables\n", tao.HostChannelTypeEnvVar)
		}
		return tao.NewStackedLinuxHost(hostPath(), domain.Guard, parent, childFactory)
	}
}