func main() { options.Parse() if *options.String["config"] != "" && !*options.Bool["init"] { err := options.Load(*options.String["config"]) options.FailIf(err, "Can't load configuration") } fmt.Println("Cloudproxy HTTPS Server") if tao.Parent() == nil { options.Fail(nil, "can't continue: no host Tao available") } self, err := tao.Parent().GetTaoName() options.FailIf(err, "Can't get Tao name") // TODO(kwalsh) extend tao name with operating mode and policy addr := net.JoinHostPort(*options.String["host"], *options.String["port"]) 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") } docs := *options.String["docs"] if docs == "" && cpath != "" { docs = path.Join(path.Dir(cpath), "docs") } else if docs == "" { options.Fail(nil, "Option -keys or -config is required") } var keys *tao.Keys if *options.Bool["init"] { keys = taoca.GenerateKeys(name, addr, kdir) } else { keys = taoca.LoadKeys(kdir) } fmt.Printf("Configuration file: %s\n", cpath) if *options.Bool["init"] && cpath != "" { err := options.Save(cpath, "HTTPS server configuration", "persistent") options.FailIf(err, "Can't save configuration") } http.Handle("/cert/", https.CertificateHandler{keys.CertificatePool}) http.Handle("/prin/", https.ManifestHandler{"/prin/", self.String()}) http.Handle("/", http.FileServer(https.LoggingFilesystem{http.Dir(docs)})) fmt.Printf("Listening at %s using HTTPS\n", addr) err = tao.ListenAndServeTLS(addr, keys) options.FailIf(err, "can't listen and serve") fmt.Println("Server Done") }
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 subcmd(cmd, prog string, args []string) { dirs := util.LiberalSearchPath() binary := util.FindExecutable(prog, dirs) if binary == "" { options.Fail(nil, "Can't find `%s` on path '%s'", prog, strings.Join(dirs, ":")) } args = append([]string{"tao_" + cmd}, args...) err := syscall.Exec(binary, args, os.Environ()) options.Fail(err, "Can't exec `%s`", cmd) }
func configureFromFile() *tao.LinuxHostConfig { d, err := ioutil.ReadFile(hostConfigPath()) if err != nil { options.Fail(err, "Can't read linux host configuration") } var cfg tao.LinuxHostConfig if err := proto.UnmarshalText(string(d), &cfg); err != nil { options.Fail(err, "Can't parse linux host configuration") } return &cfg }
func main() { options.Parse() if *options.String["config"] != "" && !*options.Bool["init"] { err := options.Load(*options.String["config"]) options.FailIf(err, "Can't load configuration") } fmt.Println("Cloudproxy HTTPS Netlog Viewer") if tao.Parent() == nil { options.Fail(nil, "can't continue: no host Tao available") } // TODO(kwalsh) extend tao name with operating mode and policy addr := net.JoinHostPort(*options.String["host"], *options.String["port"]) 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") } var keys *tao.Keys if *options.Bool["init"] { keys = taoca.GenerateKeys(name, addr, kdir) } else { keys = taoca.LoadKeys(kdir) } fmt.Printf("Configuration file: %s\n", cpath) if *options.Bool["init"] && cpath != "" { err := options.Save(cpath, "Cloudproxy HTTPS netlog viewer configuration", "persistent") options.FailIf(err, "Can't save configuration") } http.Handle("/cert/", https.CertificateHandler{keys.CertificatePool}) http.Handle("/index.html", http.RedirectHandler("/", 301)) http.HandleFunc("/", netlog_show) fmt.Printf("Listening at %s using HTTPS\n", addr) err := tao.ListenAndServeTLS(addr, keys) options.FailIf(err, "can't listen and serve") fmt.Println("Server Done") }
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") }
func SubmitAndInstall(keys *tao.Keys, csr *CSR) { verbose.Printf("Obtaining certificate from CA (may take a while)\n") resp, err := Submit(keys, csr) options.FailIf(err, "can't obtain X509 certificate from CA") if len(resp) == 0 { options.Fail(nil, "no x509 certificates returned from CA") } // Add the certs to our keys... keys.Cert["default"] = resp[0] for i, c := range resp { name := "ca" if i > 0 { name = fmt.Sprintf("ca-%d", i) } keys.Cert[name] = c } if keys.X509Path("default") != "" { err = keys.SaveCerts() } options.FailIf(err, "can't save X509 certificates") chain := keys.CertChain("default") verbose.Printf("Obtained certfificate chain of length %d:\n", len(chain)) for i, cert := range chain { verbose.Printf(" Cert[%d] Subject: %s\n", i, x509txt.RDNString(cert.Subject)) } if Warn { fmt.Println("Note: You may need to install root CA's key into the browser.") } }
func UrlBasename(loc string) string { u, err := url.ParseRequestURI(loc) options.FailIf(err, "can't parse url in certificate: %s", u) s := strings.Split(u.Path, "/") if len(s) < 2 { options.Fail(nil, "can't parse url in certificate: %s", u) } return s[len(s)-1] }
func main() { verbose.Set(true) options.Parse() if *options.String["config"] != "" && !*options.Bool["init"] { err := options.Load(*options.String["config"]) options.FailIf(err, "Can't load configuration") } if *options.Bool["init"] { cpath := *options.String["config"] if cpath == "" { options.Fail(nil, "Option -init requires option -config") } fmt.Println("Initializing configuration file: " + cpath) err := options.Save(cpath, "Tao rendezvous configuration", "persistent") options.FailIf(err, "Can't save configuration") } fmt.Println("Cloudproxy Rendezvous Service") if tao.Parent() == nil { options.Fail(nil, "can't continue: no host Tao available") } allowAnon = *options.Bool["anon"] manualMode = *options.Bool["manual"] fcfsMode = *options.Bool["fcfs"] addr := *options.String["addr"] netlog.Log("rendezvous: init") netlog.Log("rendezvous: allow anon? %v", allowAnon) netlog.Log("rendezvous: manual? %v", manualMode) netlog.Log("rendezvous: fcfs? %v", fcfsMode) netlog.Log("rendezvous: addr = %v", addr) // TODO(kwalsh) extend tao name with operating mode and policy err := tao.NewOpenServer(tao.ConnHandlerFunc(doResponses)).ListenAndServe(addr) options.FailIf(err, "server died") netlog.Log("rendezvous: done") }
func prompt(msg, def string) string { fmt.Printf("%s [%s]: ", msg, def) line, hasMoreInLine, err := bufio.NewReader(os.Stdin).ReadLine() options.FailIf(err, "Bad input") if hasMoreInLine { options.Fail(nil, "Buffer overflow: Bad input") } s := strings.TrimSpace(string(line)) if s == "" { s = def } return s }
func main() { options.Parse() fmt.Println("Cloudproxy Networked Logging Service") if tao.Parent() == nil { options.Fail(nil, "can't continue: No host Tao available") } addr := *options.String["addr"] // TODO(kwalsh) perhaps extend our tao name with current config options err := tao.NewOpenServer(tao.ConnHandlerFunc(doResponse)).ListenAndServe(addr) options.FailIf(err, "netlog: server died") }
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") }
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) }