| // Copyright 2015 The Vanadium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package rt |
| |
| import ( |
| "fmt" |
| "os" |
| "os/user" |
| "strconv" |
| "syscall" |
| |
| "v.io/v23/context" |
| "v.io/v23/naming" |
| "v.io/v23/security" |
| "v.io/v23/verror" |
| "v.io/x/ref/envvar" |
| "v.io/x/ref/lib/exec" |
| "v.io/x/ref/lib/mgmt" |
| vsecurity "v.io/x/ref/lib/security" |
| inaming "v.io/x/ref/profiles/internal/naming" |
| "v.io/x/ref/services/agent/agentlib" |
| ) |
| |
| func (r *Runtime) initPrincipal(ctx *context.T, credentials string) (principal security.Principal, deps []interface{}, shutdown func(), err error) { |
| if principal, _ = ctx.Value(principalKey).(security.Principal); principal != nil { |
| return principal, nil, func() {}, nil |
| } |
| if len(credentials) > 0 { |
| // Explicitly specified credentials, ignore the agent. |
| if _, fd, _ := agentEP(); fd >= 0 { |
| syscall.Close(fd) |
| } |
| // TODO(ataly, ashankar): If multiple runtimes are getting |
| // initialized at the same time from the same |
| // envvar.Credentials we will need some kind of locking for the |
| // credential files. |
| if principal, err = vsecurity.LoadPersistentPrincipal(credentials, nil); err != nil { |
| if os.IsNotExist(err) { |
| if principal, err = vsecurity.CreatePersistentPrincipal(credentials, nil); err != nil { |
| return principal, nil, nil, err |
| } |
| return principal, nil, func() {}, vsecurity.InitDefaultBlessings(principal, defaultBlessingName()) |
| } |
| return nil, nil, nil, err |
| } |
| return principal, nil, func() {}, nil |
| } |
| // Use credentials stored in the agent. |
| if ep, _, err := agentEP(); err != nil { |
| return nil, nil, nil, err |
| } else if ep != nil { |
| // Use a new stream manager and an "incomplete" client (the |
| // principal is nil) to talk to the agent. |
| // |
| // The lack of a principal works out for the rpc.Client |
| // only because the agent uses anonymous unix sockets and |
| // the SecurityNone option. |
| // |
| // Using a distinct stream manager to manage agent-related |
| // connections helps isolate these connections to the agent |
| // from management of any other connections created in the |
| // process (such as future RPCs to other services). |
| if ctx, err = r.WithNewStreamManager(ctx); err != nil { |
| return nil, nil, nil, err |
| } |
| client := r.GetClient(ctx) |
| |
| // We reparent the context we use to construct the agent. |
| // We do this because the agent needs to be able to make RPCs |
| // during runtime shutdown. |
| ctx, shutdown = context.WithRootCancel(ctx) |
| |
| if principal, err = agentlib.NewAgentPrincipal(ctx, ep, client); err != nil { |
| shutdown() |
| client.Close() |
| return nil, nil, nil, err |
| } |
| return principal, []interface{}{client}, shutdown, nil |
| } |
| // No agent, no explicit credentials specified: - create a new principal and blessing in memory. |
| if principal, err = vsecurity.NewPrincipal(); err != nil { |
| return principal, nil, nil, err |
| } |
| return principal, nil, func() {}, vsecurity.InitDefaultBlessings(principal, defaultBlessingName()) |
| } |
| |
| func parseAgentFD(ep naming.Endpoint) (int, error) { |
| fd := ep.Addr().String() |
| ifd, err := strconv.Atoi(fd) |
| if err != nil { |
| ifd = -1 |
| } |
| return ifd, nil |
| } |
| |
| // agentEP returns an Endpoint to be used to communicate with |
| // the security agent if the current process has been configured to use the |
| // agent. |
| func agentEP() (naming.Endpoint, int, error) { |
| handle, err := exec.GetChildHandle() |
| if err != nil && verror.ErrorID(err) != exec.ErrNoVersion.ID { |
| return nil, -1, err |
| } |
| var endpoint string |
| if handle != nil { |
| // We were started by a parent (presumably, device manager). |
| endpoint, _ = handle.Config.Get(mgmt.SecurityAgentEndpointConfigKey) |
| } else { |
| endpoint = os.Getenv(envvar.AgentEndpoint) |
| } |
| if endpoint == "" { |
| return nil, -1, nil |
| } |
| ep, err := inaming.NewEndpoint(endpoint) |
| if err != nil { |
| return nil, -1, err |
| } |
| |
| // Don't let children accidentally inherit the agent connection. |
| fd, err := parseAgentFD(ep) |
| if err != nil { |
| return nil, -1, err |
| } |
| if fd >= 0 { |
| syscall.CloseOnExec(fd) |
| } |
| return ep, fd, nil |
| } |
| |
| func defaultBlessingName() string { |
| var name string |
| if user, _ := user.Current(); user != nil && len(user.Username) > 0 { |
| name = user.Username |
| } else { |
| name = "anonymous" |
| } |
| if host, _ := os.Hostname(); len(host) > 0 { |
| name = name + "@" + host |
| } |
| return fmt.Sprintf("%s-%d", name, os.Getpid()) |
| } |