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") }
// 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) } }
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]) } }
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) } }
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") } }
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 }
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 }
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") }
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 "" }
// 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 } }
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 }
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()) }
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") }
// 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) } }
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) } }
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) } }
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") }
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) }
func stopHost(domain *tao.Domain) { err := shutdown() if err != nil { options.Usage("Couldn't connect to linux_host: %s", err) } }
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) } }
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) } }