Merge "core: Rename vom2 to vom."
diff --git a/lib/modules/core/wspr.go b/lib/modules/core/wspr.go
index d6d8dd1..42db213 100644
--- a/lib/modules/core/wspr.go
+++ b/lib/modules/core/wspr.go
@@ -9,7 +9,7 @@
 	"v.io/core/veyron/lib/modules"
 	"v.io/wspr/veyron/services/wsprd/wspr"
 
-	"v.io/core/veyron2/rt"
+	"v.io/core/veyron2"
 )
 
 var (
@@ -32,13 +32,11 @@
 		return fmt.Errorf("failed to parse args: %s", err)
 	}
 
-	r, err := rt.New()
-	if err != nil {
-		return fmt.Errorf("rt.New failed: %s", err)
-	}
-	defer r.Cleanup()
+	ctx, shutdown := veyron2.Init()
+	defer shutdown()
+
 	l := initListenSpec(fl)
-	proxy := wspr.NewWSPR(r.NewContext(), *port, nil, &l, *identd, nil)
+	proxy := wspr.NewWSPR(ctx, *port, &l, *identd, nil)
 	defer proxy.Shutdown()
 
 	addr := proxy.Listen()
diff --git a/services/mgmt/binary/binaryd/main.go b/services/mgmt/binary/binaryd/main.go
index 7dc03fa..4a22834 100644
--- a/services/mgmt/binary/binaryd/main.go
+++ b/services/mgmt/binary/binaryd/main.go
@@ -13,7 +13,6 @@
 	"v.io/core/veyron/lib/netstate"
 	"v.io/core/veyron/lib/signals"
 	"v.io/core/veyron/profiles/roaming"
-	vflag "v.io/core/veyron/security/flag"
 	"v.io/core/veyron/services/mgmt/binary/impl"
 )
 
@@ -86,13 +85,18 @@
 		return
 	}
 	defer server.Stop()
-	auth := vflag.NewAuthorizerOrDie()
 	endpoints, err := server.Listen(roaming.ListenSpec)
 	if err != nil {
 		vlog.Errorf("Listen(%s) failed: %v", roaming.ListenSpec, err)
 		return
 	}
-	if err := server.ServeDispatcher(*name, impl.NewDispatcher(state, auth)); err != nil {
+
+	dis, err := impl.NewDispatcher(veyron2.GetPrincipal(ctx), state)
+	if err != nil {
+		vlog.Errorf("NewDispatcher() failed: %v\n", err)
+		return
+	}
+	if err := server.ServeDispatcher(*name, dis); err != nil {
 		vlog.Errorf("ServeDispatcher(%v) failed: %v", *name, err)
 		return
 	}
diff --git a/services/mgmt/binary/impl/acl_test.go b/services/mgmt/binary/impl/acl_test.go
new file mode 100644
index 0000000..6778da3
--- /dev/null
+++ b/services/mgmt/binary/impl/acl_test.go
@@ -0,0 +1,317 @@
+package impl_test
+
+import (
+	"fmt"
+	"io"
+	"os"
+	"reflect"
+	"syscall"
+	"testing"
+
+	"v.io/core/veyron2"
+	"v.io/core/veyron2/naming"
+	"v.io/core/veyron2/rt"
+	"v.io/core/veyron2/security"
+	"v.io/core/veyron2/services/mgmt/repository"
+	"v.io/core/veyron2/services/security/access"
+	"v.io/core/veyron2/vdl/vdlutil"
+	"v.io/core/veyron2/verror"
+	"v.io/core/veyron2/vlog"
+
+	"v.io/core/veyron/lib/modules"
+	"v.io/core/veyron/lib/signals"
+	"v.io/core/veyron/lib/testutil"
+	tsecurity "v.io/core/veyron/lib/testutil/security"
+	vsecurity "v.io/core/veyron/security"
+	"v.io/core/veyron/services/mgmt/binary/impl"
+	mgmttest "v.io/core/veyron/services/mgmt/lib/testutil"
+)
+
+const (
+	binaryCmd = "binaryd"
+)
+
+func init() {
+	// TODO(rjkroege): Remove when vom2 is ready.
+	vdlutil.Register(&naming.VDLMountedServer{})
+
+	modules.RegisterChild(binaryCmd, "", binaryd)
+	testutil.Init()
+
+	globalRT, err := rt.New()
+	if err != nil {
+		panic(err)
+	}
+	gctx = globalRT.NewContext()
+	globalCancel = globalRT.Cleanup
+	veyron2.GetNamespace(gctx).CacheCtl(naming.DisableCache(true))
+}
+
+// TestHelperProcess is the entrypoint for the modules commands in
+// a test subprocess.
+func TestHelperProcess(t *testing.T) {
+	modules.DispatchInTest()
+}
+
+func binaryd(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
+	args = args[1:]
+	if len(args) < 2 {
+		vlog.Fatalf("binaryd expected at least name and store arguments and optionally ACL flags per TaggedACLMapFromFlag")
+	}
+	publishName := args[0]
+	storedir := args[1]
+
+	defer fmt.Fprintf(stdout, "%v terminating\n", publishName)
+	defer vlog.VI(1).Infof("%v terminating", publishName)
+	defer globalCancel()
+	server, endpoint := mgmttest.NewServer(gctx)
+	defer server.Stop()
+
+	name := naming.JoinAddressName(endpoint, "")
+	vlog.VI(1).Infof("binaryd name: %v", name)
+
+	depth := 2
+	state, err := impl.NewState(storedir, "", depth)
+	if err != nil {
+		vlog.Fatalf("NewState(%v, %v, %v) failed: %v", storedir, "", depth, err)
+	}
+	dispatcher, err := impl.NewDispatcher(veyron2.GetPrincipal(gctx), state)
+	if err != nil {
+		vlog.Fatalf("Failed to create binaryd dispatcher: %v", err)
+	}
+	if err := server.ServeDispatcher(publishName, dispatcher); err != nil {
+		vlog.Fatalf("Serve(%v) failed: %v", publishName, err)
+	}
+
+	fmt.Fprintf(stdout, "ready:%d\n", os.Getpid())
+	<-signals.ShutdownOnSignals(gctx)
+
+	return nil
+}
+
+func TestBinaryRootACL(t *testing.T) {
+	selfPrincipal := tsecurity.NewPrincipal("self")
+	selfCtx, err := veyron2.SetPrincipal(gctx, selfPrincipal)
+	if err != nil {
+		t.Fatalf("SetPrincipal failed: %v", err)
+	}
+	sh, deferFn := mgmttest.CreateShellAndMountTable(t, selfCtx, veyron2.GetPrincipal(selfCtx))
+	defer deferFn()
+
+	// setup mock up directory to put state in
+	storedir, cleanup := mgmttest.SetupRootDir(t, "bindir")
+	defer cleanup()
+	prepDirectory(t, storedir)
+
+	otherPrincipal, err := vsecurity.NewPrincipal()
+	if err != nil {
+		t.Fatalf("NewPrincipal() failed: %v", err)
+	}
+	otherCtx, err := veyron2.SetPrincipal(selfCtx, otherPrincipal)
+	if err != nil {
+		t.Fatalf("SetPrincipal() failed: %v", err)
+	}
+
+	selfBlessing := selfPrincipal.BlessingStore().Default()
+	otherBlessing, err := selfPrincipal.Bless(otherPrincipal.PublicKey(), selfBlessing, "other", security.UnconstrainedUse())
+	if err != nil {
+		t.Fatalf("selfPrincipal.Bless() failed: %v", err)
+	}
+	if _, err := otherPrincipal.BlessingStore().Set(otherBlessing, "self/child"); err != nil {
+		t.Fatalf("otherPrincipal.BlessingStore() failed: %v", err)
+	}
+	if err := otherPrincipal.AddToRoots(otherBlessing); err != nil {
+		t.Fatalf("otherPrincipal.AddToRoots() failed: %v", err)
+	}
+
+	_, nms := mgmttest.RunShellCommand(t, sh, nil, binaryCmd, "bini", storedir)
+	pid := mgmttest.ReadPID(t, nms)
+	defer syscall.Kill(pid, syscall.SIGINT)
+
+	vlog.VI(2).Infof("Self uploads a shared and private binary.")
+	binary := repository.BinaryClient("bini/private")
+	if err := binary.Create(selfCtx, 1, repository.MediaInfo{Type: "application/octet-stream"}); err != nil {
+		t.Fatalf("Create() failed %v", err)
+	}
+	fakeDataPrivate := testData()
+	if streamErr, err := invokeUpload(t, selfCtx, binary, fakeDataPrivate, 0); streamErr != nil || err != nil {
+		t.Fatalf("invokeUpload() failed %v, %v", err, streamErr)
+	}
+
+	binary = repository.BinaryClient("bini/shared")
+	if err := binary.Create(selfCtx, 1, repository.MediaInfo{Type: "application/octet-stream"}); err != nil {
+		t.Fatalf("Create() failed %v", err)
+	}
+	fakeDataShared := testData()
+	if streamErr, err := invokeUpload(t, selfCtx, binary, fakeDataShared, 0); streamErr != nil || err != nil {
+		t.Fatalf("invokeUpload() failed %v, %v", err, streamErr)
+	}
+
+	vlog.VI(2).Infof("Verify that other can't access bini/private")
+	binary = repository.BinaryClient("bini/shared")
+	if _, _, err := binary.Stat(otherCtx); !verror.Is(err, verror.NoAccess) {
+		t.Fatalf("Stat() should have failed but didn't: %v", err)
+	}
+
+	vlog.VI(2).Infof("Validate the ACL file on bini/private.")
+	binary = repository.BinaryClient("bini/private")
+	acl, _, err := binary.GetACL(selfCtx)
+	if err != nil {
+		t.Fatalf("GetACL failed: %v", err)
+	}
+	expected := access.TaggedACLMap{"Admin": access.ACL{In: []security.BlessingPattern{"self"}, NotIn: []string{}}, "Read": access.ACL{In: []security.BlessingPattern{"self"}, NotIn: []string{}}, "Write": access.ACL{In: []security.BlessingPattern{"self"}, NotIn: []string{}}, "Debug": access.ACL{In: []security.BlessingPattern{"self"}, NotIn: []string{}}, "Resolve": access.ACL{In: []security.BlessingPattern{"self"}, NotIn: []string{}}}
+	if got, want := acl.Normalize(), expected.Normalize(); !reflect.DeepEqual(got, want) {
+		t.Errorf("got %#v, exected %#v ", got, want)
+	}
+
+	vlog.VI(2).Infof("Validate the ACL file on bini/shared.")
+	binary = repository.BinaryClient("bini/shared")
+	acl, etag, err := binary.GetACL(selfCtx)
+	if err != nil {
+		t.Fatalf("GetACL failed: %v", err)
+	}
+	if got, want := acl.Normalize(), expected.Normalize(); !reflect.DeepEqual(got, want) {
+		t.Errorf("got %#v, exected %#v ", got, want)
+	}
+
+	vlog.VI(2).Infof("Self modifies the ACL file on bini/shared.")
+	for _, tag := range access.AllTypicalTags() {
+		acl.Add("self/other", string(tag))
+	}
+	if err := binary.SetACL(selfCtx, acl, etag); err != nil {
+		t.Fatalf("SetACL failed: %v", err)
+	}
+
+	vlog.VI(2).Infof(" Verify that bini/shared's acls are updated.")
+	binary = repository.BinaryClient("bini/shared")
+	updated := access.TaggedACLMap{"Admin": access.ACL{In: []security.BlessingPattern{"self", "self/other"}, NotIn: []string{}}, "Read": access.ACL{In: []security.BlessingPattern{"self", "self/other"}, NotIn: []string{}}, "Write": access.ACL{In: []security.BlessingPattern{"self", "self/other"}, NotIn: []string{}}, "Debug": access.ACL{In: []security.BlessingPattern{"self", "self/other"}, NotIn: []string{}}, "Resolve": access.ACL{In: []security.BlessingPattern{"self", "self/other"}, NotIn: []string{}}}
+	acl, _, err = binary.GetACL(selfCtx)
+	if err != nil {
+		t.Fatalf("GetACL failed: %v", err)
+	}
+	if got, want := acl.Normalize(), updated.Normalize(); !reflect.DeepEqual(got, want) {
+		t.Errorf("got %#v, exected %#v ", got, want)
+	}
+
+	// Other still can't access bini/shared because there's no ACL file at the
+	// root level. Self has to set one explicitly to enable sharing. This way, self
+	// can't accidentally expose the server without setting a root ACL.
+	vlog.VI(2).Infof(" Verify that other still can't access bini/shared.")
+	binary = repository.BinaryClient("bini/shared")
+	if _, _, err := binary.Stat(otherCtx); !verror.Is(err, verror.NoAccess) {
+		t.Fatalf("Stat() should have failed but didn't: %v", err)
+	}
+
+	vlog.VI(2).Infof("Self sets a root ACL.")
+	binary = repository.BinaryClient("bini")
+	newRootACL := make(access.TaggedACLMap)
+	for _, tag := range access.AllTypicalTags() {
+		newRootACL.Add("self", string(tag))
+	}
+	if err := binary.SetACL(selfCtx, newRootACL, ""); err != nil {
+		t.Fatalf("SetACL failed: %v", err)
+	}
+
+	vlog.VI(2).Infof("Verify that other can access bini/shared now but not access bini/private.")
+	binary = repository.BinaryClient("bini/shared")
+	if _, _, err := binary.Stat(otherCtx); err != nil {
+		t.Fatalf("Stat() shouldn't have failed: %v", err)
+	}
+	binary = repository.BinaryClient("bini/private")
+	if _, _, err := binary.Stat(otherCtx); !verror.Is(err, verror.NoAccess) {
+		t.Fatalf("Stat() should have failed but didn't: %v", err)
+	}
+
+	vlog.VI(2).Infof("Other still can't create so Self gives Other right to Create.")
+	binary = repository.BinaryClient("bini")
+	acl, tag, err := binary.GetACL(selfCtx)
+	if err != nil {
+		t.Fatalf("GetACL() failed: %v", err)
+	}
+	acl.Add("self/other", string("Write"))
+	err = binary.SetACL(selfCtx, acl, tag)
+	if err != nil {
+		t.Fatalf("SetACL() failed: %v", err)
+	}
+
+	vlog.VI(2).Infof("Other creates bini/otherbinary")
+	binary = repository.BinaryClient("bini/otherbinary")
+	if err := binary.Create(otherCtx, 1, repository.MediaInfo{Type: "application/octet-stream"}); err != nil {
+		t.Fatalf("Create() failed %v", err)
+	}
+	fakeDataOther := testData()
+	if streamErr, err := invokeUpload(t, otherCtx, binary, fakeDataOther, 0); streamErr != nil || err != nil {
+		t.FailNow()
+	}
+
+	vlog.VI(2).Infof("Other can read acls for bini/otherbinary.")
+	updated = access.TaggedACLMap{
+		"Admin": access.ACL{
+			In:    []security.BlessingPattern{"self/other"},
+			NotIn: []string{}},
+		"Read": access.ACL{
+			In:    []security.BlessingPattern{"self/other"},
+			NotIn: []string{}},
+		"Write": access.ACL{
+			In:    []security.BlessingPattern{"self/other"},
+			NotIn: []string{}},
+		"Debug": access.ACL{In: []security.BlessingPattern{"self/other"},
+			NotIn: []string{}},
+		"Resolve": access.ACL{In: []security.BlessingPattern{"self/other"},
+			NotIn: []string{}}}
+	acl, _, err = binary.GetACL(otherCtx)
+	if err != nil {
+		t.Fatalf("GetACL failed: %v", err)
+	}
+	if got, want := acl.Normalize(), updated.Normalize(); !reflect.DeepEqual(want, got) {
+		t.Errorf("got %#v, exected %#v ", got, want)
+	}
+
+	vlog.VI(2).Infof("Other tries to exclude self by adding self to Read's notin")
+	acl, tag, err = binary.GetACL(otherCtx)
+	if err != nil {
+		t.Fatalf("GetACL() failed: %v", err)
+	}
+	acl.Blacklist("self", string("Read"))
+	err = binary.SetACL(otherCtx, acl, tag)
+	if err != nil {
+		t.Fatalf("SetACL() failed: %v", err)
+	}
+
+	vlog.VI(2).Infof("But self's rights are inherited from root so self can still access despite blacklist.")
+	binary = repository.BinaryClient("bini/otherbinary")
+	if _, _, err := binary.Stat(selfCtx); err != nil {
+		t.Fatalf("Stat() shouldn't have failed: %v", err)
+	}
+
+	vlog.VI(2).Infof("Self petulantly blacklists other back.")
+	binary = repository.BinaryClient("bini")
+	acl, tag, err = binary.GetACL(selfCtx)
+	if err != nil {
+		t.Fatalf("GetACL() failed: %v", err)
+	}
+	for _, tag := range access.AllTypicalTags() {
+		acl.Blacklist("self/other", string(tag))
+	}
+	err = binary.SetACL(selfCtx, acl, tag)
+	if err != nil {
+		t.Fatalf("SetACL() failed: %v", err)
+	}
+
+	vlog.VI(2).Infof("And now other can do nothing. Other should be penitent.")
+	binary = repository.BinaryClient("bini/nototherbinary")
+	if err := binary.Create(otherCtx, 1, repository.MediaInfo{Type: "application/octet-stream"}); !verror.Is(err, verror.NoAccess) {
+		t.Fatalf("Create() should have failed %v", err)
+	}
+
+	binary = repository.BinaryClient("bini/shared")
+	if _, _, err := binary.Stat(otherCtx); !verror.Is(err, verror.NoAccess) {
+		t.Fatalf("Stat() should have failed but didn't: %v", err)
+	}
+
+	vlog.VI(2).Infof("Pennance includes no access to the binary that other made.")
+	binary = repository.BinaryClient("bini/otherbinary")
+	if _, _, err := binary.Stat(otherCtx); !verror.Is(err, verror.NoAccess) {
+		t.Fatalf("Stat() should have failed but didn't: %v", err)
+	}
+}
diff --git a/services/mgmt/binary/impl/dispatcher.go b/services/mgmt/binary/impl/dispatcher.go
index 2105776..a8538d3 100644
--- a/services/mgmt/binary/impl/dispatcher.go
+++ b/services/mgmt/binary/impl/dispatcher.go
@@ -1,9 +1,16 @@
 package impl
 
 import (
-	"v.io/core/veyron2/ipc"
+	"fmt"
+	"os"
+	"path/filepath"
+
 	"v.io/core/veyron2/security"
 	"v.io/core/veyron2/services/mgmt/repository"
+	"v.io/core/veyron2/services/security/access"
+	"v.io/core/veyron2/vlog"
+
+	"v.io/core/veyron/services/mgmt/lib/acls"
 )
 
 const (
@@ -13,20 +20,114 @@
 
 // dispatcher holds the state of the binary repository dispatcher.
 type dispatcher struct {
-	auth  security.Authorizer
-	state *state
+	state     *state
+	locks     *acls.Locks
+	principal security.Principal
 }
 
 // NewDispatcher is the dispatcher factory.
-func NewDispatcher(state *state, authorizer security.Authorizer) ipc.Dispatcher {
+func NewDispatcher(principal security.Principal, state *state) (*dispatcher, error) {
 	return &dispatcher{
-		auth:  authorizer,
-		state: state,
-	}
+		state:     state,
+		locks:     acls.NewLocks(),
+		principal: principal,
+	}, nil
 }
 
 // DISPATCHER INTERFACE IMPLEMENTATION
 
+type hierarchicalAuthorizer struct {
+	root  security.Authorizer
+	child security.Authorizer
+}
+
+func aclPath(rootDir, suffix string) string {
+	var dir string
+	if suffix == "" {
+		// Directory is in namespace overlapped with Vanadium namespace
+		// so hide it.
+		dir = filepath.Join(rootDir, "__acls")
+	} else {
+		dir = filepath.Join(rootDir, suffix, "acls")
+	}
+	return dir
+}
+
+func newAuthorizer(principal security.Principal, rootDir, suffix string, locks *acls.Locks) (security.Authorizer, error) {
+	aclDir := aclPath(rootDir, "")
+	rootTam, _, err := locks.GetPathACL(principal, aclDir)
+	if err != nil && os.IsNotExist(err) {
+		vlog.VI(2).Infof("GetPathACL(%s) failed: %v, using default authorizer", aclDir, err)
+		return nil, nil
+	} else if err != nil {
+		return nil, err
+	}
+
+	rootAuth, err := access.TaggedACLAuthorizer(rootTam, access.TypicalTagType())
+	if err != nil {
+		vlog.Errorf("Successfully obtained an ACL from the filesystem but TaggedACLAuthorizer couldn't use it: %v", err)
+		return nil, err
+	}
+
+	if suffix == "" {
+		return rootAuth, nil
+	}
+
+	// This is not fatal: the suffix may not exist if we are invoking
+	// a Create() method so we only use the root ACL.
+	aclDir = aclPath(rootDir, suffix)
+	childTam, _, err := locks.GetPathACL(principal, aclDir)
+	if err != nil && os.IsNotExist(err) {
+		return rootAuth, nil
+	} else if err != nil {
+		return nil, err
+	}
+	// Root's blacklist also applies to the child.
+	meldBlacklists(rootTam, childTam)
+
+	childAuth, err := access.TaggedACLAuthorizer(childTam, access.TypicalTagType())
+	if err != nil {
+		vlog.Errorf("Successfully obtained an ACL from the filesystem but TaggedACLAuthorizer couldn't use it: %v", err)
+		return nil, err
+	}
+
+	return &hierarchicalAuthorizer{
+		root:  rootAuth,
+		child: childAuth,
+	}, nil
+}
+
+func meldBlacklists(root, child access.TaggedACLMap) {
+	for n, r := range root {
+		for _, b := range r.NotIn {
+			child.Blacklist(b, n)
+		}
+	}
+}
+
+// Authorize implements a chain of logic that works like this: If the
+// root blacklists or the child blacklists, (as implemented by
+// meldBlacklists) then the remote principal is forbidden to connect.
+// This way, the administrator can blacklist a principal even if the
+// child principal has admin permissions on the suffix. Otherwise, Authorize first
+// checks the child authorizer and then fallbacks to the root authorizer.
+// TODO(rjkroege): Introduce a different label for Create().
+func (ha *hierarchicalAuthorizer) Authorize(ctx security.Context) error {
+	childErr := ha.child.Authorize(ctx)
+	if childErr == nil {
+		return nil
+	}
+	rootErr := ha.root.Authorize(ctx)
+	if rootErr == nil {
+		return nil
+	}
+	return fmt.Errorf("Both root acls (%v) and child acls (%v) deny access.", rootErr, childErr)
+}
+
 func (d *dispatcher) Lookup(suffix string) (interface{}, security.Authorizer, error) {
-	return repository.BinaryServer(newBinaryService(d.state, suffix)), d.auth, nil
+	auth, err := newAuthorizer(d.principal, d.state.rootDir, suffix, d.locks)
+	if err != nil {
+		return nil, nil, err
+	}
+	return repository.BinaryServer(newBinaryService(d.state, suffix, d.locks)), auth, nil
 }
diff --git a/services/mgmt/binary/impl/impl_test.go b/services/mgmt/binary/impl/impl_test.go
index 09fb3a4..97ac906 100644
--- a/services/mgmt/binary/impl/impl_test.go
+++ b/services/mgmt/binary/impl/impl_test.go
@@ -10,9 +10,9 @@
 	"reflect"
 	"testing"
 
+	"v.io/core/veyron2"
 	"v.io/core/veyron2/context"
 	"v.io/core/veyron2/naming"
-	"v.io/core/veyron2/rt"
 	"v.io/core/veyron2/services/mgmt/repository"
 	verror "v.io/core/veyron2/verror2"
 	"v.io/core/veyron2/vlog"
@@ -28,16 +28,7 @@
 )
 
 var gctx *context.T
-
-func init() {
-	testutil.Init()
-
-	runtime, err := rt.New()
-	if err != nil {
-		panic(err)
-	}
-	gctx = runtime.NewContext()
-}
+var globalCancel context.CancelFunc
 
 // startServer starts the binary repository server.
 func startServer(t *testing.T, depth int) (repository.BinaryClientMethods, string, string, func()) {
@@ -61,7 +52,10 @@
 			vlog.Fatalf("Serve() failed: %v", err)
 		}
 	}()
-	dispatcher := impl.NewDispatcher(state, nil)
+	dispatcher, err := impl.NewDispatcher(veyron2.GetPrincipal(gctx), state)
+	if err != nil {
+		t.Fatalf("NewDispatcher failed: %v", err)
+	}
 	dontPublishName := ""
 	if err := server.ServeDispatcher(dontPublishName, dispatcher); err != nil {
 		t.Fatalf("Serve(%q) failed: %v", dontPublishName, err)
diff --git a/services/mgmt/binary/impl/service.go b/services/mgmt/binary/impl/service.go
index 0ce7bbe..12b1e54 100644
--- a/services/mgmt/binary/impl/service.go
+++ b/services/mgmt/binary/impl/service.go
@@ -1,14 +1,17 @@
-// The implementation of the binary repository interface stores
-// objects identified by object name suffixes using the local file
-// system. Given an object name suffix, the implementation computes an
-// MD5 hash of the suffix and generates the following path in the
-// local filesystem: /<root_dir>/<dir_1>/.../<dir_n>/<hash>. The root
-// directory and the directory depth are parameters of the
-// implementation. The contents of the directory include the checksum
-// and data for each of the individual parts of the binary, and the
-// name of the object:
+// The implementation of the binary repository interface stores objects
+// identified by object name suffixes using the local file system. Given
+// an object name suffix, the implementation computes an MD5 hash of the
+// suffix and generates the following path in the local filesystem:
+// /<root_dir>/<dir_1>/.../<dir_n>/<hash>. The root directory and the
+// directory depth are parameters of the implementation. <root_dir> also
+// contains __acls/data and __acls/sig files storing the ACLs for the
+// root level. The contents of the directory include the checksum and
+// data for each of the individual parts of the binary, the name of the
+// object and a directory containing the acls for this particular object:
 //
 // name
+// acls/data
+// acls/sig
 // <part_1>/checksum
 // <part_1>/data
 // ...
@@ -31,9 +34,12 @@
 	"strings"
 	"syscall"
 
+	"v.io/core/veyron/services/mgmt/lib/acls"
 	"v.io/core/veyron2/ipc"
+	"v.io/core/veyron2/security"
 	"v.io/core/veyron2/services/mgmt/binary"
 	"v.io/core/veyron2/services/mgmt/repository"
+	"v.io/core/veyron2/services/security/access"
 	verror "v.io/core/veyron2/verror2"
 	"v.io/core/veyron2/vlog"
 )
@@ -48,6 +54,7 @@
 	state *state
 	// suffix is the name of the binary object.
 	suffix string
+	locks  *acls.Locks
 }
 
 const pkgPath = "v.io/core/veyron/services/mgmt/binary/impl"
@@ -67,16 +74,31 @@
 }
 
 // newBinaryService returns a new Binary service implementation.
-func newBinaryService(state *state, suffix string) *binaryService {
+func newBinaryService(state *state, suffix string, locks *acls.Locks) *binaryService {
 	return &binaryService{
 		path:   state.dir(suffix),
 		state:  state,
 		suffix: suffix,
+		locks:  locks,
 	}
 }
 
 const BufferLength = 4096
 
+// insertACLs configures the starting ACL set for a newly "Create"-d binary based
+// on the caller's blessings.
+func insertACLs(dir string, principal security.Principal, locks *acls.Locks, blessings []string) error {
+	tam := make(access.TaggedACLMap)
+
+	// Add the invoker's blessings.
+	for _, b := range blessings {
+		for _, tag := range access.AllTypicalTags() {
+			tam.Add(security.BlessingPattern(b), string(tag))
+		}
+	}
+	return locks.SetPathACL(principal, dir, tam, "")
+}
+
 func (i *binaryService) Create(context ipc.ServerContext, nparts int32, mediaInfo repository.MediaInfo) error {
 	vlog.Infof("%v.Create(%v, %v)", i.suffix, nparts, mediaInfo)
 	if nparts < 1 {
@@ -98,6 +120,14 @@
 		vlog.Errorf("WriteFile(%q) failed: %v", nameFile)
 		return verror.Make(ErrOperationFailed, context.Context())
 	}
+
+	lp := context.LocalPrincipal()
+	rb := context.RemoteBlessings().ForContext(context)
+	if err := insertACLs(aclPath(i.state.rootDir, i.suffix), lp, i.locks, rb); err != nil {
+		vlog.Errorf("insertACLs(%v, %v) failed: %v", lp, rb, err)
+		return verror.Make(ErrOperationFailed, context.Context())
+	}
+
 	infoFile := filepath.Join(tmpDir, "mediainfo")
 	jInfo, err := json.Marshal(mediaInfo)
 	if err != nil {
@@ -343,3 +373,11 @@
 	}()
 	return ch, nil
 }
+
+func (i *binaryService) GetACL(ctx ipc.ServerContext) (acl access.TaggedACLMap, etag string, err error) {
+	return i.locks.GetPathACL(ctx.LocalPrincipal(), aclPath(i.state.rootDir, i.suffix))
+}
+
+func (i *binaryService) SetACL(ctx ipc.ServerContext, acl access.TaggedACLMap, etag string) error {
+	return i.locks.SetPathACL(ctx.LocalPrincipal(), aclPath(i.state.rootDir, i.suffix), acl, etag)
+}
diff --git a/services/mgmt/device/impl/impl_test.go b/services/mgmt/device/impl/impl_test.go
index 99b86c4..54760db 100644
--- a/services/mgmt/device/impl/impl_test.go
+++ b/services/mgmt/device/impl/impl_test.go
@@ -749,7 +749,11 @@
 	}
 	server, _ := mgmttest.NewServer(globalCtx)
 	name := "realbin"
-	if err := server.ServeDispatcher(name, binaryimpl.NewDispatcher(state, nil)); err != nil {
+	d, err := binaryimpl.NewDispatcher(veyron2.GetPrincipal(globalCtx), state)
+	if err != nil {
+		t.Fatalf("server.NewDispatcher failed: %v", err)
+	}
+	if err := server.ServeDispatcher(name, d); err != nil {
 		t.Fatalf("server.ServeDispatcher failed: %v", err)
 	}
 
diff --git a/services/mgmt/device/impl/mock_repo_test.go b/services/mgmt/device/impl/mock_repo_test.go
index 4c2dd10..eca07b1 100644
--- a/services/mgmt/device/impl/mock_repo_test.go
+++ b/services/mgmt/device/impl/mock_repo_test.go
@@ -165,3 +165,11 @@
 	vlog.VI(1).Infof("Upload()")
 	return nil
 }
+
+func (i *brInvoker) GetACL(ctx ipc.ServerContext) (acl access.TaggedACLMap, etag string, err error) {
+	return nil, "", nil
+}
+
+func (i *brInvoker) SetACL(ctx ipc.ServerContext, acl access.TaggedACLMap, etag string) error {
+	return nil
+}
diff --git a/services/mgmt/lib/acls/aclaccess.go b/services/mgmt/lib/acls/aclaccess.go
index 07e63a6..c81bfa4 100644
--- a/services/mgmt/lib/acls/aclaccess.go
+++ b/services/mgmt/lib/acls/aclaccess.go
@@ -7,7 +7,7 @@
 import (
 	"io/ioutil"
 	"os"
-	"path"
+	"path/filepath"
 	"sync"
 
 	"v.io/core/veyron2/security"
@@ -41,8 +41,8 @@
 
 // GetPathACL returns the TaggedACLMap from the data file in dir.
 func (locks Locks) GetPathACL(principal security.Principal, dir string) (access.TaggedACLMap, string, error) {
-	aclpath := path.Join(dir, aclName)
-	sigpath := path.Join(dir, sigName)
+	aclpath := filepath.Join(dir, aclName)
+	sigpath := filepath.Join(dir, sigName)
 	defer locks.lockPath(dir)()
 	return getCore(principal, aclpath, sigpath)
 }
@@ -100,8 +100,8 @@
 // directory with enforcement of etag synchronization mechanism and
 // locking.
 func (locks Locks) SetPathACL(principal security.Principal, dir string, acl access.TaggedACLMap, etag string) error {
-	aclpath := path.Join(dir, aclName)
-	sigpath := path.Join(dir, sigName)
+	aclpath := filepath.Join(dir, aclName)
+	sigpath := filepath.Join(dir, sigName)
 	defer locks.lockPath(dir)()
 	_, oetag, err := getCore(principal, aclpath, sigpath)
 	if err != nil && !os.IsNotExist(err) {
diff --git a/services/mgmt/lib/binary/impl_test.go b/services/mgmt/lib/binary/impl_test.go
index 1b77501..4a4deb4 100644
--- a/services/mgmt/lib/binary/impl_test.go
+++ b/services/mgmt/lib/binary/impl_test.go
@@ -56,7 +56,11 @@
 	if err != nil {
 		t.Fatalf("NewState(%v, %v) failed: %v", rootDir, depth, err)
 	}
-	dispatcher := impl.NewDispatcher(state, nil)
+
+	dispatcher, err := impl.NewDispatcher(veyron2.GetPrincipal(gctx), state)
+	if err != nil {
+		t.Fatalf("NewDispatcher() failed: %v\n", err)
+	}
 	endpoints, err := server.Listen(profiles.LocalListenSpec)
 	if err != nil {
 		t.Fatalf("Listen(%s) failed: %v", profiles.LocalListenSpec, err)
diff --git a/tools/binary/impl_test.go b/tools/binary/impl_test.go
index d8708f7..8d19bbd 100644
--- a/tools/binary/impl_test.go
+++ b/tools/binary/impl_test.go
@@ -19,6 +19,7 @@
 	"v.io/core/veyron2/security"
 	"v.io/core/veyron2/services/mgmt/binary"
 	"v.io/core/veyron2/services/mgmt/repository"
+	"v.io/core/veyron2/services/security/access"
 	"v.io/core/veyron2/vlog"
 
 	"v.io/core/veyron/profiles"
@@ -74,6 +75,14 @@
 	return nil
 }
 
+func (s *server) GetACL(ipc.ServerContext) (acl access.TaggedACLMap, etag string, err error) {
+	return nil, "", nil
+}
+
+func (s *server) SetACL(ctx ipc.ServerContext, acl access.TaggedACLMap, etag string) error {
+	return nil
+}
+
 type dispatcher struct {
 }