blob: 21ebe014d215cdc3a75e210a3238654584719f64 [file] [log] [blame]
Jiri Simsad7616c92015-03-24 23:44:30 -07001// Copyright 2015 The Vanadium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
Jiri Simsa5293dcb2014-05-10 09:56:38 -07005package impl
6
7import (
Bogdan Capritac87a9142014-07-21 10:38:13 -07008 "fmt"
Gautham82bb9952014-08-28 14:11:51 -07009 "os"
Robert Kroegeracc778b2014-11-03 17:17:21 -080010 "path"
Gautham82bb9952014-08-28 14:11:51 -070011 "path/filepath"
Bogdan Caprita4d67c042014-08-19 10:41:19 -070012 "strings"
Gautham6fe61e52014-09-16 13:58:17 -070013 "sync"
Jiri Simsa24e87aa2014-06-09 09:27:34 -070014
Jiri Simsa6ac95222015-02-23 16:11:49 -080015 "v.io/v23/context"
Jiri Simsa6ac95222015-02-23 16:11:49 -080016 "v.io/v23/naming"
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070017 "v.io/v23/rpc"
Jiri Simsa6ac95222015-02-23 16:11:49 -080018 "v.io/v23/security"
Todd Wang387d8a42015-03-30 17:09:05 -070019 "v.io/v23/security/access"
Todd Wang94c9d0b2015-04-01 14:27:00 -070020 "v.io/v23/services/device"
21 "v.io/v23/services/pprof"
22 "v.io/v23/services/stats"
gauthamtfd1e34e2015-03-05 15:30:52 -080023 "v.io/v23/vdl"
24 "v.io/v23/vdlroot/signature"
Jiri Simsa6ac95222015-02-23 16:11:49 -080025 "v.io/v23/verror"
Jiri Simsa337af232015-02-27 14:36:46 -080026 "v.io/x/lib/vlog"
Todd Wang8123b5e2015-05-14 18:44:43 -070027 "v.io/x/ref"
Todd Wangb3511492015-04-07 23:32:34 -070028 "v.io/x/ref/services/agent/keymgr"
29 s_device "v.io/x/ref/services/device"
30 "v.io/x/ref/services/device/internal/config"
Bogdan Caprita040603b2015-06-23 18:19:30 -070031 "v.io/x/ref/services/device/internal/errors"
Todd Wangfb939032015-04-08 16:42:44 -070032 "v.io/x/ref/services/internal/logreaderlib"
Adam Sadovskya4d4a692015-04-20 11:36:49 -070033 "v.io/x/ref/services/internal/pathperms"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070034)
35
Bogdan Caprita2b219362014-12-09 17:03:33 -080036// internalState wraps state shared between different device manager
Bogdan Caprita4d67c042014-08-19 10:41:19 -070037// invocations.
38type internalState struct {
Bogdan Caprita29a3b352015-01-16 16:28:49 -080039 callback *callbackState
40 updating *updatingState
41 securityAgent *securityAgentState
42 restartHandler func()
Robin Thellend9299b782015-02-03 08:42:46 -080043 testMode bool
Robert Kroegercc9f55d2015-05-20 16:25:36 -070044 // reap is the app process monitoring subsystem.
45 reap *reaper
Robert Kroeger1f6b8912015-06-18 10:29:39 -070046 // tidying is the automatic state tidying subsystem.
47 tidying chan<- tidyRequests
Bogdan Caprita4d67c042014-08-19 10:41:19 -070048}
49
Bogdan Caprita2b219362014-12-09 17:03:33 -080050// dispatcher holds the state of the device manager dispatcher.
Jiri Simsa5293dcb2014-05-10 09:56:38 -070051type dispatcher struct {
Bogdan Caprita4d67c042014-08-19 10:41:19 -070052 // internal holds the state that persists across RPC method invocations.
Bogdan Capritac87a9142014-07-21 10:38:13 -070053 internal *internalState
Bogdan Caprita2b219362014-12-09 17:03:33 -080054 // config holds the device manager's (immutable) configuration state.
Bogdan Caprita4d67c042014-08-19 10:41:19 -070055 config *config.State
Gautham6fe61e52014-09-16 13:58:17 -070056 // dispatcherMutex is a lock for coordinating concurrent access to some
57 // dispatcher methods.
Bogdan Caprita7f491672014-11-13 14:51:08 -080058 mu sync.RWMutex
59 // TODO(rjkroege): Consider moving this inside internal.
Adam Sadovskya4d4a692015-04-20 11:36:49 -070060 uat BlessingSystemAssociationStore
61 permsStore *pathperms.PathStore
Robin Thellendacaa4322015-02-05 11:00:28 -080062 // Namespace
63 mtAddress string // The address of the local mounttable.
Jiri Simsa5293dcb2014-05-10 09:56:38 -070064}
65
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070066var _ rpc.Dispatcher = (*dispatcher)(nil)
Benjamin Prosnitzfdfbf7b2014-10-08 09:47:21 -070067
Bogdan Caprita4d67c042014-08-19 10:41:19 -070068const (
69 appsSuffix = "apps"
Bogdan Caprita9c4aa222014-12-10 14:46:30 -080070 deviceSuffix = "device"
Bogdan Caprita4d67c042014-08-19 10:41:19 -070071 configSuffix = "cfg"
Todd Wang34ed4c62014-11-26 15:15:52 -080072
Todd Wangcd4b3cc2015-04-06 16:42:02 -070073 pkgPath = "v.io/x/ref/services/device/internal/impl"
Bogdan Caprita4d67c042014-08-19 10:41:19 -070074)
75
76var (
Mike Burrows39bbaaf2015-03-24 11:27:32 -070077 errInvalidConfig = verror.Register(pkgPath+".errInvalidConfig", verror.NoRetry, "{1:}{2:} invalid config {3}{:_}")
78 errCantCreateAccountStore = verror.Register(pkgPath+".errCantCreateAccountStore", verror.NoRetry, "{1:}{2:} cannot create persistent store for identity to system account associations{:_}")
79 errCantCreateAppWatcher = verror.Register(pkgPath+".errCantCreateAppWatcher", verror.NoRetry, "{1:}{2:} cannot create app status watcher{:_}")
80 errNewAgentFailed = verror.Register(pkgPath+".errNewAgentFailed", verror.NoRetry, "{1:}{2:} NewAgent() failed{:_}")
Bogdan Caprita4d67c042014-08-19 10:41:19 -070081)
82
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070083// NewClaimableDispatcher returns an rpc.Dispatcher that allows the device to
Asim Shankar23dac322015-02-14 12:42:26 -080084// be Claimed if it hasn't been already and a channel that will be closed once
85// the device has been claimed.
86//
87// It returns (nil, nil) if the device is no longer claimable.
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070088func NewClaimableDispatcher(ctx *context.T, config *config.State, pairingToken string) (rpc.Dispatcher, <-chan struct{}) {
Asim Shankar23dac322015-02-14 12:42:26 -080089 var (
Adam Sadovskya4d4a692015-04-20 11:36:49 -070090 permsDir = PermsDir(config)
Cosmos Nicolaou7a4221f2015-06-21 08:02:23 -070091 permsStore = pathperms.NewPathStore(ctx)
Asim Shankar23dac322015-02-14 12:42:26 -080092 )
Adam Sadovskya4d4a692015-04-20 11:36:49 -070093 if _, _, err := permsStore.Get(permsDir); !os.IsNotExist(err) {
Asim Shankar23dac322015-02-14 12:42:26 -080094 return nil, nil
95 }
96 // The device is claimable only if Claim hasn't been called before. The
Adam Sadovskya4d4a692015-04-20 11:36:49 -070097 // existence of the Permissions file is an indication of a successful prior
Asim Shankar23dac322015-02-14 12:42:26 -080098 // call to Claim.
99 notify := make(chan struct{})
Adam Sadovskya4d4a692015-04-20 11:36:49 -0700100 return &claimable{token: pairingToken, permsStore: permsStore, permsDir: permsDir, notify: notify}, notify
Asim Shankar23dac322015-02-14 12:42:26 -0800101}
102
Bogdan Caprita2b219362014-12-09 17:03:33 -0800103// NewDispatcher is the device manager dispatcher factory.
Adam Sadovskya4d4a692015-04-20 11:36:49 -0700104func NewDispatcher(ctx *context.T, config *config.State, mtAddress string, testMode bool, restartHandler func(), permStore *pathperms.PathStore) (rpc.Dispatcher, error) {
Bogdan Capritac87a9142014-07-21 10:38:13 -0700105 if err := config.Validate(); err != nil {
Mike Burrows39bbaaf2015-03-24 11:27:32 -0700106 return nil, verror.New(errInvalidConfig, ctx, config, err)
Bogdan Capritac87a9142014-07-21 10:38:13 -0700107 }
Robert Kroeger1cb4a0d2014-10-20 11:55:38 -0700108 uat, err := NewBlessingSystemAssociationStore(config.Root)
109 if err != nil {
Mike Burrows39bbaaf2015-03-24 11:27:32 -0700110 return nil, verror.New(errCantCreateAccountStore, ctx, err)
Robert Kroeger1cb4a0d2014-10-20 11:55:38 -0700111 }
Arup Mukherjee746444f2015-04-16 19:13:24 -0700112 initSuidHelper(config.Helper)
Gautham82bb9952014-08-28 14:11:51 -0700113 d := &dispatcher{
Bogdan Capritac87a9142014-07-21 10:38:13 -0700114 internal: &internalState{
Bogdan Caprita29a3b352015-01-16 16:28:49 -0800115 callback: newCallbackState(config.Name),
116 updating: newUpdatingState(),
117 restartHandler: restartHandler,
Robin Thellend9299b782015-02-03 08:42:46 -0800118 testMode: testMode,
Robert Kroeger1f6b8912015-06-18 10:29:39 -0700119 tidying: newTidyingDaemon(config.Root),
Jiri Simsa70c32052014-06-18 11:38:21 -0700120 },
Adam Sadovskya4d4a692015-04-20 11:36:49 -0700121 config: config,
122 uat: uat,
123 permsStore: permStore,
124 mtAddress: mtAddress,
Gautham82bb9952014-08-28 14:11:51 -0700125 }
Robert Kroegere95ed6d2015-01-14 17:41:04 -0800126
Bogdan Caprita7f491672014-11-13 14:51:08 -0800127 // If we're in 'security agent mode', set up the key manager agent.
Todd Wang8123b5e2015-05-14 18:44:43 -0700128 if len(os.Getenv(ref.EnvAgentEndpoint)) > 0 {
Bogdan Caprita7f491672014-11-13 14:51:08 -0800129 if keyMgrAgent, err := keymgr.NewAgent(); err != nil {
Mike Burrows39bbaaf2015-03-24 11:27:32 -0700130 return nil, verror.New(errNewAgentFailed, ctx, err)
Bogdan Caprita7f491672014-11-13 14:51:08 -0800131 } else {
132 d.internal.securityAgent = &securityAgentState{
133 keyMgrAgent: keyMgrAgent,
134 }
135 }
136 }
Robert Kroegercc9f55d2015-05-20 16:25:36 -0700137 reap, err := newReaper(ctx, config.Root, &appRunner{
138 callback: d.internal.callback,
139 securityAgent: d.internal.securityAgent,
140 })
141 if err != nil {
142 return nil, verror.New(errCantCreateAppWatcher, ctx, err)
143 }
144 d.internal.reap = reap
145
Robin Thellend9299b782015-02-03 08:42:46 -0800146 if testMode {
147 return &testModeDispatcher{d}, nil
148 }
Gautham82bb9952014-08-28 14:11:51 -0700149 return d, nil
150}
151
Robert Kroeger936853a2015-01-28 17:42:55 -0800152// Shutdown the dispatcher.
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700153func Shutdown(rpcd rpc.Dispatcher) {
154 switch d := rpcd.(type) {
Robert Kroeger936853a2015-01-28 17:42:55 -0800155 case *dispatcher:
Robert Kroegercc9f55d2015-05-20 16:25:36 -0700156 d.internal.reap.shutdown()
Robert Kroeger936853a2015-01-28 17:42:55 -0800157 case *testModeDispatcher:
158 Shutdown(d.realDispatcher)
159 default:
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700160 vlog.Panicf("%v not a supported dispatcher type.", rpcd)
Robert Kroeger936853a2015-01-28 17:42:55 -0800161 }
162}
163
gauthamtfd1e34e2015-03-05 15:30:52 -0800164// Logging invoker that logs any error messages before returning.
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700165func newLoggingInvoker(obj interface{}) (rpc.Invoker, error) {
166 if invoker, ok := obj.(rpc.Invoker); ok {
gauthamtfd1e34e2015-03-05 15:30:52 -0800167 return &loggingInvoker{invoker}, nil
168 }
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700169 invoker, err := rpc.ReflectInvoker(obj)
gauthamtfd1e34e2015-03-05 15:30:52 -0800170 if err != nil {
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700171 vlog.Errorf("rpc.ReflectInvoker returned error: %v", err)
gauthamtfd1e34e2015-03-05 15:30:52 -0800172 return nil, err
173 }
174 return &loggingInvoker{invoker}, nil
175}
176
177type loggingInvoker struct {
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700178 invoker rpc.Invoker
gauthamtfd1e34e2015-03-05 15:30:52 -0800179}
180
181func (l *loggingInvoker) Prepare(method string, numArgs int) (argptrs []interface{}, tags []*vdl.Value, err error) {
182 argptrs, tags, err = l.invoker.Prepare(method, numArgs)
183 if err != nil {
184 vlog.Errorf("Prepare(%s %d) returned error: %v", method, numArgs, err)
185 }
186 return
187}
188
Todd Wang54feabe2015-04-15 23:38:26 -0700189func (l *loggingInvoker) Invoke(ctx *context.T, call rpc.StreamServerCall, method string, argptrs []interface{}) (results []interface{}, err error) {
190 results, err = l.invoker.Invoke(ctx, call, method, argptrs)
gauthamtfd1e34e2015-03-05 15:30:52 -0800191 if err != nil {
192 vlog.Errorf("Invoke(method:%s argptrs:%v) returned error: %v", method, argptrs, err)
193 }
194 return
195}
196
Todd Wang54feabe2015-04-15 23:38:26 -0700197func (l *loggingInvoker) Signature(ctx *context.T, call rpc.ServerCall) ([]signature.Interface, error) {
198 sig, err := l.invoker.Signature(ctx, call)
gauthamtfd1e34e2015-03-05 15:30:52 -0800199 if err != nil {
200 vlog.Errorf("Signature returned error: %v", err)
201 }
202 return sig, err
203}
204
Todd Wang54feabe2015-04-15 23:38:26 -0700205func (l *loggingInvoker) MethodSignature(ctx *context.T, call rpc.ServerCall, method string) (signature.Method, error) {
206 methodSig, err := l.invoker.MethodSignature(ctx, call, method)
gauthamtfd1e34e2015-03-05 15:30:52 -0800207 if err != nil {
208 vlog.Errorf("MethodSignature(%s) returned error: %v", method, err)
209 }
210 return methodSig, err
211}
212
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700213func (l *loggingInvoker) Globber() *rpc.GlobState {
gauthamtfd1e34e2015-03-05 15:30:52 -0800214 return l.invoker.Globber()
215}
216
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700217// DISPATCHER INTERFACE IMPLEMENTATION
Robin Thellenda02fe8f2014-11-19 09:58:29 -0800218func (d *dispatcher) Lookup(suffix string) (interface{}, security.Authorizer, error) {
gauthamtfd1e34e2015-03-05 15:30:52 -0800219 invoker, auth, err := d.internalLookup(suffix)
220 if err != nil {
221 return nil, nil, err
222 }
223 loggingInvoker, err := newLoggingInvoker(invoker)
224 if err != nil {
225 return nil, nil, err
226 }
227 return loggingInvoker, auth, nil
228}
229
Adam Sadovskya4d4a692015-04-20 11:36:49 -0700230func newTestableHierarchicalAuth(testMode bool, rootDir, childDir string, get pathperms.PermsGetter) (security.Authorizer, error) {
Robert Kroeger7a8b2222015-03-06 07:58:57 -0800231 if testMode {
Adam Sadovskya4d4a692015-04-20 11:36:49 -0700232 // In test mode, the device manager will not be able to read the
233 // Permissions, because they were signed with the key of the real device
234 // manager. It's not a problem because the testModeDispatcher overrides the
235 // authorizer anyway.
Robert Kroeger7a8b2222015-03-06 07:58:57 -0800236 return nil, nil
237 }
Adam Sadovskya4d4a692015-04-20 11:36:49 -0700238 return pathperms.NewHierarchicalAuthorizer(rootDir, childDir, get)
Robert Kroeger7a8b2222015-03-06 07:58:57 -0800239}
240
gauthamtfd1e34e2015-03-05 15:30:52 -0800241func (d *dispatcher) internalLookup(suffix string) (interface{}, security.Authorizer, error) {
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700242 components := strings.Split(suffix, "/")
243 for i := 0; i < len(components); i++ {
244 if len(components[i]) == 0 {
245 components = append(components[:i], components[i+1:]...)
246 i--
247 }
248 }
Robin Thellend9299b782015-02-03 08:42:46 -0800249
Adam Sadovskya4d4a692015-04-20 11:36:49 -0700250 // TODO(rjkroege): Permit the root Permissions to diverge for the device and
251 // app sub-namespaces of the device manager after claiming.
252 auth, err := newTestableHierarchicalAuth(d.internal.testMode, PermsDir(d.config), PermsDir(d.config), d.permsStore)
Robert Kroegere95ed6d2015-01-14 17:41:04 -0800253 if err != nil {
254 return nil, nil, err
255 }
256
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700257 if len(components) == 0 {
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700258 return rpc.ChildrenGlobberInvoker(deviceSuffix, appsSuffix), auth, nil
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700259 }
Bogdan Caprita2b219362014-12-09 17:03:33 -0800260 // The implementation of the device manager is split up into several
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700261 // invokers, which are instantiated depending on the receiver name
262 // prefix.
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700263 switch components[0] {
Bogdan Caprita2b219362014-12-09 17:03:33 -0800264 case deviceSuffix:
Bogdan Capritaa456f472014-12-10 10:18:03 -0800265 receiver := device.DeviceServer(&deviceService{
Bogdan Caprita29a3b352015-01-16 16:28:49 -0800266 callback: d.internal.callback,
267 updating: d.internal.updating,
268 restartHandler: d.internal.restartHandler,
269 config: d.config,
270 disp: d,
271 uat: d.uat,
Robin Thellend9299b782015-02-03 08:42:46 -0800272 securityAgent: d.internal.securityAgent,
Robert Kroeger1f6b8912015-06-18 10:29:39 -0700273 tidying: d.internal.tidying,
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700274 })
Robert Kroegere95ed6d2015-01-14 17:41:04 -0800275 return receiver, auth, nil
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700276 case appsSuffix:
Robin Thellend8a0f04f2014-11-17 10:40:24 -0800277 // Requests to apps/*/*/*/logs are handled locally by LogFileService.
Robin Thellendb9dd9bb2014-10-29 13:54:08 -0700278 // Requests to apps/*/*/*/pprof are proxied to the apps' __debug/pprof object.
279 // Requests to apps/*/*/*/stats are proxied to the apps' __debug/stats object.
Robin Thellend9bc8fcb2014-11-17 10:23:04 -0800280 // Everything else is handled by the Application server.
Robin Thellendac7128c2014-11-11 09:58:28 -0800281 if len(components) >= 5 {
Robin Thellend4c5266e2014-10-27 13:19:29 -0700282 appInstanceDir, err := instanceDir(d.config.Root, components[1:4])
283 if err != nil {
284 return nil, nil, err
285 }
Robin Thellendb9dd9bb2014-10-29 13:54:08 -0700286 switch kind := components[4]; kind {
287 case "logs":
288 logsDir := filepath.Join(appInstanceDir, "logs")
289 suffix := naming.Join(components[5:]...)
Adam Sadovskya4d4a692015-04-20 11:36:49 -0700290 appSpecificAuthorizer, err := newAppSpecificAuthorizer(auth, d.config, components[1:], d.permsStore)
Robert Kroeger8f914be2015-03-14 16:32:37 -0700291 if err != nil {
292 return nil, nil, err
293 }
Todd Wang1ea8f192015-04-03 17:31:51 -0700294 return logreaderlib.NewLogFileService(logsDir, suffix), appSpecificAuthorizer, nil
Robin Thellendb9dd9bb2014-10-29 13:54:08 -0700295 case "pprof", "stats":
gauthamtfd1e34e2015-03-05 15:30:52 -0800296 info, err := loadInstanceInfo(nil, appInstanceDir)
Robin Thellendb9dd9bb2014-10-29 13:54:08 -0700297 if err != nil {
298 return nil, nil, err
299 }
Bogdan Caprita2b050322015-04-17 09:04:03 -0700300 if !instanceStateIs(appInstanceDir, device.InstanceStateRunning) {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700301 return nil, nil, verror.New(errors.ErrInvalidSuffix, nil)
Robin Thellendb9dd9bb2014-10-29 13:54:08 -0700302 }
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700303 var desc []rpc.InterfaceDesc
Todd Wangf519f8f2015-01-21 10:07:41 -0800304 switch kind {
305 case "pprof":
306 desc = pprof.PProfServer(nil).Describe__()
307 case "stats":
308 desc = stats.StatsServer(nil).Describe__()
Robin Thellendb9dd9bb2014-10-29 13:54:08 -0700309 }
310 suffix := naming.Join("__debug", naming.Join(components[4:]...))
311 remote := naming.JoinAddressName(info.AppCycleMgrName, suffix)
Robert Kroeger16ee22b2015-03-12 14:57:09 -0700312
313 // Use hierarchical auth with debugacls under debug access.
Adam Sadovskya4d4a692015-04-20 11:36:49 -0700314 appSpecificAuthorizer, err := newAppSpecificAuthorizer(auth, d.config, components[1:], d.permsStore)
Robert Kroeger16ee22b2015-03-12 14:57:09 -0700315 if err != nil {
316 return nil, nil, err
317 }
318 return newProxyInvoker(remote, access.Debug, desc), appSpecificAuthorizer, nil
Robin Thellendb9dd9bb2014-10-29 13:54:08 -0700319 }
Robin Thellend4c5266e2014-10-27 13:19:29 -0700320 }
Bogdan Capritaa456f472014-12-10 10:18:03 -0800321 receiver := device.ApplicationServer(&appService{
Robert Kroeger450fdf12015-05-19 14:40:42 -0700322 config: d.config,
323 suffix: components[1:],
324 uat: d.uat,
325 permsStore: d.permsStore,
Robert Kroegercc9f55d2015-05-20 16:25:36 -0700326 runner: &appRunner{
327 reap: d.internal.reap,
Robert Kroeger450fdf12015-05-19 14:40:42 -0700328 callback: d.internal.callback,
329 securityAgent: d.internal.securityAgent,
330 mtAddress: d.mtAddress,
331 },
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700332 })
Adam Sadovskya4d4a692015-04-20 11:36:49 -0700333 appSpecificAuthorizer, err := newAppSpecificAuthorizer(auth, d.config, components[1:], d.permsStore)
Robert Kroegeracc778b2014-11-03 17:17:21 -0800334 if err != nil {
335 return nil, nil, err
336 }
Cosmos Nicolaou710daa22014-11-11 19:39:18 -0800337 return receiver, appSpecificAuthorizer, nil
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700338 case configSuffix:
339 if len(components) != 2 {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700340 return nil, nil, verror.New(errors.ErrInvalidSuffix, nil)
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700341 }
Todd Wangcd4b3cc2015-04-06 16:42:02 -0700342 receiver := s_device.ConfigServer(&configService{
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700343 callback: d.internal.callback,
344 suffix: components[1],
345 })
Bogdan Capritab9501d12014-10-10 15:02:03 -0700346 // The nil authorizer ensures that only principals blessed by
Bogdan Caprita2b219362014-12-09 17:03:33 -0800347 // the device manager can talk back to it. All apps started by
348 // the device manager should fall in that category.
Bogdan Capritab9501d12014-10-10 15:02:03 -0700349 //
350 // TODO(caprita,rjkroege): We should further refine this, by
351 // only allowing the app to update state referring to itself
352 // (and not other apps).
Cosmos Nicolaou710daa22014-11-11 19:39:18 -0800353 return receiver, nil, nil
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700354 default:
Bogdan Caprita040603b2015-06-23 18:19:30 -0700355 return nil, nil, verror.New(errors.ErrInvalidSuffix, nil)
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700356 }
Jiri Simsa24e87aa2014-06-09 09:27:34 -0700357}
Robert Kroegeracc778b2014-11-03 17:17:21 -0800358
Robin Thellend9299b782015-02-03 08:42:46 -0800359// testModeDispatcher is a wrapper around the real dispatcher. It returns the
360// exact same object as the real dispatcher, but the authorizer only allows
Bogdan Caprita2b050322015-04-17 09:04:03 -0700361// calls to "device".Delete().
Robin Thellend9299b782015-02-03 08:42:46 -0800362type testModeDispatcher struct {
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700363 realDispatcher rpc.Dispatcher
Robin Thellend9299b782015-02-03 08:42:46 -0800364}
365
366func (d *testModeDispatcher) Lookup(suffix string) (interface{}, security.Authorizer, error) {
367 obj, _, err := d.realDispatcher.Lookup(suffix)
368 return obj, d, err
369}
370
Todd Wang4264e4b2015-04-16 22:43:40 -0700371func (testModeDispatcher) Authorize(ctx *context.T, call security.Call) error {
Bogdan Caprita2b050322015-04-17 09:04:03 -0700372 if call.Suffix() == deviceSuffix && call.Method() == "Delete" {
Matt Rosencrantz9dce9b22015-03-02 10:48:37 -0800373 vlog.Infof("testModeDispatcher.Authorize: Allow %q.%s()", call.Suffix(), call.Method())
Robin Thellend9299b782015-02-03 08:42:46 -0800374 return nil
375 }
Matt Rosencrantz9dce9b22015-03-02 10:48:37 -0800376 vlog.Infof("testModeDispatcher.Authorize: Reject %q.%s()", call.Suffix(), call.Method())
Bogdan Caprita040603b2015-06-23 18:19:30 -0700377 return verror.New(errors.ErrInvalidSuffix, nil)
Robin Thellend9299b782015-02-03 08:42:46 -0800378}
379
Adam Sadovskya4d4a692015-04-20 11:36:49 -0700380func newAppSpecificAuthorizer(sec security.Authorizer, config *config.State, suffix []string, getter pathperms.PermsGetter) (security.Authorizer, error) {
Bogdan Caprita2b219362014-12-09 17:03:33 -0800381 // TODO(rjkroege): This does not support <appname>.Start() to start all
382 // instances. Correct this.
Robert Kroegeracc778b2014-11-03 17:17:21 -0800383
Adam Sadovskya4d4a692015-04-20 11:36:49 -0700384 // If we are attempting a method invocation against "apps/", we use the root
385 // Permissions.
Robert Kroegeracc778b2014-11-03 17:17:21 -0800386 if len(suffix) == 0 || len(suffix) == 1 {
387 return sec, nil
388 }
Adam Sadovskya4d4a692015-04-20 11:36:49 -0700389 // Otherwise, we require a per-installation and per-instance Permissions file.
Robert Kroegeracc778b2014-11-03 17:17:21 -0800390 if len(suffix) == 2 {
391 p, err := installationDirCore(suffix, config.Root)
392 if err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700393 return nil, verror.New(errors.ErrOperationFailed, nil, fmt.Sprintf("newAppSpecificAuthorizer failed: %v", err))
Robert Kroegeracc778b2014-11-03 17:17:21 -0800394 }
Adam Sadovskya4d4a692015-04-20 11:36:49 -0700395 return pathperms.NewHierarchicalAuthorizer(PermsDir(config), path.Join(p, "acls"), getter)
Asim Shankar68885192014-11-26 12:48:35 -0800396 }
Adam Sadovskya4d4a692015-04-20 11:36:49 -0700397 // Use the special debugacls for instance/logs, instance/pprof, instance/stats.
Robert Kroeger16ee22b2015-03-12 14:57:09 -0700398 if len(suffix) > 3 && (suffix[3] == "logs" || suffix[3] == "pprof" || suffix[3] == "stats") {
399 p, err := instanceDir(config.Root, suffix[0:3])
400 if err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700401 return nil, verror.New(errors.ErrOperationFailed, nil, fmt.Sprintf("newAppSpecificAuthorizer failed: %v", err))
Robert Kroeger16ee22b2015-03-12 14:57:09 -0700402 }
Adam Sadovskya4d4a692015-04-20 11:36:49 -0700403 return pathperms.NewHierarchicalAuthorizer(PermsDir(config), path.Join(p, "debugacls"), getter)
Robert Kroeger16ee22b2015-03-12 14:57:09 -0700404 }
405
Robert Kroeger7a8b2222015-03-06 07:58:57 -0800406 p, err := instanceDir(config.Root, suffix[0:3])
407 if err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700408 return nil, verror.New(errors.ErrOperationFailed, nil, fmt.Sprintf("newAppSpecificAuthorizer failed: %v", err))
Robert Kroegeracc778b2014-11-03 17:17:21 -0800409 }
Adam Sadovskya4d4a692015-04-20 11:36:49 -0700410 return pathperms.NewHierarchicalAuthorizer(PermsDir(config), path.Join(p, "acls"), getter)
Robert Kroegeracc778b2014-11-03 17:17:21 -0800411}