Merge "veyron/lib/modules: introduce sh.StartExternalCommand"
diff --git a/profiles/chrome/chromeinit.go b/profiles/chrome/chromeinit.go
index 9f4ace2..1019de9 100644
--- a/profiles/chrome/chromeinit.go
+++ b/profiles/chrome/chromeinit.go
@@ -7,6 +7,7 @@
"v.io/core/veyron2"
"v.io/core/veyron2/context"
+ "v.io/core/veyron2/ipc"
"v.io/core/veyron2/ipc/stream"
"v.io/core/veyron2/vlog"
@@ -31,7 +32,9 @@
return nil, nil, nil, err
}
- runtime, ctx, shutdown, err := grt.Init(ctx, nil, nil, nil, commonFlags.RuntimeFlags(), nil)
+ protocols := []string{"wsh", "ws"}
+ listenSpec := ipc.ListenSpec{Addrs: ipc.ListenAddrs{{Protocol: "ws", Address: ""}}}
+ runtime, ctx, shutdown, err := grt.Init(ctx, nil, protocols, &listenSpec, commonFlags.RuntimeFlags(), nil)
if err != nil {
return nil, nil, shutdown, err
}
diff --git a/profiles/roaming/roaming_server.go b/profiles/roaming/roaming_server.go
index e85f22e..30874be 100644
--- a/profiles/roaming/roaming_server.go
+++ b/profiles/roaming/roaming_server.go
@@ -7,6 +7,7 @@
"v.io/core/veyron2"
"v.io/core/veyron2/ipc"
+ "v.io/core/veyron2/vlog"
"v.io/core/veyron/profiles/roaming"
)
@@ -14,11 +15,10 @@
func main() {
ctx, shutdown := veyron2.Init()
defer shutdown()
- log := veyron2.GetLogger(ctx)
server, err := veyron2.NewServer(ctx)
if err != nil {
- log.Fatalf("unexpected error: %q", err)
+ vlog.Fatalf("unexpected error: %q", err)
}
listenSpec := veyron2.GetListenSpec(ctx)
@@ -26,13 +26,13 @@
fmt.Printf("listen spec: %v\n", listenSpec)
ep, err := server.Listen(listenSpec)
if err != nil {
- log.Fatalf("unexpected error: %q", err)
+ vlog.Fatalf("unexpected error: %q", err)
}
if ep != nil {
fmt.Println(ep)
}
if err := server.Serve("roamer", &receiver{}, nil); err != nil {
- log.Fatalf("unexpected error: %q", err)
+ vlog.Fatalf("unexpected error: %q", err)
}
done := make(chan struct{})
diff --git a/profiles/roaming/roaminginit.go b/profiles/roaming/roaminginit.go
index 48350e4..45a5f56 100644
--- a/profiles/roaming/roaminginit.go
+++ b/profiles/roaming/roaminginit.go
@@ -139,7 +139,6 @@
ch chan<- config.Setting) {
defer close(ch)
- log := runtime.GetLogger(ctx)
listenSpec := runtime.GetListenSpec(ctx)
// TODO(cnicolaou): add support for listening on multiple network addresses.
@@ -150,21 +149,21 @@
case <-watcher.Channel():
cur, err := netstate.GetAccessibleIPs()
if err != nil {
- log.Errorf("failed to read network state: %s", err)
+ vlog.Errorf("failed to read network state: %s", err)
continue
}
removed := netstate.FindRemoved(prev, cur)
added := netstate.FindAdded(prev, cur)
- log.VI(2).Infof("Previous: %d: %s", len(prev), prev)
- log.VI(2).Infof("Current : %d: %s", len(cur), cur)
- log.VI(2).Infof("Added : %d: %s", len(added), added)
- log.VI(2).Infof("Removed : %d: %s", len(removed), removed)
+ vlog.VI(2).Infof("Previous: %d: %s", len(prev), prev)
+ vlog.VI(2).Infof("Current : %d: %s", len(cur), cur)
+ vlog.VI(2).Infof("Added : %d: %s", len(added), added)
+ vlog.VI(2).Infof("Removed : %d: %s", len(removed), removed)
if len(removed) == 0 && len(added) == 0 {
- log.VI(2).Infof("Network event that lead to no address changes since our last 'baseline'")
+ vlog.VI(2).Infof("Network event that lead to no address changes since our last 'baseline'")
continue
}
if len(removed) > 0 {
- log.VI(2).Infof("Sending removed: %s", removed)
+ vlog.VI(2).Infof("Sending removed: %s", removed)
ch <- ipc.NewRmAddrsSetting(removed)
}
// We will always send the best currently available address
diff --git a/runtimes/fake/runtime.go b/runtimes/fake/runtime.go
index baa6386..4f5bd29 100644
--- a/runtimes/fake/runtime.go
+++ b/runtimes/fake/runtime.go
@@ -7,7 +7,6 @@
"v.io/core/veyron2"
"v.io/core/veyron2/context"
"v.io/core/veyron2/security"
- "v.io/core/veyron2/vlog"
tsecurity "v.io/core/veyron/lib/testutil/security"
)
@@ -28,6 +27,10 @@
return &Runtime{}, ctx, func() {}, nil
}
+func (r *Runtime) Init(ctx *context.T) error {
+ return nil
+}
+
func (r *Runtime) SetPrincipal(ctx *context.T, principal security.Principal) (*context.T, error) {
return context.WithValue(ctx, principalKey, principal), nil
}
@@ -37,19 +40,6 @@
return p
}
-func (r *Runtime) SetNewLogger(ctx *context.T, name string, opts ...vlog.LoggingOpts) (*context.T, vlog.Logger, error) {
- logger, err := vlog.NewLogger(name, opts...)
- if err != nil {
- return context.WithValue(ctx, loggerKey, logger), logger, nil
- }
- return ctx, nil, err
-}
-
-func (r *Runtime) GetLogger(ctx *context.T) vlog.Logger {
- l, _ := ctx.Value(loggerKey).(vlog.Logger)
- return l
-}
-
func (r *Runtime) GetAppCycle(ctx *context.T) veyron2.AppCycle {
panic("unimplemented")
}
diff --git a/runtimes/google/rt/mgmt.go b/runtimes/google/rt/mgmt.go
index ca0f7e3..ccaad62 100644
--- a/runtimes/google/rt/mgmt.go
+++ b/runtimes/google/rt/mgmt.go
@@ -14,13 +14,17 @@
"v.io/core/veyron/lib/exec"
)
-func (rt *Runtime) initMgmt(ctx *context.T, appCycle veyron2.AppCycle, handle *exec.ChildHandle) error {
- // Do not initialize the mgmt runtime if the process has not
- // been started through the veyron exec library by a device
- // manager.
- if handle == nil {
+func (rt *Runtime) initMgmt(ctx *context.T) error {
+ handle, err := exec.GetChildHandle()
+ if err == exec.ErrNoVersion {
+ // Do not initialize the mgmt runtime if the process has not
+ // been started through the veyron exec library by a device
+ // manager.
return nil
+ } else if err != nil {
+ return err
}
+
parentName, err := handle.Config.Get(mgmt.ParentNameConfigKey)
if err != nil {
return nil
@@ -45,7 +49,7 @@
if err != nil {
return err
}
- if err := server.Serve("", appCycle.Remote(), nil); err != nil {
+ if err := server.Serve("", veyron2.GetAppCycle(ctx).Remote(), nil); err != nil {
server.Stop()
return err
}
@@ -55,6 +59,13 @@
return err
}
+ // Note(mattr): that we ignore the error here.
+ // As far as I can tell this is because the modules framework actually calls
+ // SetReady(), so we would then call it here a second time and get
+ // an error.
+ // TODO(mattr): We should change the modules framework so we can properly check
+ // errors here.
+ handle.SetReady()
return nil
}
@@ -79,7 +90,7 @@
func (rt *Runtime) callbackToParent(ctx *context.T, parentName, myName string) error {
ctx, _ = context.WithTimeout(ctx, time.Minute)
- call, err := rt.GetClient(ctx).StartCall(ctx, parentName, "Set", []interface{}{mgmt.AppCycleManagerConfigKey, myName}, options.NoResolve{})
+ call, err := rt.GetClient(ctx).StartCall(ctx, parentName, "Set", []interface{}{mgmt.AppCycleManagerConfigKey, myName})
if err != nil {
return err
diff --git a/runtimes/google/rt/rt_test.go b/runtimes/google/rt/rt_test.go
index ce3a6a4..a4e473d 100644
--- a/runtimes/google/rt/rt_test.go
+++ b/runtimes/google/rt/rt_test.go
@@ -36,7 +36,7 @@
ctx, shutdown := veyron2.Init()
defer shutdown()
- l := veyron2.GetLogger(ctx)
+ l := vlog.Log
fmt.Println(l)
args := fmt.Sprintf("%s", l)
expected := regexp.MustCompile("name=veyron logdirs=\\[/tmp\\] logtostderr=true|false alsologtostderr=false|true max_stack_buf_size=4292608 v=[0-9] stderrthreshold=2 vmodule= log_backtrace_at=:0")
@@ -59,10 +59,10 @@
}
func child(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
- ctx, shutdown := veyron2.Init()
+ _, shutdown := veyron2.Init()
defer shutdown()
- logger := veyron2.GetLogger(ctx)
+ logger := vlog.Log
vlog.Infof("%s\n", logger)
fmt.Fprintf(stdout, "%s\n", logger)
modules.WaitForEOF(stdin)
diff --git a/runtimes/google/rt/runtime.go b/runtimes/google/rt/runtime.go
index b74bc10..f52b2d9 100644
--- a/runtimes/google/rt/runtime.go
+++ b/runtimes/google/rt/runtime.go
@@ -21,7 +21,6 @@
"v.io/core/veyron2/vlog"
"v.io/core/veyron2/vtrace"
- "v.io/core/veyron/lib/exec"
"v.io/core/veyron/lib/flags"
_ "v.io/core/veyron/lib/stats/sysstats"
iipc "v.io/core/veyron/runtimes/google/ipc"
@@ -39,7 +38,6 @@
streamManagerKey = contextKey(iota)
clientKey
namespaceKey
- loggerKey
principalKey
reservedNameKey
profileKey
@@ -63,26 +61,16 @@
opts []ipc.ServerOpt
}
-// TODO(mattr,suharshs): Decide if ROpts would be better than this.
+// TODO(mattr,suharshs): Decide if Options would be better than this.
func Init(ctx *context.T, appCycle veyron2.AppCycle, protocols []string, listenSpec *ipc.ListenSpec, flags flags.RuntimeFlags,
reservedDispatcher ipc.Dispatcher, dispatcherOpts ...ipc.ServerOpt) (*Runtime, *context.T, veyron2.Shutdown, error) {
r := &Runtime{deps: dependency.NewGraph()}
- handle, err := exec.GetChildHandle()
- switch err {
- case exec.ErrNoVersion:
- // The process has not been started through the veyron exec
- // library. No further action is needed.
- case nil:
- // The process has been started through the veyron exec
- // library.
- default:
+ err := vlog.ConfigureLibraryLoggerFromFlags()
+ if err != nil {
return nil, nil, nil, err
}
- r.initLogging(ctx)
- ctx = context.WithValue(ctx, loggerKey, vlog.Log)
-
// Setup the initial trace.
ctx, err = ivtrace.Init(ctx, flags.Vtrace)
if err != nil {
@@ -148,7 +136,7 @@
}
// Initialize security.
- principal, err := initSecurity(ctx, handle, flags.Credentials, client)
+ principal, err := initSecurity(ctx, flags.Credentials, client)
if err != nil {
return nil, nil, nil, err
}
@@ -160,20 +148,11 @@
return nil, nil, nil, err
}
- // Initialize management.
- if err := r.initMgmt(ctx, r.GetAppCycle(ctx), handle); err != nil {
- return nil, nil, nil, err
- }
-
ctx = r.SetBackgroundContext(ctx)
// TODO(suharshs,mattr): Go through the rt.Cleanup function and make sure everything
// gets cleaned up.
- if handle != nil {
- handle.SetReady()
- }
-
return r, ctx, r.shutdown, nil
}
@@ -192,17 +171,15 @@
return nil
}
+func (r *Runtime) Init(ctx *context.T) error {
+ return r.initMgmt(ctx)
+}
+
func (r *Runtime) shutdown() {
r.deps.CloseAndWaitForAll()
vlog.FlushLog()
}
-// initLogging configures logging for the runtime. It needs to be called after
-// flag.Parse and after signal handling has been initialized.
-func (r *Runtime) initLogging(ctx *context.T) error {
- return vlog.ConfigureLibraryLoggerFromFlags()
-}
-
func (r *Runtime) initSignalHandling(ctx *context.T) {
// TODO(caprita): Given that our device manager implementation is to
// kill all child apps when the device manager dies, we should
@@ -394,19 +371,6 @@
return ns
}
-func (*Runtime) SetNewLogger(ctx *context.T, name string, opts ...vlog.LoggingOpts) (*context.T, vlog.Logger, error) {
- logger, err := vlog.NewLogger(name, opts...)
- if err == nil {
- ctx = context.WithValue(ctx, loggerKey, logger)
- }
- return ctx, logger, err
-}
-
-func (*Runtime) GetLogger(ctx *context.T) vlog.Logger {
- logger, _ := ctx.Value(loggerKey).(vlog.Logger)
- return logger
-}
-
func (*Runtime) GetAppCycle(ctx *context.T) veyron2.AppCycle {
appCycle, _ := ctx.Value(appCycleKey).(veyron2.AppCycle)
return appCycle
diff --git a/runtimes/google/rt/security.go b/runtimes/google/rt/security.go
index ab640df..b4a3aef 100644
--- a/runtimes/google/rt/security.go
+++ b/runtimes/google/rt/security.go
@@ -18,8 +18,8 @@
"v.io/core/veyron/security/agent"
)
-func initSecurity(ctx *context.T, handle *exec.ChildHandle, credentials string, client ipc.Client) (security.Principal, error) {
- principal, err := setupPrincipal(ctx, handle, credentials, client)
+func initSecurity(ctx *context.T, credentials string, client ipc.Client) (security.Principal, error) {
+ principal, err := setupPrincipal(ctx, credentials, client)
if err != nil {
return nil, err
}
@@ -31,13 +31,13 @@
return principal, nil
}
-func setupPrincipal(ctx *context.T, handle *exec.ChildHandle, credentials string, client ipc.Client) (security.Principal, error) {
+func setupPrincipal(ctx *context.T, credentials string, client ipc.Client) (security.Principal, error) {
var err error
var principal security.Principal
if principal, _ = ctx.Value(principalKey).(security.Principal); principal != nil {
return principal, nil
}
- if fd, err := agentFD(handle); err != nil {
+ if fd, err := agentFD(); err != nil {
return nil, err
} else if fd >= 0 {
return connectToAgent(ctx, fd, client)
@@ -66,7 +66,11 @@
// agentFD returns a non-negative file descriptor to be used to communicate with
// the security agent if the current process has been configured to use the
// agent.
-func agentFD(handle *exec.ChildHandle) (int, error) {
+func agentFD() (int, error) {
+ handle, err := exec.GetChildHandle()
+ if err != nil && err != exec.ErrNoVersion {
+ return -1, err
+ }
var fd string
if handle != nil {
// We were started by a parent (presumably, device manager).
diff --git a/security/agent/agentd/main.go b/security/agent/agentd/main.go
index c011d8a..ec7babd 100644
--- a/security/agent/agentd/main.go
+++ b/security/agent/agentd/main.go
@@ -81,13 +81,11 @@
vlog.Panic("failed to set principal for ctx: %v", err)
}
- log := veyron2.GetLogger(ctx)
-
if err = os.Setenv(agent.FdVarName, "3"); err != nil {
- log.Fatalf("setenv: %v", err)
+ vlog.Fatalf("setenv: %v", err)
}
if err = os.Setenv(consts.VeyronCredentials, ""); err != nil {
- log.Fatalf("setenv: %v", err)
+ vlog.Fatalf("setenv: %v", err)
}
if *keypath == "" && passphrase != nil {
@@ -101,11 +99,11 @@
// Start running our server.
var sock, mgrSock *os.File
if sock, err = server.RunAnonymousAgent(ctx, p); err != nil {
- log.Fatalf("RunAnonymousAgent: %v", err)
+ vlog.Fatalf("RunAnonymousAgent: %v", err)
}
if *keypath != "" {
if mgrSock, err = server.RunKeyManager(ctx, *keypath, passphrase); err != nil {
- log.Fatalf("RunKeyManager: %v", err)
+ vlog.Fatalf("RunKeyManager: %v", err)
}
}
@@ -123,7 +121,7 @@
err = cmd.Start()
if err != nil {
- log.Fatalf("Error starting child: %v", err)
+ vlog.Fatalf("Error starting child: %v", err)
}
shutdown := make(chan struct{})
go func() {
diff --git a/security/agent/pingpong/main.go b/security/agent/pingpong/main.go
index 532edd9..4b8c428 100644
--- a/security/agent/pingpong/main.go
+++ b/security/agent/pingpong/main.go
@@ -8,6 +8,7 @@
"v.io/core/veyron2/context"
"v.io/core/veyron2/ipc"
"v.io/core/veyron2/security"
+ "v.io/core/veyron2/vlog"
"v.io/core/veyron/lib/signals"
_ "v.io/core/veyron/profiles"
@@ -22,24 +23,22 @@
}
func clientMain(ctx *context.T) {
- log := veyron2.GetLogger(ctx)
- log.Info("Pinging...")
+ vlog.Info("Pinging...")
s := PingPongClient("pingpong")
pong, err := s.Ping(ctx, "ping")
if err != nil {
- log.Fatal("error pinging: ", err)
+ vlog.Fatal("error pinging: ", err)
}
fmt.Println(pong)
}
func serverMain(ctx *context.T) {
- log := veyron2.GetLogger(ctx)
s, err := veyron2.NewServer(ctx)
if err != nil {
- log.Fatal("failure creating server: ", err)
+ vlog.Fatal("failure creating server: ", err)
}
- log.Info("Waiting for ping")
+ vlog.Info("Waiting for ping")
serverPong := PingPongServer(&pongd{})
@@ -47,11 +46,11 @@
if endpoint, err := s.Listen(spec); err == nil {
fmt.Printf("Listening at: %v\n", endpoint)
} else {
- log.Fatal("error listening to service: ", err)
+ vlog.Fatal("error listening to service: ", err)
}
if err := s.Serve("pingpong", serverPong, allowEveryone{}); err != nil {
- log.Fatal("error serving service: ", err)
+ vlog.Fatal("error serving service: ", err)
}
// Wait forever.
@@ -63,8 +62,6 @@
func (allowEveryone) Authorize(security.Context) error { return nil }
func main() {
- flag.Parse()
-
ctx, shutdown := veyron2.Init()
defer shutdown()
diff --git a/services/mgmt/device/impl/app_service.go b/services/mgmt/device/impl/app_service.go
index 940df40..1538c98 100644
--- a/services/mgmt/device/impl/app_service.go
+++ b/services/mgmt/device/impl/app_service.go
@@ -119,7 +119,6 @@
"io/ioutil"
"os"
"os/exec"
- "os/user"
"path"
"path/filepath"
"reflect"
@@ -677,56 +676,6 @@
return instanceDir, instanceID, nil
}
-// isSetuid is defined like this so we can override its
-// implementation for tests.
-var isSetuid = func(fileStat os.FileInfo) bool {
- vlog.VI(2).Infof("running the original isSetuid")
- return fileStat.Mode()&os.ModeSetuid == os.ModeSetuid
-}
-
-// systemAccountForHelper returns the uname that the helper uses to invoke the
-// application. If the helper exists and is setuid, the device manager
-// requires that there is a uname associated with the Veyron
-// identity that requested starting an application.
-// TODO(rjkroege): This function assumes a desktop installation target
-// and is probably not a good fit in other contexts. Revisit the design
-// as appropriate. This function also internalizes a decision as to when
-// it is possible to start an application that needs to be made explicit.
-func systemAccountForHelper(ctx ipc.ServerContext, helperPath string, uat BlessingSystemAssociationStore) (systemName string, err error) {
- identityNames := ctx.RemoteBlessings().ForContext(ctx)
- helperStat, err := os.Stat(helperPath)
- if err != nil {
- vlog.Errorf("Stat(%v) failed: %v. helper is required.", helperPath, err)
- return "", verror2.Make(ErrOperationFailed, ctx.Context())
- }
- haveHelper := isSetuid(helperStat)
- systemName, present := uat.SystemAccountForBlessings(identityNames)
-
- switch {
- case haveHelper && present:
- return systemName, nil
- case haveHelper && !present:
- // The helper is owned by the device manager and installed as
- // setuid root. Therefore, the device manager must never run an
- // app as itself to prevent an app trivially granting itself
- // root permissions. There must be an associated uname for the
- // account in this case.
- return "", verror2.Make(verror2.NoAccess, ctx.Context(), "use of setuid helper requires an associated uname.")
- case !haveHelper:
- // When the helper is not setuid, the helper can't change the
- // app's uid so just run the app as the device manager's uname
- // whether or not there is an association.
- vlog.VI(1).Infof("helper not setuid. Device manager will invoke app with its own userid")
- user, err := user.Current()
- if err != nil {
- vlog.Errorf("user.Current() failed: %v", err)
- return "", verror2.Make(ErrOperationFailed, ctx.Context())
- }
- return user.Username, nil
- }
- return "", verror2.Make(ErrOperationFailed, ctx.Context())
-}
-
func genCmd(instanceDir, helperPath, systemName string, nsRoots []string) (*exec.Cmd, error) {
versionLink := filepath.Join(instanceDir, "version")
versionDir, err := filepath.EvalSymlinks(versionLink)
@@ -745,7 +694,15 @@
}
cmd := exec.Command(helperPath)
- cmd.Args = append(cmd.Args, "--username", systemName)
+
+ switch yes, err := suidHelper.suidhelperEnabled(systemName, helperPath); {
+ case err != nil:
+ return nil, err
+ case yes:
+ cmd.Args = append(cmd.Args, "--username", systemName)
+ case !yes:
+ cmd.Args = append(cmd.Args, "--username", systemName, "--dryrun")
+ }
var nsRootEnvs []string
for i, r := range nsRoots {
@@ -908,12 +865,7 @@
return nil, err
}
- systemName, err := systemAccountForHelper(call, helper, i.uat)
- if err != nil {
- cleanupDir(instanceDir, helper)
- return nil, err
- }
-
+ systemName := suidHelper.usernameForPrincipal(call, i.uat)
if err := saveSystemNameForInstance(instanceDir, systemName); err != nil {
cleanupDir(instanceDir, helper)
return nil, err
@@ -956,11 +908,7 @@
return err
}
- systemName, err := systemAccountForHelper(call, i.config.Helper, i.uat)
- if err != nil {
- return err
- }
-
+ systemName := suidHelper.usernameForPrincipal(call, i.uat)
startSystemName, err := readSystemNameForInstance(instanceDir)
if err != nil {
return err
diff --git a/services/mgmt/device/impl/helper_manager.go b/services/mgmt/device/impl/helper_manager.go
new file mode 100644
index 0000000..9e935d2
--- /dev/null
+++ b/services/mgmt/device/impl/helper_manager.go
@@ -0,0 +1,69 @@
+package impl
+
+import (
+ "os"
+ "os/user"
+
+ "v.io/core/veyron2/ipc"
+ "v.io/core/veyron2/verror2"
+ "v.io/core/veyron2/vlog"
+)
+
+type suidHelperState string
+
+var suidHelper suidHelperState
+
+func init() {
+ u, err := user.Current()
+ if err != nil {
+ vlog.Panicf("devicemanager has no current user: %v", err)
+ }
+ suidHelper = suidHelperState(u.Username)
+}
+
+// isSetuid is defined like this so we can override its
+// implementation for tests.
+var isSetuid = func(fileStat os.FileInfo) bool {
+ vlog.VI(2).Infof("running the original isSetuid")
+ return fileStat.Mode()&os.ModeSetuid == os.ModeSetuid
+}
+
+// unameRequiresSuidhelper determines if the the suidhelper must exist
+// and be setuid to run an application as system user un. If false, the
+// setuidhelper must be invoked with the --dryrun flag to skip making
+// system calls that will fail or provide apps with a trivial
+// priviledge escalation.
+func (dn suidHelperState) suidhelperEnabled(un, helperPath string) (bool, error) {
+ helperStat, err := os.Stat(helperPath)
+ if err != nil {
+ vlog.Errorf("Stat(%v) failed: %v. helper is required.", helperPath, err)
+ return false, verror2.Make(ErrOperationFailed, nil)
+ }
+ haveHelper := isSetuid(helperStat)
+
+ switch {
+ case haveHelper && string(dn) != un:
+ return true, nil
+ case haveHelper && string(dn) == un:
+ return false, verror2.Make(verror2.NoAccess, nil)
+ default:
+ return false, nil
+ }
+ // Keep the compiler happy.
+ return false, nil
+}
+
+// usernameForVanadiumPrincipal returns the system name that the
+// devicemanager will use to invoke apps.
+// TODO(rjkroege): This code assumes a desktop target and will need
+// to be reconsidered for embedded contexts.
+func (i suidHelperState) usernameForPrincipal(ctx ipc.ServerContext, uat BlessingSystemAssociationStore) string {
+ identityNames := ctx.RemoteBlessings().ForContext(ctx)
+ systemName, present := uat.SystemAccountForBlessings(identityNames)
+
+ if present {
+ return systemName
+ } else {
+ return string(i)
+ }
+}
diff --git a/services/mgmt/suidhelper/impl/args.go b/services/mgmt/suidhelper/impl/args.go
index 67003a3..185bae8 100644
--- a/services/mgmt/suidhelper/impl/args.go
+++ b/services/mgmt/suidhelper/impl/args.go
@@ -36,7 +36,7 @@
var (
flagUsername, flagWorkspace, flagLogDir, flagRun *string
flagMinimumUid *int64
- flagRemove *bool
+ flagRemove, flagDryrun *bool
)
func init() {
@@ -53,6 +53,7 @@
flagRun = sflag.Run
flagMinimumUid = sflag.MinimumUid
flagRemove = sflag.Remove
+ flagDryrun = sflag.Dryrun
}
// ParseArguments populates the WorkParameter object from the provided args
@@ -88,6 +89,8 @@
return fmt.Errorf("suidhelper does not permit uids less than %d", *flagMinimumUid)
}
+ wp.dryrun = *flagDryrun
+
// Preserve the arguments for examination by the test harness if executed
// in the course of a test.
if os.Getenv("VEYRON_SUIDHELPER_TEST") != "" {
diff --git a/services/mgmt/suidhelper/impl/args_test.go b/services/mgmt/suidhelper/impl/args_test.go
index 9358e9f..9341fc7 100644
--- a/services/mgmt/suidhelper/impl/args_test.go
+++ b/services/mgmt/suidhelper/impl/args_test.go
@@ -85,6 +85,24 @@
fmt.Errorf("suidhelper does not permit uids less than 501"),
WorkParameters{},
},
+
+ {
+ []string{"setuidhelper", "--minuid", "1", "--username", testUserName, "--workspace", "/hello",
+ "--logdir", "/logging", "--run", "/bin/veyron", "--dryrun", "--", "one", "two"},
+ []string{"A=B"},
+ nil,
+ WorkParameters{
+ uid: testUid,
+ gid: testGid,
+ workspace: "/hello",
+ logDir: "/logging",
+ argv0: "/bin/veyron",
+ argv: []string{"/bin/veyron", "one", "two"},
+ envv: []string{"A=B"},
+ dryrun: true,
+ remove: false,
+ },
+ },
}
for _, c := range cases {
diff --git a/services/mgmt/suidhelper/impl/flag/flag.go b/services/mgmt/suidhelper/impl/flag/flag.go
index f8b53e1..273f56b 100644
--- a/services/mgmt/suidhelper/impl/flag/flag.go
+++ b/services/mgmt/suidhelper/impl/flag/flag.go
@@ -15,7 +15,7 @@
var (
Username, Workspace, LogDir, Run *string
MinimumUid *int64
- Remove *bool
+ Remove, Dryrun *bool
)
func init() {
@@ -29,6 +29,7 @@
Run = fs.String("run", "", "Path to the application to exec.")
MinimumUid = fs.Int64("minuid", uidThreshold, "UIDs cannot be less than this number.")
Remove = fs.Bool("rm", false, "Remove the file trees given as command-line arguments.")
+ Dryrun = fs.Bool("dryrun", false, "Elides root-requiring systemcalls.")
}
const uidThreshold = 501
diff --git a/services/mgmt/suidhelper/impl/system.go b/services/mgmt/suidhelper/impl/system.go
index 60a7b92..8a93d91 100644
--- a/services/mgmt/suidhelper/impl/system.go
+++ b/services/mgmt/suidhelper/impl/system.go
@@ -34,22 +34,37 @@
}
func (hw *WorkParameters) Exec() error {
+ attr := new(syscall.ProcAttr)
+
+ if dir, err := os.Getwd(); err != nil {
+ log.Printf("error Getwd(): %v\n", err)
+ return fmt.Errorf("os.Getwd failed: %v", err)
+ attr.Dir = dir
+ }
+ attr.Env = hw.envv
+
if hw.dryrun {
log.Printf("[dryrun] syscall.Setgid(%d)", hw.gid)
log.Printf("[dryrun] syscall.Setuid(%d)", hw.uid)
} else {
- // NOTE(caprita): Commenting this out since it's broken with go
- // 1.4, to make the integration test pass. go/vcl/8240 will fix
- // it properly.
-
- // if err := syscall.Setgid(hw.gid); err != nil {
- // return fmt.Errorf("syscall.Setgid(%d) failed: %v", hw.gid, err)
- // }
- // if err := syscall.Setuid(hw.uid); err != nil {
- // return fmt.Errorf("syscall.Setuid(%d) failed: %v", hw.uid, err)
- // }
+ attr.Sys = new(syscall.SysProcAttr)
+ attr.Sys.Credential = new(syscall.Credential)
+ attr.Sys.Credential.Gid = uint32(hw.gid)
+ attr.Sys.Credential.Uid = uint32(hw.uid)
}
- return syscall.Exec(hw.argv0, hw.argv, hw.envv)
+
+ _, _, err := syscall.StartProcess(hw.argv0, hw.argv, attr)
+ if err != nil {
+ if !hw.dryrun {
+ log.Printf("StartProcess failed: attr: %#v, attr.Sys: %#v, attr.Sys.Cred: %#v error: %v\n", attr, attr.Sys, attr.Sys.Credential, err)
+ } else {
+ log.Printf("StartProcess failed: %v", err)
+ }
+ return fmt.Errorf("syscall.StartProcess(%s) failed: %v", hw.argv0, err)
+ }
+ // TODO(rjkroege): Return the pid to the node manager.
+ os.Exit(0)
+ return nil // Not reached.
}
func (hw *WorkParameters) Remove() error {
diff --git a/tools/application/impl.go b/tools/application/impl.go
index 026f2c3..ef0bf9e 100644
--- a/tools/application/impl.go
+++ b/tools/application/impl.go
@@ -17,7 +17,9 @@
"v.io/lib/cmdline"
)
-func getEnvelopeJSON(ctx *context.T, app repository.ApplicationClientMethods, profiles string) ([]byte, error) {
+func getEnvelopeJSON(app repository.ApplicationClientMethods, profiles string) ([]byte, error) {
+ ctx, cancel := context.WithTimeout(gctx, time.Minute)
+ defer cancel()
env, err := app.Match(ctx, strings.Split(profiles, ","))
if err != nil {
return nil, err
@@ -29,11 +31,13 @@
return j, nil
}
-func putEnvelopeJSON(ctx *context.T, app repository.ApplicationClientMethods, profiles string, j []byte) error {
+func putEnvelopeJSON(app repository.ApplicationClientMethods, profiles string, j []byte) error {
var env application.Envelope
if err := json.Unmarshal(j, &env); err != nil {
return fmt.Errorf("Unmarshal(%v) failed: %v", string(j), err)
}
+ ctx, cancel := context.WithTimeout(gctx, time.Minute)
+ defer cancel()
if err := app.Put(ctx, strings.Split(profiles, ","), env); err != nil {
return err
}
@@ -66,9 +70,7 @@
}
name, profiles := args[0], args[1]
app := repository.ApplicationClient(name)
- ctx, cancel := context.WithTimeout(gctx, time.Minute)
- defer cancel()
- j, err := getEnvelopeJSON(ctx, app, profiles)
+ j, err := getEnvelopeJSON(app, profiles)
if err != nil {
return err
}
@@ -81,29 +83,40 @@
Name: "put",
Short: "Add the given envelope to the application for the given profiles.",
Long: "Add the given envelope to the application for the given profiles.",
- ArgsName: "<application> <profiles> <envelope>",
+ ArgsName: "<application> <profiles> [<envelope>]",
ArgsLong: `
<application> is the full name of the application.
<profiles> is a comma-separated list of profiles.
-<envelope> is the file that contains a JSON-encoded envelope.`,
+<envelope> is the file that contains a JSON-encoded envelope. If this file is
+not provided, the user will be prompted to enter the data manually.`,
}
func runPut(cmd *cmdline.Command, args []string) error {
- if expected, got := 3, len(args); expected != got {
- return cmd.UsageErrorf("put: incorrect number of arguments, expected %d, got %d", expected, got)
+ if got := len(args); got != 2 && got != 3 {
+ return cmd.UsageErrorf("put: incorrect number of arguments, expected 2 or 3, got %d", got)
}
- name, profiles, envelope := args[0], args[1], args[2]
+ name, profiles := args[0], args[1]
app := repository.ApplicationClient(name)
- j, err := ioutil.ReadFile(envelope)
- if err != nil {
- return fmt.Errorf("ReadFile(%v): %v", envelope, err)
+ if len(args) == 3 {
+ envelope := args[2]
+ j, err := ioutil.ReadFile(envelope)
+ if err != nil {
+ return fmt.Errorf("ReadFile(%v): %v", envelope, err)
+ }
+ if err = putEnvelopeJSON(app, profiles, j); err != nil {
+ return err
+ }
+ fmt.Fprintln(cmd.Stdout(), "Application envelope added successfully.")
+ return nil
}
- ctx, cancel := context.WithTimeout(gctx, time.Minute)
- defer cancel()
- if err = putEnvelopeJSON(ctx, app, profiles, j); err != nil {
+ env := application.Envelope{Args: []string{}, Env: []string{}, Packages: map[string]string{}}
+ j, err := json.MarshalIndent(env, "", " ")
+ if err != nil {
+ return fmt.Errorf("MarshalIndent() failed: %v", err)
+ }
+ if err := editAndPutEnvelopeJSON(cmd, app, profiles, j); err != nil {
return err
}
- fmt.Fprintln(cmd.Stdout(), "Application envelope added successfully.")
return nil
}
@@ -150,6 +163,18 @@
}
name, profile := args[0], args[1]
app := repository.ApplicationClient(name)
+
+ envData, err := getEnvelopeJSON(app, profile)
+ if err != nil {
+ return err
+ }
+ if err := editAndPutEnvelopeJSON(cmd, app, profile, envData); err != nil {
+ return err
+ }
+ return nil
+}
+
+func editAndPutEnvelopeJSON(cmd *cmdline.Command, app repository.ApplicationClientMethods, profile string, envData []byte) error {
f, err := ioutil.TempFile("", "application-edit-")
if err != nil {
return fmt.Errorf("TempFile() failed: %v", err)
@@ -157,13 +182,6 @@
fileName := f.Name()
f.Close()
defer os.Remove(fileName)
-
- ctx, cancel := context.WithTimeout(gctx, time.Minute)
- defer cancel()
- envData, err := getEnvelopeJSON(ctx, app, profile)
- if err != nil {
- return err
- }
if err = ioutil.WriteFile(fileName, envData, os.FileMode(0644)); err != nil {
return err
}
@@ -191,7 +209,7 @@
fmt.Fprintln(cmd.Stdout(), "Nothing changed")
return nil
}
- if err = putEnvelopeJSON(ctx, app, profile, newData); err != nil {
+ if err = putEnvelopeJSON(app, profile, newData); err != nil {
fmt.Fprintf(cmd.Stdout(), "Error: %v\n", err)
if ans := promptUser(cmd, "Try again? [y/N] "); strings.ToUpper(ans) == "Y" {
continue