blob: da884c4103fe282d0a0700f9574030e6b3c05af2 [file] [log] [blame]
David Why Use Two When One Will Do Presottoba9593f2015-04-22 12:29:26 -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
5package mounttablelib
6
7import (
8 "encoding/json"
9 "io"
10 "os"
David Why Use Two When One Will Do Presottoe3e932c2015-05-15 14:59:46 -070011 "sort"
David Why Use Two When One Will Do Presottoba9593f2015-04-22 12:29:26 -070012 "strconv"
13 "strings"
14
15 "v.io/v23/context"
David Why Use Two When One Will Do Presotto67b70712015-06-02 13:13:58 -070016 "v.io/v23/conventions"
David Why Use Two When One Will Do Presottoba9593f2015-04-22 12:29:26 -070017 "v.io/v23/security"
18 "v.io/v23/security/access"
19 "v.io/v23/services/mounttable"
20 "v.io/v23/verror"
David Why Use Two When One Will Do Presottoba9593f2015-04-22 12:29:26 -070021)
22
David Why Use Two When One Will Do Presottoc74ac702015-05-07 15:33:52 -070023// Blessings can't include a comma so we use them in made up user ids. The following distinctions are
24// made so that we can account for them differently.
25const localUser = ",LOCAL," // a client that has our public key but no blessing from which we can extract a user name
26const blessedUser = ",BLESSED," // a client with blessings we trust but from which we can't extract a user name
27const unknownUser = ",UNKNOWN," // a client which presents no blessing we trust
28
David Why Use Two When One Will Do Presottoba9593f2015-04-22 12:29:26 -070029// VersionedPermissions associates a Version with a Permissions
30type VersionedPermissions struct {
31 V int32
32 P access.Permissions
33}
34
35func NewVersionedPermissions() *VersionedPermissions {
36 return &VersionedPermissions{P: make(access.Permissions)}
37}
38
39// Set sets the Permissions iff Version matches the current Version. If the set happens, the Version is advanced.
40// If b is nil, this creates a new VersionedPermissions.
41func (b *VersionedPermissions) Set(ctx *context.T, verstr string, perm access.Permissions) (*VersionedPermissions, error) {
42 if b == nil {
43 b = new(VersionedPermissions)
44 }
45 if len(verstr) > 0 {
46 gen, err := strconv.ParseInt(verstr, 10, 32)
47 if err != nil {
48 return b, verror.NewErrBadVersion(ctx)
49 }
50 if gen >= 0 && int32(gen) != b.V {
51 return b, verror.NewErrBadVersion(ctx)
52 }
53 }
54 b.P = perm
David Why Use Two When One Will Do Presottoc74ac702015-05-07 15:33:52 -070055 // Increment with possible wrap.
David Why Use Two When One Will Do Presottoba9593f2015-04-22 12:29:26 -070056 b.V++
David Why Use Two When One Will Do Presottoba9593f2015-04-22 12:29:26 -070057 if b.V < 0 {
58 b.V = 0
59 }
60 return b, nil
61}
62
63// Get returns the current Version and Permissions.
64func (b *VersionedPermissions) Get() (string, access.Permissions) {
65 if b == nil {
66 return "", nil
67 }
68 return strconv.FormatInt(int64(b.V), 10), b.P
69}
70
71// AccessListForTag returns the current access list for the given tag.
72func (b *VersionedPermissions) AccessListForTag(tag string) (access.AccessList, bool) {
73 al, exists := b.P[tag]
74 return al, exists
75}
76
77// Copy copies the receiver.
78func (b *VersionedPermissions) Copy() *VersionedPermissions {
79 nt := new(VersionedPermissions)
80 nt.P = b.P.Copy()
81 nt.V = b.V
82 return nt
83}
84
85// Add adds the blessing pattern to the tag in the reciever.
86func (b *VersionedPermissions) Add(pattern security.BlessingPattern, tag string) {
87 b.P.Add(pattern, tag)
88}
89
90// parsePermFile reads a file and parses the contained permissions.
Cosmos Nicolaou19a50f62015-06-20 09:15:40 -070091func (mt *mountTable) parsePermFile(ctx *context.T, path string) error {
92 ctx.VI(2).Infof("parsePermFile(%s)", path)
David Why Use Two When One Will Do Presottoba9593f2015-04-22 12:29:26 -070093 if path == "" {
94 return nil
95 }
96 // A map from node name to permissions.
97 var pm map[string]access.Permissions
98 f, err := os.Open(path)
99 if err != nil {
100 return err
101 }
102 defer f.Close()
103 decoder := json.NewDecoder(f)
104 for {
105 if err = decoder.Decode(&pm); err != nil {
106 if err == io.EOF {
107 break
108 }
109 return err
110 }
David Why Use Two When One Will Do Presotto30f7a112015-08-17 09:39:33 -0700111 cc := &callContext{ctx: ctx,
112 creatorSet: true,
113 create: true,
114 ignorePerms: true,
115 ignoreLimits: true,
116 }
David Why Use Two When One Will Do Presottoe3e932c2015-05-15 14:59:46 -0700117 // Sort the map shortest key first. That way configs for nodes higher up in the
118 // name tree happen first ensuring that lower nodes correctly inherit permissions.
119 var keys []string
120 for name := range pm {
121 keys = append(keys, name)
122 }
123 sort.Strings(keys)
124 for _, name := range keys {
125 perms := pm[name]
David Why Use Two When One Will Do Presottoba9593f2015-04-22 12:29:26 -0700126 var elems []string
127 isPattern := false
128
129 // The configuration file allows patterns and also will cause the superuser to
130 // be set to the root's administrator.
131 if len(name) == 0 {
132 // If the config file has is an Admin tag on the root AccessList, the
133 // list of Admin users is the equivalent of a super user for
134 // the whole table. Later SetPermissions do not update the set
135 // of super users.
136 if bp, exists := perms[string(mounttable.Admin)]; exists {
137 mt.superUsers = bp
138 }
139 } else {
140 // AccessList templates terminate with a %% element. These are very
141 // constrained matches, i.e., the trailing element of the name
142 // is copied into every %% in the AccessList.
143 elems = strings.Split(name, "/")
144 if elems[len(elems)-1] == templateVar {
145 isPattern = true
146 elems = elems[:len(elems)-1]
147 }
148 }
149
150 // Create name and add the Permissions map to it.
David Why Use Two When One Will Do Presotto30f7a112015-08-17 09:39:33 -0700151 cc.creator = mt.pickCreator(ctx, nil)
152 n, err := mt.findNode(cc, elems, nil, nil)
David Why Use Two When One Will Do Presottoe0a71c72015-08-10 10:31:54 -0700153 if err != nil {
154 ctx.Errorf("skipping node for %v; error: %v", elems, err)
155 }
156 if n == nil {
157 continue
158 }
159 if err == nil {
Cosmos Nicolaou19a50f62015-06-20 09:15:40 -0700160 ctx.VI(2).Infof("added perms %v to %s", perms, name)
David Why Use Two When One Will Do Presottoba9593f2015-04-22 12:29:26 -0700161 if isPattern {
162 n.permsTemplate = perms
163 } else {
164 n.vPerms, _ = n.vPerms.Set(nil, "", perms)
165 n.explicitPermissions = true
166 }
167 }
168 n.parent.Unlock()
169 n.Unlock()
170 }
171 }
172 return nil
173}
David Why Use Two When One Will Do Presottoc74ac702015-05-07 15:33:52 -0700174
David Why Use Two When One Will Do Presotto67b70712015-06-02 13:13:58 -0700175// pickCreator returns a string matching the blessing of the user performing the creation.
David Why Use Two When One Will Do Presottoc74ac702015-05-07 15:33:52 -0700176func (mt *mountTable) pickCreator(ctx *context.T, call security.Call) string {
David Why Use Two When One Will Do Presotto67b70712015-06-02 13:13:58 -0700177 ids := conventions.GetClientUserIds(ctx, call)
178 // Replace the slashes with something else or we'll confuse the stats package.
179 return strings.Replace(ids[0], "/", "\\", 0)
David Why Use Two When One Will Do Presottoc74ac702015-05-07 15:33:52 -0700180}