From 6bb96074da00131baf1b70b1b9fd91cea7b7bf83 Mon Sep 17 00:00:00 2001 From: Hitoshi Mitake Date: Tue, 7 Jun 2016 11:45:29 -0700 Subject: [PATCH 1/2] auth, etcdserver: permission of range requests Currently the auth mechanism doesn't support permissions of range request. It just checks exact matching of key names even for range queries. This commit adds a mechanism for setting permission to range queries. Range queries are allowed if a range of the query is [begin1, end1) and the user has a permission of reading [begin2, range2) and [begin1, end2) is a subset of [begin2, range2). Range delete requests will follow the same rule. --- auth/authpb/auth.pb.go | 93 +++++++++++----- auth/authpb/auth.proto | 7 +- auth/range_perm_cache.go | 195 ++++++++++++++++++++++++++++++++++ auth/range_perm_cache_test.go | 96 +++++++++++++++++ auth/store.go | 62 +++++++---- etcdserver/apply.go | 2 +- 6 files changed, 407 insertions(+), 48 deletions(-) create mode 100644 auth/range_perm_cache.go create mode 100644 auth/range_perm_cache_test.go diff --git a/auth/authpb/auth.pb.go b/auth/authpb/auth.pb.go index 00a63e464..9f8430808 100644 --- a/auth/authpb/auth.pb.go +++ b/auth/authpb/auth.pb.go @@ -72,8 +72,9 @@ func (*User) Descriptor() ([]byte, []int) { return fileDescriptorAuth, []int{0} // Permission is a single entity type Permission struct { - Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` - PermType Permission_Type `protobuf:"varint,2,opt,name=permType,proto3,enum=authpb.Permission_Type" json:"permType,omitempty"` + PermType Permission_Type `protobuf:"varint,1,opt,name=permType,proto3,enum=authpb.Permission_Type" json:"permType,omitempty"` + Key []byte `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` + RangeEnd []byte `protobuf:"bytes,3,opt,name=range_end,json=rangeEnd,proto3" json:"range_end,omitempty"` } func (m *Permission) Reset() { *m = Permission{} } @@ -158,16 +159,22 @@ func (m *Permission) MarshalTo(data []byte) (int, error) { _ = i var l int _ = l + if m.PermType != 0 { + data[i] = 0x8 + i++ + i = encodeVarintAuth(data, i, uint64(m.PermType)) + } if len(m.Key) > 0 { - data[i] = 0xa + data[i] = 0x12 i++ i = encodeVarintAuth(data, i, uint64(len(m.Key))) i += copy(data[i:], m.Key) } - if m.PermType != 0 { - data[i] = 0x10 + if len(m.RangeEnd) > 0 { + data[i] = 0x1a i++ - i = encodeVarintAuth(data, i, uint64(m.PermType)) + i = encodeVarintAuth(data, i, uint64(len(m.RangeEnd))) + i += copy(data[i:], m.RangeEnd) } return i, nil } @@ -258,12 +265,16 @@ func (m *User) Size() (n int) { func (m *Permission) Size() (n int) { var l int _ = l + if m.PermType != 0 { + n += 1 + sovAuth(uint64(m.PermType)) + } l = len(m.Key) if l > 0 { n += 1 + l + sovAuth(uint64(l)) } - if m.PermType != 0 { - n += 1 + sovAuth(uint64(m.PermType)) + l = len(m.RangeEnd) + if l > 0 { + n += 1 + l + sovAuth(uint64(l)) } return n } @@ -468,6 +479,25 @@ func (m *Permission) Unmarshal(data []byte) error { } switch fieldNum { case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PermType", wireType) + } + m.PermType = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuth + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + m.PermType |= (Permission_Type(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + case 2: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Key", wireType) } @@ -498,11 +528,11 @@ func (m *Permission) Unmarshal(data []byte) error { m.Key = []byte{} } iNdEx = postIndex - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field PermType", wireType) + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RangeEnd", wireType) } - m.PermType = 0 + var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowAuth @@ -512,11 +542,23 @@ func (m *Permission) Unmarshal(data []byte) error { } b := data[iNdEx] iNdEx++ - m.PermType |= (Permission_Type(b) & 0x7F) << shift + byteLen |= (int(b) & 0x7F) << shift if b < 0x80 { break } } + if byteLen < 0 { + return ErrInvalidLengthAuth + } + postIndex := iNdEx + byteLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RangeEnd = append(m.RangeEnd[:0], data[iNdEx:postIndex]...) + if m.RangeEnd == nil { + m.RangeEnd = []byte{} + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipAuth(data[iNdEx:]) @@ -756,22 +798,23 @@ var ( ) var fileDescriptorAuth = []byte{ - // 265 bytes of a gzipped FileDescriptorProto + // 276 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0xe2, 0x4a, 0x2c, 0x2d, 0xc9, 0xd0, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x03, 0xb1, 0x0b, 0x92, 0xa4, 0x44, 0xd2, 0xf3, 0xd3, 0xf3, 0xc1, 0x42, 0xfa, 0x20, 0x16, 0x44, 0x56, 0xc9, 0x87, 0x8b, 0x25, 0xb4, 0x38, 0xb5, 0x48, 0x48, 0x88, 0x8b, 0x25, 0x2f, 0x31, 0x37, 0x55, 0x82, 0x51, 0x81, 0x51, 0x83, 0x27, 0x08, 0xcc, 0x16, 0x92, 0xe2, 0xe2, 0x28, 0x48, 0x2c, 0x2e, 0x2e, 0xcf, 0x2f, 0x4a, 0x91, 0x60, 0x02, 0x8b, 0xc3, 0xf9, 0x42, 0x22, 0x5c, 0xac, 0x45, 0xf9, 0x39, 0xa9, 0xc5, 0x12, 0xcc, 0x0a, 0xcc, - 0x1a, 0x9c, 0x41, 0x10, 0x8e, 0x52, 0x3d, 0x17, 0x57, 0x40, 0x6a, 0x51, 0x6e, 0x66, 0x71, 0x71, - 0x66, 0x7e, 0x9e, 0x90, 0x00, 0x17, 0x73, 0x76, 0x6a, 0x25, 0xd4, 0x48, 0x10, 0x53, 0xc8, 0x98, - 0x8b, 0xa3, 0x20, 0xb5, 0x28, 0x37, 0xa4, 0xb2, 0x20, 0x15, 0x6c, 0x22, 0x9f, 0x91, 0xb8, 0x1e, - 0xc4, 0x79, 0x7a, 0x08, 0x7d, 0x7a, 0x20, 0xe9, 0x20, 0xb8, 0x42, 0x25, 0x2d, 0x2e, 0x16, 0x10, - 0x2d, 0xc4, 0xc1, 0xc5, 0x12, 0xe4, 0xea, 0xe8, 0x22, 0xc0, 0x20, 0xc4, 0xc9, 0xc5, 0x1a, 0x1e, - 0xe4, 0x19, 0xe2, 0x2a, 0xc0, 0x28, 0xc4, 0xcb, 0xc5, 0x09, 0x12, 0x84, 0x70, 0x99, 0x94, 0x42, - 0xb8, 0x58, 0x82, 0xf2, 0x73, 0x52, 0xb1, 0x7a, 0xc7, 0x82, 0x8b, 0x37, 0x3b, 0xb5, 0x12, 0x61, - 0x8f, 0x04, 0x93, 0x02, 0xb3, 0x06, 0xb7, 0x91, 0x10, 0xa6, 0x0b, 0x82, 0x50, 0x15, 0x3a, 0x89, - 0x9c, 0x78, 0x28, 0xc7, 0x70, 0xe1, 0xa1, 0x1c, 0xc3, 0x89, 0x47, 0x72, 0x8c, 0x17, 0x1e, 0xc9, - 0x31, 0x3e, 0x78, 0x24, 0xc7, 0x98, 0xc4, 0x06, 0x0e, 0x41, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, - 0xff, 0x92, 0x06, 0xa1, 0xed, 0x6d, 0x01, 0x00, 0x00, + 0x1a, 0x9c, 0x41, 0x10, 0x8e, 0xd2, 0x1c, 0x46, 0x2e, 0xae, 0x80, 0xd4, 0xa2, 0xdc, 0xcc, 0xe2, + 0xe2, 0xcc, 0xfc, 0x3c, 0x21, 0x63, 0xa0, 0x01, 0x40, 0x5e, 0x48, 0x65, 0x01, 0xc4, 0x60, 0x3e, + 0x23, 0x71, 0x3d, 0x88, 0x6b, 0xf4, 0x10, 0xaa, 0xf4, 0x40, 0xd2, 0x41, 0x70, 0x85, 0x42, 0x02, + 0x5c, 0xcc, 0xd9, 0xa9, 0x95, 0x50, 0x0b, 0x41, 0x4c, 0x21, 0x69, 0x2e, 0xce, 0xa2, 0xc4, 0xbc, + 0xf4, 0xd4, 0xf8, 0xd4, 0xbc, 0x14, 0xa0, 0x7d, 0x60, 0x87, 0x80, 0x05, 0x5c, 0xf3, 0x52, 0x94, + 0xb4, 0xb8, 0x58, 0xc0, 0xda, 0x38, 0xb8, 0x58, 0x82, 0x5c, 0x1d, 0x5d, 0x04, 0x18, 0x84, 0x38, + 0xb9, 0x58, 0xc3, 0x83, 0x3c, 0x43, 0x5c, 0x05, 0x18, 0x85, 0x78, 0xb9, 0x38, 0x41, 0x82, 0x10, + 0x2e, 0x93, 0x52, 0x08, 0x50, 0x0d, 0xd0, 0x9d, 0x58, 0x3d, 0x6b, 0xc1, 0xc5, 0x0b, 0xb4, 0x0b, + 0xe1, 0x2c, 0xa0, 0x03, 0x98, 0x35, 0xb8, 0x8d, 0x84, 0x30, 0x1d, 0x1c, 0x84, 0xaa, 0xd0, 0x49, + 0xe4, 0xc4, 0x43, 0x39, 0x86, 0x0b, 0x40, 0x7c, 0xe2, 0x91, 0x1c, 0xe3, 0x05, 0x20, 0x7e, 0x00, + 0xc4, 0x49, 0x6c, 0xe0, 0xf0, 0x35, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0x9e, 0x31, 0x53, 0xfd, + 0x8b, 0x01, 0x00, 0x00, } diff --git a/auth/authpb/auth.proto b/auth/authpb/auth.proto index 9308a179a..001d33435 100644 --- a/auth/authpb/auth.proto +++ b/auth/authpb/auth.proto @@ -18,14 +18,15 @@ message User { // Permission is a single entity message Permission { - bytes key = 1; - enum Type { READ = 0; WRITE = 1; READWRITE = 2; } - Type permType = 2; + Type permType = 1; + + bytes key = 2; + bytes range_end = 3; } // Role is a single entry in the bucket authRoles diff --git a/auth/range_perm_cache.go b/auth/range_perm_cache.go new file mode 100644 index 000000000..8ad39aa55 --- /dev/null +++ b/auth/range_perm_cache.go @@ -0,0 +1,195 @@ +// Copyright 2016 The etcd Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package auth + +import ( + "sort" + "strings" + + "github.com/coreos/etcd/auth/authpb" + "github.com/coreos/etcd/mvcc/backend" +) + +func isSubset(a, b *rangePerm) bool { + // return true if a is a subset of b + return 0 <= strings.Compare(a.begin, b.begin) && strings.Compare(a.end, b.end) <= 0 +} + +func reduceSubsets(perms []*rangePerm) []*rangePerm { + // TODO(mitake): currently it is O(n^2), we need a better algorithm + ret := make([]*rangePerm, 0) + + for i := range perms { + subset := false + + for j := range perms { + if i != j && isSubset(perms[i], perms[j]) { + subset = true + break + } + } + + if subset { + continue + } + + ret = append(ret, perms[i]) + } + + return ret +} + +func unifyPerms(perms []*rangePerm) []*rangePerm { + ret := make([]*rangePerm, 0) + perms = reduceSubsets(perms) + sort.Sort(RangePermSliceByBegin(perms)) + + i := 0 + for i < len(perms) { + begin := i + for i+1 < len(perms) && perms[i].end >= perms[i+1].begin { + i++ + } + + if i == begin { + ret = append(ret, &rangePerm{begin: perms[i].begin, end: perms[i].end}) + } else { + ret = append(ret, &rangePerm{begin: perms[begin].begin, end: perms[i].end}) + } + + i++ + } + + return ret +} + +func (as *authStore) makeUnifiedPerms(tx backend.BatchTx, userName string) *unifiedRangePermissions { + user := getUser(tx, userName) + if user == nil { + plog.Errorf("invalid user name %s", userName) + return nil + } + + var readPerms, writePerms []*rangePerm + + for _, roleName := range user.Roles { + _, vs := tx.UnsafeRange(authRolesBucketName, []byte(roleName), nil, 0) + if len(vs) != 1 { + plog.Errorf("invalid role name %s", roleName) + return nil + } + + role := &authpb.Role{} + err := role.Unmarshal(vs[0]) + if err != nil { + plog.Errorf("failed to unmarshal a role %s: %s", roleName, err) + return nil + } + + for _, perm := range role.KeyPermission { + if len(perm.RangeEnd) == 0 { + continue + } + + if perm.PermType == authpb.READWRITE || perm.PermType == authpb.READ { + readPerms = append(readPerms, &rangePerm{begin: string(perm.Key), end: string(perm.RangeEnd)}) + } + + if perm.PermType == authpb.READWRITE || perm.PermType == authpb.WRITE { + writePerms = append(writePerms, &rangePerm{begin: string(perm.Key), end: string(perm.RangeEnd)}) + } + } + } + + return &unifiedRangePermissions{readPerms: unifyPerms(readPerms), writePerms: unifyPerms(writePerms)} +} + +func checkCachedPerm(cachedPerms *unifiedRangePermissions, userName string, key, rangeEnd string, write, read bool) bool { + var perms []*rangePerm + + if write { + perms = cachedPerms.writePerms + } else { + perms = cachedPerms.readPerms + } + + for _, perm := range perms { + if strings.Compare(rangeEnd, "") != 0 { + if strings.Compare(perm.begin, key) <= 0 && strings.Compare(rangeEnd, perm.end) <= 0 { + return true + } + } else { + if strings.Compare(perm.begin, key) <= 0 && strings.Compare(key, perm.end) <= 0 { + return true + } + } + } + + return false +} + +func (as *authStore) isRangeOpPermitted(tx backend.BatchTx, userName string, key, rangeEnd string, write, read bool) bool { + // assumption: tx is Lock()ed + _, ok := as.rangePermCache[userName] + if ok { + return checkCachedPerm(as.rangePermCache[userName], userName, key, rangeEnd, write, read) + } + + perms := as.makeUnifiedPerms(tx, userName) + if perms == nil { + plog.Errorf("failed to create a unified permission of user %s", userName) + return false + } + as.rangePermCache[userName] = perms + + return checkCachedPerm(as.rangePermCache[userName], userName, key, rangeEnd, write, read) + +} + +func (as *authStore) clearCachedPerm() { + as.rangePermCache = make(map[string]*unifiedRangePermissions) +} + +func (as *authStore) invalidateCachedPerm(userName string) { + delete(as.rangePermCache, userName) +} + +type unifiedRangePermissions struct { + // readPerms[i] and readPerms[j] (i != j) don't overlap + readPerms []*rangePerm + // writePerms[i] and writePerms[j] (i != j) don't overlap, too + writePerms []*rangePerm +} + +type rangePerm struct { + begin, end string +} + +type RangePermSliceByBegin []*rangePerm + +func (slice RangePermSliceByBegin) Len() int { + return len(slice) +} + +func (slice RangePermSliceByBegin) Less(i, j int) bool { + if slice[i].begin == slice[j].begin { + return slice[i].end < slice[j].end + } + return slice[i].begin < slice[j].begin +} + +func (slice RangePermSliceByBegin) Swap(i, j int) { + slice[i], slice[j] = slice[j], slice[i] +} diff --git a/auth/range_perm_cache_test.go b/auth/range_perm_cache_test.go new file mode 100644 index 000000000..d32ea50fb --- /dev/null +++ b/auth/range_perm_cache_test.go @@ -0,0 +1,96 @@ +// Copyright 2016 The etcd Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package auth + +import ( + "testing" +) + +func isPermsEqual(a, b []*rangePerm) bool { + if len(a) != len(b) { + return false + } + + for i := range a { + if len(b) <= i { + return false + } + + if a[i].begin != b[i].begin || a[i].end != b[i].end { + return false + } + } + + return true +} + +func TestUnifyParams(t *testing.T) { + tests := []struct { + params []*rangePerm + want []*rangePerm + }{ + { + []*rangePerm{{"a", "b"}}, + []*rangePerm{{"a", "b"}}, + }, + { + []*rangePerm{{"a", "b"}, {"b", "c"}}, + []*rangePerm{{"a", "c"}}, + }, + { + []*rangePerm{{"a", "c"}, {"b", "d"}}, + []*rangePerm{{"a", "d"}}, + }, + { + []*rangePerm{{"a", "b"}, {"b", "c"}, {"d", "e"}}, + []*rangePerm{{"a", "c"}, {"d", "e"}}, + }, + { + []*rangePerm{{"a", "b"}, {"c", "d"}, {"e", "f"}}, + []*rangePerm{{"a", "b"}, {"c", "d"}, {"e", "f"}}, + }, + { + []*rangePerm{{"e", "f"}, {"c", "d"}, {"a", "b"}}, + []*rangePerm{{"a", "b"}, {"c", "d"}, {"e", "f"}}, + }, + { + []*rangePerm{{"a", "b"}, {"c", "d"}, {"a", "z"}}, + []*rangePerm{{"a", "z"}}, + }, + { + []*rangePerm{{"a", "b"}, {"c", "d"}, {"a", "z"}, {"1", "9"}}, + []*rangePerm{{"1", "9"}, {"a", "z"}}, + }, + { + []*rangePerm{{"a", "b"}, {"c", "d"}, {"a", "z"}, {"1", "a"}}, + []*rangePerm{{"1", "z"}}, + }, + { + []*rangePerm{{"a", "b"}, {"a", "z"}, {"5", "6"}, {"1", "9"}}, + []*rangePerm{{"1", "9"}, {"a", "z"}}, + }, + { + []*rangePerm{{"a", "b"}, {"b", "c"}, {"c", "d"}, {"d", "f"}, {"1", "9"}}, + []*rangePerm{{"1", "9"}, {"a", "f"}}, + }, + } + + for i, tt := range tests { + result := unifyPerms(tt.params) + if !isPermsEqual(result, tt.want) { + t.Errorf("#%d: result=%q, want=%q", i, result, tt.want) + } + } +} diff --git a/auth/store.go b/auth/store.go index 6fffa27b0..90872ecfd 100644 --- a/auth/store.go +++ b/auth/store.go @@ -103,13 +103,15 @@ type AuthStore interface { IsPutPermitted(header *pb.RequestHeader, key string) bool // IsRangePermitted checks range permission of the user - IsRangePermitted(header *pb.RequestHeader, key string) bool + IsRangePermitted(header *pb.RequestHeader, key, rangeEnd string) bool } type authStore struct { be backend.Backend enabled bool enabledMu sync.RWMutex + + rangePermCache map[string]*unifiedRangePermissions // username -> unifiedRangePermissions } func (as *authStore) AuthEnable() { @@ -126,6 +128,8 @@ func (as *authStore) AuthEnable() { as.enabled = true as.enabledMu.Unlock() + as.rangePermCache = make(map[string]*unifiedRangePermissions) + plog.Noticef("Authentication enabled") } @@ -301,6 +305,8 @@ func (as *authStore) UserGrantRole(r *pb.AuthUserGrantRoleRequest) (*pb.AuthUser tx.UnsafePut(authUsersBucketName, user.Name, marshaledUser) + as.invalidateCachedPerm(r.User) + plog.Noticef("granted role %s to user %s", r.Role, r.User) return &pb.AuthUserGrantRoleResponse{}, nil } @@ -357,6 +363,8 @@ func (as *authStore) UserRevokeRole(r *pb.AuthUserRevokeRoleRequest) (*pb.AuthUs tx.UnsafePut(authUsersBucketName, updatedUser.Name, marshaledUser) + as.invalidateCachedPerm(r.Name) + plog.Noticef("revoked role %s from user %s", r.Role, r.Name) return &pb.AuthUserRevokeRoleResponse{}, nil } @@ -424,6 +432,10 @@ func (as *authStore) RoleRevokePermission(r *pb.AuthRoleRevokePermissionRequest) tx.UnsafePut(authRolesBucketName, updatedRole.Name, marshaledRole) + // TODO(mitake): currently single role update invalidates every cache + // It should be optimized. + as.clearCachedPerm() + plog.Noticef("revoked key %s from role %s", r.Key, r.Role) return &pb.AuthRoleRevokePermissionResponse{}, nil } @@ -546,12 +558,16 @@ func (as *authStore) RoleGrantPermission(r *pb.AuthRoleGrantPermissionRequest) ( tx.UnsafePut(authRolesBucketName, []byte(r.Name), marshaledRole) + // TODO(mitake): currently single role update invalidates every cache + // It should be optimized. + as.clearCachedPerm() + plog.Noticef("role %s's permission of key %s is updated as %s", r.Name, r.Perm.Key, authpb.Permission_Type_name[int32(r.Perm.PermType)]) return &pb.AuthRoleGrantPermissionResponse{}, nil } -func (as *authStore) isOpPermitted(userName string, key string, write bool, read bool) bool { +func (as *authStore) isOpPermitted(userName string, key, rangeEnd string, write bool, read bool) bool { // TODO(mitake): this function would be costly so we need a caching mechanism if !as.isAuthEnabled() { return true @@ -567,22 +583,26 @@ func (as *authStore) isOpPermitted(userName string, key string, write bool, read return false } - for _, roleName := range user.Roles { - _, vs := tx.UnsafeRange(authRolesBucketName, []byte(roleName), nil, 0) - if len(vs) != 1 { - plog.Errorf("invalid role name %s for permission checking", roleName) - return false - } + if strings.Compare(rangeEnd, "") == 0 { + for _, roleName := range user.Roles { + _, vs := tx.UnsafeRange(authRolesBucketName, []byte(roleName), nil, 0) + if len(vs) != 1 { + plog.Errorf("invalid role name %s for permission checking", roleName) + return false + } - role := &authpb.Role{} - err := role.Unmarshal(vs[0]) - if err != nil { - plog.Errorf("failed to unmarshal a role %s: %s", roleName, err) - return false - } + role := &authpb.Role{} + err := role.Unmarshal(vs[0]) + if err != nil { + plog.Errorf("failed to unmarshal a role %s: %s", roleName, err) + return false + } + + for _, perm := range role.KeyPermission { + if !bytes.Equal(perm.Key, []byte(key)) { + continue + } - for _, perm := range role.KeyPermission { - if bytes.Equal(perm.Key, []byte(key)) { if perm.PermType == authpb.READWRITE { return true } @@ -598,15 +618,19 @@ func (as *authStore) isOpPermitted(userName string, key string, write bool, read } } + if as.isRangeOpPermitted(tx, userName, key, rangeEnd, write, read) { + return true + } + return false } func (as *authStore) IsPutPermitted(header *pb.RequestHeader, key string) bool { - return as.isOpPermitted(header.Username, key, true, false) + return as.isOpPermitted(header.Username, key, "", true, false) } -func (as *authStore) IsRangePermitted(header *pb.RequestHeader, key string) bool { - return as.isOpPermitted(header.Username, key, false, true) +func (as *authStore) IsRangePermitted(header *pb.RequestHeader, key, rangeEnd string) bool { + return as.isOpPermitted(header.Username, key, rangeEnd, false, true) } func getUser(tx backend.BatchTx, username string) *authpb.User { diff --git a/etcdserver/apply.go b/etcdserver/apply.go index 8a3742a31..7bf55abc8 100644 --- a/etcdserver/apply.go +++ b/etcdserver/apply.go @@ -81,7 +81,7 @@ func (s *EtcdServer) applyV3Request(r *pb.InternalRaftRequest) *applyResult { ar := &applyResult{} switch { case r.Range != nil: - if s.AuthStore().IsRangePermitted(r.Header, string(r.Range.Key)) { + if s.AuthStore().IsRangePermitted(r.Header, string(r.Range.Key), string(r.Range.RangeEnd)) { ar.resp, ar.err = s.applyV3.Range(noTxn, r.Range) } else { ar.err = auth.ErrPermissionDenied From 253e313c09df390d265e810668216e648f1a106e Mon Sep 17 00:00:00 2001 From: Hitoshi Mitake Date: Wed, 8 Jun 2016 11:52:57 -0700 Subject: [PATCH 2/2] *: support granting and revoking range This commit adds a feature for granting and revoking range of keys, not a single key. Example: $ ETCDCTL_API=3 bin/etcdctl role grant r1 readwrite k1 k3 Role r1 updated $ ETCDCTL_API=3 bin/etcdctl role get r1 Role r1 KV Read: [a, b) [k1, k3) [k2, k4) KV Write: [a, b) [k1, k3) [k2, k4) $ ETCDCTL_API=3 bin/etcdctl --user u1:p get k1 k4 k1 v1 $ ETCDCTL_API=3 bin/etcdctl --user u1:p get k1 k5 Error: etcdserver: permission denied --- auth/store.go | 5 +- clientv3/auth.go | 13 +- etcdctl/ctlv3/command/role_command.go | 38 ++- etcdserver/etcdserverpb/rpc.pb.go | 380 ++++++++++++++------------ etcdserver/etcdserverpb/rpc.proto | 1 + 5 files changed, 249 insertions(+), 188 deletions(-) diff --git a/auth/store.go b/auth/store.go index 90872ecfd..f872eb9ba 100644 --- a/auth/store.go +++ b/auth/store.go @@ -414,7 +414,7 @@ func (as *authStore) RoleRevokePermission(r *pb.AuthRoleRevokePermissionRequest) revoked := false for _, perm := range role.KeyPermission { - if !bytes.Equal(perm.Key, []byte(r.Key)) { + if !bytes.Equal(perm.Key, []byte(r.Key)) || !bytes.Equal(perm.RangeEnd, []byte(r.RangeEnd)) { updatedRole.KeyPermission = append(updatedRole.KeyPermission, perm) } else { revoked = true @@ -536,13 +536,14 @@ func (as *authStore) RoleGrantPermission(r *pb.AuthRoleGrantPermissionRequest) ( return bytes.Compare(role.KeyPermission[i].Key, []byte(r.Perm.Key)) >= 0 }) - if idx < len(role.KeyPermission) && bytes.Equal(role.KeyPermission[idx].Key, r.Perm.Key) { + if idx < len(role.KeyPermission) && bytes.Equal(role.KeyPermission[idx].Key, r.Perm.Key) && bytes.Equal(role.KeyPermission[idx].RangeEnd, r.Perm.RangeEnd) { // update existing permission role.KeyPermission[idx].PermType = r.Perm.PermType } else { // append new permission to the role newPerm := &authpb.Permission{ Key: []byte(r.Perm.Key), + RangeEnd: []byte(r.Perm.RangeEnd), PermType: r.Perm.PermType, } diff --git a/clientv3/auth.go b/clientv3/auth.go index a1fb49250..52c35450d 100644 --- a/clientv3/auth.go +++ b/clientv3/auth.go @@ -78,13 +78,13 @@ type Auth interface { RoleAdd(ctx context.Context, name string) (*AuthRoleAddResponse, error) // RoleGrantPermission grants a permission to a role. - RoleGrantPermission(ctx context.Context, name string, key string, permType PermissionType) (*AuthRoleGrantPermissionResponse, error) + RoleGrantPermission(ctx context.Context, name string, key, rangeEnd string, permType PermissionType) (*AuthRoleGrantPermissionResponse, error) // RoleGet gets a detailed information of a role. RoleGet(ctx context.Context, role string) (*AuthRoleGetResponse, error) - // RoleRevokePermission revokes a key from a user. - RoleRevokePermission(ctx context.Context, role string, key string) (*AuthRoleRevokePermissionResponse, error) + // RoleRevokePermission revokes a permission from a role. + RoleRevokePermission(ctx context.Context, role string, key, rangeEnd string) (*AuthRoleRevokePermissionResponse, error) // RoleDelete deletes a role. RoleDelete(ctx context.Context, role string) (*AuthRoleDeleteResponse, error) @@ -151,9 +151,10 @@ func (auth *auth) RoleAdd(ctx context.Context, name string) (*AuthRoleAddRespons return (*AuthRoleAddResponse)(resp), toErr(ctx, err) } -func (auth *auth) RoleGrantPermission(ctx context.Context, name string, key string, permType PermissionType) (*AuthRoleGrantPermissionResponse, error) { +func (auth *auth) RoleGrantPermission(ctx context.Context, name string, key, rangeEnd string, permType PermissionType) (*AuthRoleGrantPermissionResponse, error) { perm := &authpb.Permission{ Key: []byte(key), + RangeEnd: []byte(rangeEnd), PermType: authpb.Permission_Type(permType), } resp, err := auth.remote.RoleGrantPermission(ctx, &pb.AuthRoleGrantPermissionRequest{Name: name, Perm: perm}) @@ -165,8 +166,8 @@ func (auth *auth) RoleGet(ctx context.Context, role string) (*AuthRoleGetRespons return (*AuthRoleGetResponse)(resp), toErr(ctx, err) } -func (auth *auth) RoleRevokePermission(ctx context.Context, role string, key string) (*AuthRoleRevokePermissionResponse, error) { - resp, err := auth.remote.RoleRevokePermission(ctx, &pb.AuthRoleRevokePermissionRequest{Role: role, Key: key}) +func (auth *auth) RoleRevokePermission(ctx context.Context, role string, key, rangeEnd string) (*AuthRoleRevokePermissionResponse, error) { + resp, err := auth.remote.RoleRevokePermission(ctx, &pb.AuthRoleRevokePermissionRequest{Role: role, Key: key, RangeEnd: rangeEnd}) return (*AuthRoleRevokePermissionResponse)(resp), toErr(ctx, err) } diff --git a/etcdctl/ctlv3/command/role_command.go b/etcdctl/ctlv3/command/role_command.go index 839431b83..1eb7e4da8 100644 --- a/etcdctl/ctlv3/command/role_command.go +++ b/etcdctl/ctlv3/command/role_command.go @@ -64,7 +64,7 @@ func newRoleGetCommand() *cobra.Command { func newRoleGrantPermissionCommand() *cobra.Command { return &cobra.Command{ - Use: "grant-permission ", + Use: "grant-permission [endkey]", Short: "grant a key to a role", Run: roleGrantPermissionCommandFunc, } @@ -72,7 +72,7 @@ func newRoleGrantPermissionCommand() *cobra.Command { func newRoleRevokePermissionCommand() *cobra.Command { return &cobra.Command{ - Use: "revoke-permission ", + Use: "revoke-permission [endkey]", Short: "revoke a key from a role", Run: roleRevokePermissionCommandFunc, } @@ -121,21 +121,29 @@ func roleGetCommandFunc(cmd *cobra.Command, args []string) { fmt.Println("KV Read:") for _, perm := range resp.Perm { if perm.PermType == clientv3.PermRead || perm.PermType == clientv3.PermReadWrite { - fmt.Printf("\t%s\n", string(perm.Key)) + if len(perm.RangeEnd) == 0 { + fmt.Printf("\t%s\n", string(perm.Key)) + } else { + fmt.Printf("\t[%s, %s)\n", string(perm.Key), string(perm.RangeEnd)) + } } } fmt.Println("KV Write:") for _, perm := range resp.Perm { if perm.PermType == clientv3.PermWrite || perm.PermType == clientv3.PermReadWrite { - fmt.Printf("\t%s\n", string(perm.Key)) + if len(perm.RangeEnd) == 0 { + fmt.Printf("\t%s\n", string(perm.Key)) + } else { + fmt.Printf("\t[%s, %s)\n", string(perm.Key), string(perm.RangeEnd)) + } } } } // roleGrantPermissionCommandFunc executes the "role grant-permission" command. func roleGrantPermissionCommandFunc(cmd *cobra.Command, args []string) { - if len(args) != 3 { - ExitWithError(ExitBadArgs, fmt.Errorf("role grant command requires role name, permission type, and key as its argument.")) + if len(args) < 3 { + ExitWithError(ExitBadArgs, fmt.Errorf("role grant command requires role name, permission type, and key [endkey] as its argument.")) } perm, err := clientv3.StrToPermissionType(args[1]) @@ -143,7 +151,12 @@ func roleGrantPermissionCommandFunc(cmd *cobra.Command, args []string) { ExitWithError(ExitBadArgs, err) } - _, err = mustClientFromCmd(cmd).Auth.RoleGrantPermission(context.TODO(), args[0], args[2], perm) + rangeEnd := "" + if 4 <= len(args) { + rangeEnd = args[3] + } + + _, err = mustClientFromCmd(cmd).Auth.RoleGrantPermission(context.TODO(), args[0], args[2], rangeEnd, perm) if err != nil { ExitWithError(ExitError, err) } @@ -153,11 +166,16 @@ func roleGrantPermissionCommandFunc(cmd *cobra.Command, args []string) { // roleRevokePermissionCommandFunc executes the "role revoke-permission" command. func roleRevokePermissionCommandFunc(cmd *cobra.Command, args []string) { - if len(args) != 2 { - ExitWithError(ExitBadArgs, fmt.Errorf("role revoke-permission command requires role name and key as its argument.")) + if len(args) < 2 { + ExitWithError(ExitBadArgs, fmt.Errorf("role revoke-permission command requires role name and key [endkey] as its argument.")) } - _, err := mustClientFromCmd(cmd).Auth.RoleRevokePermission(context.TODO(), args[0], args[1]) + rangeEnd := "" + if 3 <= len(args) { + rangeEnd = args[2] + } + + _, err := mustClientFromCmd(cmd).Auth.RoleRevokePermission(context.TODO(), args[0], args[1], rangeEnd) if err != nil { ExitWithError(ExitError, err) } diff --git a/etcdserver/etcdserverpb/rpc.pb.go b/etcdserver/etcdserverpb/rpc.pb.go index 51c2bfafc..cc84c89f1 100644 --- a/etcdserver/etcdserverpb/rpc.pb.go +++ b/etcdserver/etcdserverpb/rpc.pb.go @@ -1652,8 +1652,9 @@ func (m *AuthRoleGrantPermissionRequest) GetPerm() *authpb.Permission { } type AuthRoleRevokePermissionRequest struct { - Role string `protobuf:"bytes,1,opt,name=role,proto3" json:"role,omitempty"` - Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` + Role string `protobuf:"bytes,1,opt,name=role,proto3" json:"role,omitempty"` + Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` + RangeEnd string `protobuf:"bytes,3,opt,name=range_end,json=rangeEnd,proto3" json:"range_end,omitempty"` } func (m *AuthRoleRevokePermissionRequest) Reset() { *m = AuthRoleRevokePermissionRequest{} } @@ -5441,6 +5442,12 @@ func (m *AuthRoleRevokePermissionRequest) MarshalTo(data []byte) (int, error) { i = encodeVarintRpc(data, i, uint64(len(m.Key))) i += copy(data[i:], m.Key) } + if len(m.RangeEnd) > 0 { + data[i] = 0x1a + i++ + i = encodeVarintRpc(data, i, uint64(len(m.RangeEnd))) + i += copy(data[i:], m.RangeEnd) + } return i, nil } @@ -6766,6 +6773,10 @@ func (m *AuthRoleRevokePermissionRequest) Size() (n int) { if l > 0 { n += 1 + l + sovRpc(uint64(l)) } + l = len(m.RangeEnd) + if l > 0 { + n += 1 + l + sovRpc(uint64(l)) + } return n } @@ -12987,6 +12998,35 @@ func (m *AuthRoleRevokePermissionRequest) Unmarshal(data []byte) error { } m.Key = string(data[iNdEx:postIndex]) iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RangeEnd", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRpc + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthRpc + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RangeEnd = string(data[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipRpc(data[iNdEx:]) @@ -14365,172 +14405,172 @@ var ( ) var fileDescriptorRpc = []byte{ - // 2671 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xb4, 0x5a, 0x4f, 0x6f, 0xdb, 0xc8, - 0x15, 0x17, 0x25, 0x59, 0xb2, 0x9e, 0xfe, 0x58, 0x19, 0x3b, 0xa9, 0xc2, 0x24, 0x8e, 0x77, 0xf2, - 0xcf, 0xdb, 0xcd, 0x2a, 0x1b, 0x77, 0xdb, 0x4b, 0x17, 0x5b, 0xc8, 0x92, 0xd6, 0xf6, 0xda, 0xb1, - 0x1d, 0x5a, 0x71, 0xb2, 0x40, 0x01, 0x83, 0x92, 0x26, 0x36, 0x11, 0x89, 0xd4, 0x92, 0x94, 0x13, - 0x07, 0xe8, 0xa5, 0x40, 0x3f, 0xc1, 0xf6, 0xd2, 0x5e, 0xfb, 0x11, 0x8a, 0x7e, 0x87, 0xa2, 0x97, - 0xf6, 0x13, 0x14, 0x45, 0x4e, 0x45, 0xd1, 0x7b, 0x0f, 0xbd, 0x14, 0xf3, 0x8f, 0x1c, 0x52, 0x94, - 0x93, 0x2d, 0xdb, 0x4b, 0xcc, 0x79, 0x7c, 0xef, 0x37, 0x6f, 0xde, 0xbc, 0xf9, 0xf1, 0xbd, 0x51, - 0xa0, 0xe4, 0x4e, 0x06, 0xcd, 0x89, 0xeb, 0xf8, 0x0e, 0xaa, 0x10, 0x7f, 0x30, 0xf4, 0x88, 0x7b, - 0x4e, 0xdc, 0x49, 0x5f, 0x5f, 0x39, 0x75, 0x4e, 0x1d, 0xf6, 0xe2, 0x11, 0x7d, 0xe2, 0x3a, 0xfa, - 0x75, 0xaa, 0xf3, 0x68, 0x7c, 0x3e, 0x18, 0xb0, 0x7f, 0x26, 0xfd, 0x47, 0xaf, 0xce, 0xc5, 0xab, - 0x1b, 0xec, 0x95, 0x39, 0xf5, 0xcf, 0xd8, 0x3f, 0x93, 0x3e, 0xfb, 0xc3, 0x5f, 0xe2, 0x5f, 0x69, - 0x50, 0x33, 0x88, 0x37, 0x71, 0x6c, 0x8f, 0x6c, 0x13, 0x73, 0x48, 0x5c, 0x74, 0x0b, 0x60, 0x30, - 0x9a, 0x7a, 0x3e, 0x71, 0x4f, 0xac, 0x61, 0x43, 0x5b, 0xd3, 0xd6, 0xf3, 0x46, 0x49, 0x48, 0x76, - 0x86, 0xe8, 0x06, 0x94, 0xc6, 0x64, 0xdc, 0xe7, 0x6f, 0xb3, 0xec, 0xed, 0x22, 0x17, 0xec, 0x0c, - 0x91, 0x0e, 0x8b, 0x2e, 0x39, 0xb7, 0x3c, 0xcb, 0xb1, 0x1b, 0xb9, 0x35, 0x6d, 0x3d, 0x67, 0x04, - 0x63, 0x6a, 0xe8, 0x9a, 0x2f, 0xfd, 0x13, 0x9f, 0xb8, 0xe3, 0x46, 0x9e, 0x1b, 0x52, 0x41, 0x8f, - 0xb8, 0x63, 0xfc, 0xeb, 0x1c, 0x54, 0x0c, 0xd3, 0x3e, 0x25, 0x06, 0xf9, 0x76, 0x4a, 0x3c, 0x1f, - 0xd5, 0x21, 0xf7, 0x8a, 0x5c, 0xb0, 0xe9, 0x2b, 0x06, 0x7d, 0xe4, 0xf6, 0xf6, 0x29, 0x39, 0x21, - 0x36, 0x9f, 0xb8, 0x42, 0xed, 0xed, 0x53, 0xd2, 0xb5, 0x87, 0x68, 0x05, 0x16, 0x46, 0xd6, 0xd8, - 0xf2, 0xc5, 0xac, 0x7c, 0x10, 0x71, 0x27, 0x1f, 0x73, 0xa7, 0x0d, 0xe0, 0x39, 0xae, 0x7f, 0xe2, - 0xb8, 0x43, 0xe2, 0x36, 0x16, 0xd6, 0xb4, 0xf5, 0xda, 0xc6, 0xdd, 0xa6, 0x1a, 0xea, 0xa6, 0xea, - 0x50, 0xf3, 0xc8, 0x71, 0xfd, 0x03, 0xaa, 0x6b, 0x94, 0x3c, 0xf9, 0x88, 0xbe, 0x82, 0x32, 0x03, - 0xf1, 0x4d, 0xf7, 0x94, 0xf8, 0x8d, 0x02, 0x43, 0xb9, 0xf7, 0x1e, 0x94, 0x1e, 0x53, 0x36, 0xd8, - 0xf4, 0xfc, 0x19, 0x61, 0xa8, 0x78, 0xc4, 0xb5, 0xcc, 0x91, 0xf5, 0xd6, 0xec, 0x8f, 0x48, 0xa3, - 0xb8, 0xa6, 0xad, 0x2f, 0x1a, 0x11, 0x19, 0x6e, 0x42, 0x29, 0xf0, 0x01, 0x2d, 0x42, 0x7e, 0xff, - 0x60, 0xbf, 0x5b, 0xcf, 0x20, 0x80, 0x42, 0xeb, 0xa8, 0xdd, 0xdd, 0xef, 0xd4, 0x35, 0x54, 0x86, - 0x62, 0xa7, 0xcb, 0x07, 0x59, 0xbc, 0x09, 0x10, 0xce, 0x86, 0x8a, 0x90, 0xdb, 0xed, 0x7e, 0x53, - 0xcf, 0x50, 0x9d, 0xe3, 0xae, 0x71, 0xb4, 0x73, 0xb0, 0x5f, 0xd7, 0xa8, 0x71, 0xdb, 0xe8, 0xb6, - 0x7a, 0xdd, 0x7a, 0x96, 0x6a, 0x3c, 0x39, 0xe8, 0xd4, 0x73, 0xa8, 0x04, 0x0b, 0xc7, 0xad, 0xbd, - 0x67, 0xdd, 0x7a, 0x1e, 0xff, 0x02, 0xaa, 0xc2, 0x7d, 0x9e, 0x22, 0xe8, 0x73, 0x28, 0x9c, 0xb1, - 0x34, 0x61, 0x3b, 0x53, 0xde, 0xb8, 0x19, 0x5b, 0x6b, 0x24, 0x95, 0x0c, 0xa1, 0x8b, 0x30, 0xe4, - 0x5e, 0x9d, 0x7b, 0x8d, 0xec, 0x5a, 0x6e, 0xbd, 0xbc, 0x51, 0x6f, 0xf2, 0x0c, 0x6d, 0xee, 0x92, - 0x8b, 0x63, 0x73, 0x34, 0x25, 0x06, 0x7d, 0x89, 0x10, 0xe4, 0xc7, 0x8e, 0x4b, 0xd8, 0x06, 0x2e, - 0x1a, 0xec, 0x19, 0x7f, 0x0d, 0x70, 0x38, 0xf5, 0xe7, 0xa7, 0xc4, 0x0a, 0x2c, 0x9c, 0x53, 0x04, - 0x91, 0x0e, 0x7c, 0xc0, 0x72, 0x81, 0x98, 0x1e, 0x09, 0x72, 0x81, 0x0e, 0x70, 0x1b, 0xca, 0x0c, - 0x2b, 0xcd, 0x42, 0x70, 0x1b, 0x50, 0x87, 0x8c, 0x88, 0x4f, 0x52, 0xe4, 0x2a, 0x26, 0xb0, 0x1c, - 0x01, 0x49, 0x15, 0xda, 0x06, 0x14, 0x87, 0x0c, 0x8c, 0xcf, 0x93, 0x33, 0xe4, 0x10, 0xff, 0x53, - 0x83, 0x92, 0xf0, 0xf0, 0x60, 0x82, 0x5a, 0x50, 0x75, 0xf9, 0xe0, 0x84, 0x39, 0x22, 0x26, 0xd1, - 0xe7, 0xe7, 0xea, 0x76, 0xc6, 0xa8, 0x08, 0x13, 0x26, 0x46, 0x3f, 0x85, 0xb2, 0x84, 0x98, 0x4c, - 0x7d, 0x36, 0x5d, 0x79, 0xa3, 0x11, 0x05, 0x08, 0xb7, 0x6b, 0x3b, 0x63, 0x80, 0x50, 0x3f, 0x9c, - 0xfa, 0xa8, 0x07, 0x2b, 0xd2, 0x98, 0x3b, 0x28, 0xdc, 0xc8, 0x31, 0x94, 0xb5, 0x28, 0xca, 0x6c, - 0x8c, 0xb7, 0x33, 0x06, 0x12, 0xf6, 0xca, 0xcb, 0xcd, 0x12, 0x14, 0x85, 0x14, 0xff, 0x4b, 0x03, - 0x90, 0x31, 0x3a, 0x98, 0xa0, 0x0e, 0xd4, 0x5c, 0x31, 0x8a, 0x2c, 0xf8, 0x46, 0xe2, 0x82, 0x45, - 0x68, 0x33, 0x46, 0x55, 0x1a, 0xf1, 0x25, 0x7f, 0x09, 0x95, 0x00, 0x25, 0x5c, 0xf3, 0xf5, 0x84, - 0x35, 0x07, 0x08, 0x65, 0x69, 0x40, 0x57, 0xfd, 0x1c, 0xae, 0x06, 0xf6, 0x09, 0xcb, 0xfe, 0xe8, - 0x92, 0x65, 0x07, 0x80, 0xcb, 0x12, 0x41, 0x5d, 0x38, 0x50, 0x66, 0xe3, 0x62, 0xfc, 0xdb, 0x1c, - 0x14, 0xdb, 0xce, 0x78, 0x62, 0xba, 0x74, 0x8f, 0x0a, 0x2e, 0xf1, 0xa6, 0x23, 0x9f, 0x2d, 0xb7, - 0xb6, 0x71, 0x27, 0x3a, 0x83, 0x50, 0x93, 0x7f, 0x0d, 0xa6, 0x6a, 0x08, 0x13, 0x6a, 0x2c, 0x88, - 0x2c, 0xfb, 0x01, 0xc6, 0x82, 0xc6, 0x84, 0x89, 0x3c, 0x04, 0xb9, 0xf0, 0x10, 0xe8, 0x50, 0x3c, - 0x27, 0x6e, 0x48, 0xbe, 0xdb, 0x19, 0x43, 0x0a, 0xd0, 0xc7, 0xb0, 0x34, 0x70, 0x89, 0x49, 0xe3, - 0x21, 0x09, 0x7a, 0x41, 0xe8, 0xd4, 0xf8, 0x0b, 0x43, 0x12, 0xf5, 0x1d, 0xa8, 0x8c, 0x9d, 0x61, - 0xa8, 0x57, 0x10, 0x7a, 0xe5, 0xb1, 0x33, 0x0c, 0x94, 0xae, 0x49, 0x26, 0xa0, 0xcc, 0x59, 0xd9, - 0xce, 0x08, 0x2e, 0xc0, 0x8f, 0xa1, 0x1a, 0x59, 0x2b, 0x25, 0xb7, 0xee, 0xd3, 0x67, 0xad, 0x3d, - 0xce, 0x84, 0x5b, 0x8c, 0xfc, 0x8c, 0xba, 0x46, 0x09, 0x75, 0xaf, 0x7b, 0x74, 0x54, 0xcf, 0xe2, - 0x2f, 0x02, 0x13, 0x41, 0x9d, 0x0a, 0x63, 0x66, 0x14, 0xc6, 0xd4, 0x24, 0x63, 0x66, 0x43, 0xc6, - 0xcc, 0x6d, 0xd6, 0xa0, 0xc2, 0x03, 0x72, 0x32, 0xb5, 0x2d, 0xc7, 0xc6, 0xbf, 0xd3, 0x00, 0x7a, - 0x6f, 0x6c, 0x49, 0x15, 0x8f, 0xa0, 0x38, 0xe0, 0xe0, 0x0d, 0x8d, 0xb1, 0xe1, 0xd5, 0xc4, 0x18, - 0x1b, 0x52, 0x0b, 0x3d, 0x86, 0xa2, 0x37, 0x1d, 0x0c, 0x88, 0x27, 0xe9, 0xf3, 0x07, 0x71, 0x5a, - 0x10, 0x27, 0xdc, 0x90, 0x7a, 0xd4, 0xe4, 0xa5, 0x69, 0x8d, 0xa6, 0x8c, 0x4c, 0x2f, 0x37, 0x11, - 0x7a, 0xf8, 0x37, 0x1a, 0x94, 0x99, 0x97, 0xa9, 0xb8, 0xe8, 0x26, 0x94, 0x98, 0x0f, 0x64, 0x28, - 0xd8, 0x68, 0xd1, 0x08, 0x05, 0xe8, 0x27, 0x50, 0x92, 0x29, 0xeb, 0x09, 0xc7, 0x1a, 0xc9, 0xb0, - 0x07, 0x13, 0x23, 0x54, 0xc5, 0xbb, 0x70, 0x85, 0x45, 0x65, 0xe0, 0x5b, 0x4e, 0x10, 0x47, 0xf5, - 0xcb, 0xae, 0xc5, 0xbe, 0xec, 0x3a, 0x2c, 0x4e, 0xce, 0x2e, 0x3c, 0x6b, 0x60, 0x8e, 0x84, 0x17, - 0xc1, 0x18, 0x7f, 0x0d, 0x48, 0x05, 0x4b, 0xf5, 0x31, 0xa8, 0x42, 0x79, 0xdb, 0xf4, 0xce, 0x84, - 0x4b, 0xf8, 0x05, 0x54, 0xf8, 0x30, 0x55, 0x0c, 0x11, 0xe4, 0xcf, 0x4c, 0xef, 0x8c, 0x39, 0x5e, - 0x35, 0xd8, 0x33, 0xbe, 0x02, 0x4b, 0x47, 0xb6, 0x39, 0xf1, 0xce, 0x1c, 0x49, 0xae, 0xb4, 0x6e, - 0xab, 0x87, 0xb2, 0x54, 0x33, 0x3e, 0x80, 0x25, 0x97, 0x8c, 0x4d, 0xcb, 0xb6, 0xec, 0xd3, 0x93, - 0xfe, 0x85, 0x4f, 0x3c, 0x51, 0xd6, 0xd5, 0x02, 0xf1, 0x26, 0x95, 0x52, 0xd7, 0xfa, 0x23, 0xa7, - 0x2f, 0x8e, 0x38, 0x7b, 0xc6, 0x7f, 0xd0, 0xa0, 0xf2, 0xdc, 0xf4, 0x07, 0x32, 0x0a, 0x68, 0x07, - 0x6a, 0xc1, 0xc1, 0x66, 0x12, 0xe1, 0x4b, 0x8c, 0xe1, 0x99, 0x4d, 0x5b, 0x1c, 0x74, 0xc9, 0xf0, - 0xd5, 0x81, 0x2a, 0x60, 0x50, 0xa6, 0x3d, 0x20, 0xa3, 0x00, 0x2a, 0x3b, 0x1f, 0x8a, 0x29, 0xaa, - 0x50, 0xaa, 0x60, 0x73, 0x29, 0xfc, 0xfa, 0xf1, 0x63, 0xf9, 0x9d, 0x06, 0x68, 0xd6, 0x87, 0xef, - 0x5b, 0x75, 0xde, 0x83, 0x9a, 0xe7, 0x9b, 0xae, 0x7f, 0x12, 0x2b, 0x7a, 0xab, 0x4c, 0x1a, 0x90, - 0xd3, 0x03, 0x58, 0x9a, 0xb8, 0xce, 0xa9, 0x4b, 0x3c, 0xef, 0xc4, 0x76, 0x7c, 0xeb, 0xe5, 0x05, - 0x23, 0xc4, 0x45, 0xa3, 0x26, 0xc5, 0xfb, 0x4c, 0x8a, 0x1f, 0x49, 0xa7, 0x54, 0xe7, 0xd1, 0x75, - 0x58, 0x7c, 0x4d, 0xa5, 0xb2, 0x1c, 0xcf, 0x19, 0x45, 0x36, 0xde, 0x19, 0xe2, 0xbf, 0x6b, 0x50, - 0x15, 0xe1, 0x4f, 0x95, 0x03, 0xea, 0x14, 0xd9, 0xc8, 0x14, 0xb4, 0xc0, 0xe0, 0xdb, 0x32, 0x14, - 0xa5, 0x99, 0x1c, 0xd2, 0x73, 0xc6, 0xa3, 0x4c, 0x86, 0x62, 0x3d, 0xc1, 0x18, 0x7d, 0x0c, 0xf5, - 0x01, 0x3f, 0x67, 0x31, 0x82, 0x37, 0x96, 0x84, 0x3c, 0x88, 0xce, 0x3d, 0x28, 0x90, 0x73, 0x62, - 0xfb, 0x5e, 0xa3, 0xcc, 0x48, 0xa1, 0x2a, 0xeb, 0xc3, 0x2e, 0x95, 0x1a, 0xe2, 0x25, 0xfe, 0x31, - 0x5c, 0xd9, 0xa3, 0x85, 0xdc, 0x96, 0x6b, 0xda, 0x6a, 0x49, 0xd8, 0xeb, 0xed, 0x89, 0xa8, 0xe4, - 0xfc, 0xde, 0x1e, 0xaa, 0x41, 0x76, 0xa7, 0x23, 0xd6, 0x90, 0xb5, 0x3a, 0xf8, 0x97, 0x1a, 0x20, - 0xd5, 0x2e, 0x55, 0x98, 0x62, 0xe0, 0x72, 0xfa, 0x5c, 0x38, 0xfd, 0x0a, 0x2c, 0x10, 0xd7, 0x75, - 0x5c, 0x16, 0x90, 0x92, 0xc1, 0x07, 0xf8, 0xae, 0xf0, 0xc1, 0x20, 0xe7, 0xce, 0xab, 0x20, 0xd9, - 0x38, 0x9a, 0x16, 0xb8, 0xba, 0x0b, 0xcb, 0x11, 0xad, 0x54, 0xe4, 0xf4, 0x00, 0xae, 0x32, 0xb0, - 0x5d, 0x42, 0x26, 0xad, 0x91, 0x75, 0x3e, 0x77, 0xd6, 0x09, 0x5c, 0x8b, 0x2b, 0xfe, 0x7f, 0x63, - 0x84, 0xcf, 0xa0, 0xf0, 0x84, 0x35, 0x8c, 0x8a, 0x2f, 0x79, 0xa6, 0x8b, 0x20, 0x6f, 0x9b, 0x63, - 0x5e, 0xce, 0x97, 0x0c, 0xf6, 0xcc, 0xd8, 0x9c, 0x10, 0xf7, 0x99, 0xb1, 0xc7, 0xbf, 0x1a, 0x25, - 0x23, 0x18, 0xa3, 0x55, 0xda, 0xaa, 0x5a, 0xc4, 0xf6, 0xd9, 0xdb, 0x3c, 0x7b, 0xab, 0x48, 0x70, - 0x13, 0xea, 0x7c, 0xa6, 0xd6, 0x70, 0xa8, 0x7c, 0x39, 0x02, 0x3c, 0x2d, 0x8a, 0x87, 0x5f, 0xc3, - 0x15, 0x45, 0x3f, 0x55, 0x18, 0x1e, 0x42, 0x81, 0x77, 0xc5, 0x82, 0xb4, 0x56, 0xa2, 0x56, 0x7c, - 0x1a, 0x43, 0xe8, 0xe0, 0x7b, 0xb0, 0x2c, 0x24, 0x64, 0xec, 0x24, 0xed, 0x15, 0x8b, 0x0f, 0xde, - 0x83, 0x95, 0xa8, 0x5a, 0xaa, 0x14, 0x69, 0xc9, 0x49, 0x9f, 0x4d, 0x86, 0x0a, 0x07, 0xc6, 0x37, - 0x45, 0x0d, 0x58, 0x36, 0x16, 0xb0, 0xc0, 0x21, 0x09, 0x91, 0xca, 0xa1, 0x65, 0x19, 0xfe, 0x3d, - 0xcb, 0x0b, 0xbe, 0x74, 0x6f, 0x01, 0xa9, 0xc2, 0x54, 0x9b, 0xd2, 0x84, 0x22, 0x0f, 0xb8, 0x2c, - 0xa6, 0x92, 0x77, 0x45, 0x2a, 0x51, 0x87, 0x3a, 0xe4, 0xa5, 0x6b, 0x9e, 0x8e, 0x49, 0xc0, 0x39, - 0xb4, 0x84, 0x50, 0x85, 0xa9, 0x56, 0xfc, 0x67, 0x0d, 0x2a, 0xad, 0x91, 0xe9, 0x8e, 0x65, 0xf0, - 0xbf, 0x84, 0x02, 0xaf, 0x4d, 0x44, 0xfd, 0x7e, 0x3f, 0x0a, 0xa3, 0xea, 0xf2, 0x41, 0x8b, 0x57, - 0x32, 0xc2, 0x8a, 0x6e, 0x96, 0xb8, 0x8c, 0xe9, 0xc4, 0x2e, 0x67, 0x3a, 0xe8, 0x53, 0x58, 0x30, - 0xa9, 0x09, 0x3b, 0x8b, 0xb5, 0x78, 0x55, 0xc8, 0xd0, 0x7a, 0x17, 0x13, 0x62, 0x70, 0x2d, 0xfc, - 0x39, 0x94, 0x95, 0x19, 0x68, 0xb1, 0xbb, 0xd5, 0xed, 0xd5, 0x33, 0xa8, 0x02, 0x8b, 0xad, 0x76, - 0x6f, 0xe7, 0x98, 0xd7, 0xc0, 0x35, 0x80, 0x4e, 0x37, 0x18, 0x67, 0xf1, 0x0b, 0x61, 0x25, 0x4e, - 0xb8, 0xea, 0x8f, 0x36, 0xcf, 0x9f, 0xec, 0x07, 0xf9, 0xf3, 0x06, 0xaa, 0x62, 0xf9, 0xa9, 0x72, - 0xe0, 0x31, 0x14, 0x18, 0x9e, 0x4c, 0x81, 0xeb, 0x09, 0xd3, 0xca, 0xd3, 0xc9, 0x15, 0xf1, 0x12, - 0x54, 0x8f, 0x7c, 0xd3, 0x9f, 0x7a, 0x32, 0x05, 0xfe, 0xa4, 0x41, 0x4d, 0x4a, 0xd2, 0x76, 0xef, - 0xb2, 0x45, 0xe2, 0x9c, 0x17, 0x34, 0x48, 0xd7, 0xa0, 0x30, 0xec, 0x1f, 0x59, 0x6f, 0xe5, 0x2d, - 0x86, 0x18, 0x51, 0xf9, 0x88, 0xcf, 0xc3, 0xaf, 0xd0, 0xc4, 0x88, 0xd6, 0xde, 0xae, 0xf9, 0xd2, - 0xdf, 0xb1, 0x87, 0xe4, 0x0d, 0xfb, 0xd2, 0xe6, 0x8d, 0x50, 0xc0, 0xca, 0x65, 0x71, 0xd5, 0xc6, - 0xfa, 0x27, 0xf5, 0xea, 0x6d, 0x19, 0xae, 0xb4, 0xa6, 0xfe, 0x59, 0xd7, 0x36, 0xfb, 0x23, 0x49, - 0x02, 0x78, 0x05, 0x10, 0x15, 0x76, 0x2c, 0x4f, 0x95, 0x76, 0x61, 0x99, 0x4a, 0x89, 0xed, 0x5b, - 0x03, 0x85, 0x31, 0x24, 0x6d, 0x6b, 0x31, 0xda, 0x36, 0x3d, 0xef, 0xb5, 0xe3, 0x0e, 0xc5, 0xd2, - 0x82, 0x31, 0xee, 0x70, 0xf0, 0x67, 0x5e, 0x84, 0x98, 0xbf, 0x2f, 0xca, 0x7a, 0x88, 0xb2, 0x45, - 0xfc, 0x4b, 0x50, 0xf0, 0x27, 0x70, 0x55, 0x6a, 0x8a, 0x1e, 0xfa, 0x12, 0xe5, 0x03, 0xb8, 0x25, - 0x95, 0xdb, 0x67, 0xb4, 0xd0, 0x3b, 0x14, 0x13, 0xfe, 0xb7, 0x7e, 0x6e, 0x42, 0x23, 0xf0, 0x93, - 0xd5, 0x20, 0xce, 0x48, 0x75, 0x60, 0xea, 0x89, 0x9c, 0x29, 0x19, 0xec, 0x99, 0xca, 0x5c, 0x67, - 0x14, 0x7c, 0x04, 0xe9, 0x33, 0x6e, 0xc3, 0x75, 0x89, 0x21, 0xaa, 0x83, 0x28, 0xc8, 0x8c, 0x43, - 0x49, 0x20, 0x22, 0x60, 0xd4, 0xf4, 0xf2, 0xb0, 0xab, 0x9a, 0xd1, 0xd0, 0x32, 0x4c, 0x4d, 0xc1, - 0x14, 0xa1, 0xa5, 0x9a, 0x33, 0xa1, 0x9d, 0x51, 0xfe, 0x39, 0xac, 0x06, 0xb0, 0x34, 0x12, 0x87, - 0xc4, 0x1d, 0x5b, 0x9e, 0xa7, 0xb4, 0x75, 0x49, 0x4b, 0xb9, 0x0f, 0xf9, 0x09, 0x11, 0x2c, 0x51, - 0xde, 0x40, 0x4d, 0x7e, 0x89, 0xdd, 0x54, 0x8c, 0xd9, 0x7b, 0xbc, 0x05, 0xb7, 0x25, 0x3a, 0x8f, - 0x51, 0x22, 0x7c, 0xdc, 0x29, 0x59, 0xf2, 0xf3, 0x40, 0xd1, 0x47, 0x4a, 0xf0, 0xea, 0x81, 0x48, - 0x45, 0xf0, 0xbb, 0xfc, 0xc4, 0x04, 0xe7, 0x28, 0x15, 0x58, 0x1f, 0x56, 0xa2, 0xc7, 0x2f, 0x15, - 0xf7, 0xac, 0xc0, 0x82, 0xef, 0xbc, 0x22, 0x92, 0x79, 0xf8, 0x40, 0x3a, 0x1c, 0x9c, 0xcd, 0x54, - 0x0e, 0x9b, 0x21, 0x18, 0xcb, 0xa3, 0xb4, 0xfe, 0xd2, 0x0d, 0x93, 0x45, 0x08, 0x1f, 0xe0, 0x7d, - 0xb8, 0x16, 0x3f, 0xdb, 0xa9, 0x5c, 0x3e, 0xe6, 0x39, 0x9a, 0x74, 0xfc, 0x53, 0xe1, 0x3e, 0x0d, - 0x4f, 0xb0, 0xc2, 0x02, 0xa9, 0x20, 0x0d, 0xd0, 0x93, 0x48, 0xe1, 0x7f, 0x91, 0xaf, 0x01, 0x47, - 0xa4, 0x02, 0xf3, 0x42, 0xb0, 0xf4, 0xdb, 0x1f, 0xd2, 0x40, 0xee, 0x52, 0x1a, 0x10, 0x09, 0xa1, - 0x32, 0x52, 0xaa, 0x45, 0x3c, 0x0f, 0x69, 0x65, 0x86, 0xb4, 0x52, 0x01, 0xbf, 0x80, 0xb5, 0xf9, - 0x7c, 0x95, 0x06, 0xf9, 0x87, 0x18, 0x4a, 0x41, 0xf5, 0xa4, 0xfc, 0x52, 0x54, 0x86, 0xe2, 0xfe, - 0xc1, 0xd1, 0x61, 0xab, 0xdd, 0xad, 0x6b, 0x1b, 0xff, 0xc8, 0x42, 0x76, 0xf7, 0x18, 0x6d, 0xc2, - 0x02, 0xbf, 0xe9, 0xbe, 0xe4, 0x87, 0x00, 0xfd, 0xb2, 0x3b, 0x73, 0x9c, 0x41, 0x5f, 0x40, 0xee, - 0x70, 0xea, 0xa3, 0xb9, 0xbf, 0x04, 0xe8, 0xf3, 0xef, 0xcb, 0x71, 0x06, 0xf5, 0xa0, 0xac, 0x5c, - 0x6c, 0xa3, 0xf7, 0xfe, 0x12, 0xa0, 0xbf, 0xff, 0xd2, 0x9c, 0xfb, 0xd4, 0x7b, 0x63, 0xc7, 0x7d, - 0x0a, 0x2f, 0x62, 0xe3, 0x3e, 0x29, 0x97, 0x9f, 0x38, 0x83, 0xf6, 0xc5, 0x85, 0xfa, 0xc0, 0x47, - 0xb7, 0x13, 0xee, 0x67, 0xd5, 0x9b, 0x48, 0x7d, 0x6d, 0xbe, 0x82, 0xc4, 0xdb, 0x38, 0x80, 0x05, - 0x76, 0x4b, 0x83, 0xbe, 0x92, 0x0f, 0x7a, 0xc2, 0x1d, 0xd6, 0x9c, 0x70, 0x47, 0xee, 0x77, 0x70, - 0x66, 0x5d, 0xfb, 0x4c, 0xdb, 0xf8, 0x2e, 0x0b, 0x0b, 0xac, 0x6b, 0x47, 0x4f, 0x01, 0xc2, 0xeb, - 0x8d, 0xb8, 0xb7, 0x33, 0x17, 0x26, 0x71, 0x6f, 0x67, 0x6f, 0x46, 0xf8, 0x8e, 0x28, 0xf7, 0x10, - 0x28, 0xc9, 0x24, 0x72, 0x91, 0x11, 0xdf, 0x91, 0x84, 0x4b, 0x0c, 0x9c, 0x41, 0x26, 0xd4, 0xa2, - 0xf7, 0x0c, 0xe8, 0x4e, 0x82, 0x59, 0xfc, 0xba, 0x42, 0xbf, 0x7b, 0xb9, 0x52, 0x24, 0x2a, 0x7f, - 0xcd, 0x42, 0xb1, 0xcd, 0x7f, 0xa8, 0x46, 0xfb, 0x50, 0x0a, 0x5a, 0x79, 0xb4, 0x9a, 0xd4, 0xe6, - 0x85, 0x35, 0x90, 0x7e, 0x7b, 0xee, 0xfb, 0xc0, 0xfd, 0xe7, 0x50, 0x51, 0x5b, 0x6f, 0xf4, 0x51, - 0x62, 0xe7, 0xa8, 0x76, 0xef, 0x3a, 0xbe, 0x4c, 0x65, 0x16, 0x98, 0xb7, 0xd0, 0xc9, 0xc0, 0x91, - 0x0e, 0x3d, 0x19, 0x38, 0xda, 0x81, 0xe3, 0x0c, 0xcd, 0x8c, 0xb0, 0x71, 0x46, 0x89, 0x4b, 0x54, - 0xfa, 0xec, 0x78, 0x66, 0xcc, 0xf6, 0xdc, 0x38, 0xb3, 0xf1, 0xef, 0x2c, 0x94, 0x9f, 0x98, 0x96, - 0xed, 0x13, 0xdb, 0xb4, 0x07, 0x84, 0xb2, 0x07, 0x23, 0x9a, 0x78, 0x3a, 0xab, 0x6d, 0x6a, 0x3c, - 0x9d, 0x23, 0x3d, 0x1c, 0xce, 0xa0, 0x2e, 0x14, 0x78, 0x2b, 0x85, 0x62, 0x8a, 0x91, 0x96, 0x4b, - 0xbf, 0x99, 0xfc, 0x52, 0x5d, 0x6d, 0xd8, 0x95, 0xc7, 0x57, 0x3b, 0xd3, 0xc4, 0xeb, 0x6b, 0xf3, - 0x15, 0x02, 0xc8, 0x9f, 0x41, 0x7e, 0xdb, 0xf4, 0xce, 0x50, 0x8c, 0x2a, 0x94, 0x3b, 0x7f, 0x5d, - 0x4f, 0x7a, 0x15, 0x00, 0x3c, 0x81, 0x45, 0x79, 0x47, 0x8f, 0x6e, 0xc5, 0xfc, 0x8f, 0xde, 0xe7, - 0xeb, 0xab, 0xf3, 0x5e, 0x4b, 0xb0, 0xcf, 0xb4, 0x8d, 0xdf, 0x03, 0xe4, 0xe9, 0x17, 0x83, 0xae, - 0x35, 0x2c, 0x50, 0xe3, 0x6b, 0x9d, 0xe9, 0xe5, 0xe2, 0x6b, 0x9d, 0xad, 0x6d, 0xf9, 0x99, 0x57, - 0xea, 0x54, 0x94, 0x60, 0x12, 0x6d, 0x05, 0xe3, 0x67, 0x3e, 0xa1, 0xc8, 0xe5, 0xb9, 0xad, 0x16, - 0xac, 0x28, 0xc1, 0x28, 0xd6, 0x4b, 0xc6, 0x73, 0x3b, 0xa9, 0xde, 0xc5, 0x19, 0x74, 0x08, 0x45, - 0x51, 0xa1, 0x26, 0xb9, 0x1a, 0x6d, 0x2c, 0x93, 0x5c, 0x8d, 0x95, 0xb7, 0x21, 0xe2, 0x16, 0xf1, - 0xe7, 0x21, 0x86, 0x9d, 0xd0, 0x3c, 0x44, 0xa5, 0xc8, 0xc1, 0x19, 0xf4, 0x0d, 0x40, 0x58, 0x95, - 0xc6, 0xc9, 0x2e, 0xb1, 0x1f, 0x8d, 0x93, 0x5d, 0x72, 0x61, 0x8b, 0x33, 0xe8, 0x5b, 0x40, 0xb3, - 0x05, 0x2a, 0xfa, 0x24, 0xd9, 0x3a, 0xb1, 0x8b, 0xd5, 0x1f, 0x7e, 0x98, 0x72, 0x30, 0x65, 0x1f, - 0xaa, 0x91, 0xda, 0x15, 0xdd, 0x9f, 0x13, 0x83, 0x58, 0x8b, 0xab, 0x3f, 0x78, 0xaf, 0x5e, 0x30, - 0x07, 0x81, 0x5a, 0xb4, 0x98, 0x45, 0x73, 0x8c, 0x67, 0x7a, 0x60, 0x7d, 0xfd, 0xfd, 0x8a, 0xea, - 0x56, 0x8b, 0xfa, 0x36, 0x69, 0xab, 0xa3, 0xed, 0x71, 0xd2, 0x56, 0xc7, 0x8a, 0xe3, 0x10, 0x71, - 0x4e, 0xf2, 0x44, 0xdb, 0xe8, 0x79, 0x88, 0x33, 0xc9, 0x13, 0x56, 0xb0, 0x49, 0xc9, 0x33, 0xd3, - 0x71, 0x27, 0x25, 0xcf, 0x6c, 0x11, 0x8c, 0x33, 0xc8, 0x87, 0xe5, 0x84, 0x62, 0x16, 0x3d, 0x9c, - 0xe3, 0x56, 0x62, 0xa3, 0xae, 0x7f, 0xfa, 0x81, 0xda, 0xc1, 0xac, 0xaf, 0x61, 0x25, 0xa9, 0xd2, - 0x45, 0x73, 0x80, 0xe6, 0x74, 0xf0, 0x7a, 0xf3, 0x43, 0xd5, 0xe5, 0xc4, 0x9b, 0x95, 0x3f, 0xbe, - 0x5b, 0xd5, 0xfe, 0xf2, 0x6e, 0x55, 0xfb, 0xdb, 0xbb, 0x55, 0xad, 0x5f, 0x60, 0xff, 0xed, 0xed, - 0x47, 0xff, 0x09, 0x00, 0x00, 0xff, 0xff, 0x7a, 0xd6, 0x18, 0xf9, 0x5f, 0x27, 0x00, 0x00, + // 2657 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xb4, 0x5a, 0x4b, 0x6f, 0x1b, 0xc9, + 0xf1, 0xd7, 0x90, 0x14, 0x29, 0x16, 0x1f, 0x96, 0x5b, 0xb2, 0xff, 0xf4, 0xec, 0xfa, 0xb1, 0xe3, + 0xe7, 0x3f, 0xeb, 0xa5, 0x63, 0x65, 0x93, 0x4b, 0x16, 0x1b, 0x50, 0x22, 0xd7, 0xd6, 0x4a, 0x96, + 0xec, 0x11, 0x2d, 0xef, 0x02, 0x01, 0x84, 0x21, 0xd9, 0x96, 0x08, 0xf3, 0xb5, 0x33, 0x43, 0xd9, + 0x32, 0x90, 0x4b, 0x80, 0x7c, 0x82, 0xcd, 0x25, 0xb9, 0xe6, 0x23, 0x04, 0xf9, 0x0e, 0x41, 0x2e, + 0xc9, 0x27, 0x08, 0x82, 0x9c, 0x82, 0x20, 0xf7, 0x1c, 0x72, 0x49, 0xf5, 0x6b, 0xa6, 0x67, 0x38, + 0x23, 0x7b, 0x33, 0xc9, 0xc1, 0xf6, 0x74, 0x75, 0xd5, 0xaf, 0xab, 0xab, 0xab, 0xab, 0xab, 0x8a, + 0x86, 0xb2, 0x3b, 0xeb, 0x37, 0x67, 0xee, 0xd4, 0x9f, 0x92, 0x2a, 0xf5, 0xfb, 0x03, 0x8f, 0xba, + 0xa7, 0xd4, 0x9d, 0xf5, 0xcc, 0xf5, 0xe3, 0xe9, 0xf1, 0x94, 0x4f, 0x3c, 0x60, 0x5f, 0x82, 0xc7, + 0xbc, 0xc2, 0x78, 0x1e, 0x8c, 0x4f, 0xfb, 0x7d, 0xfe, 0xd7, 0xac, 0xf7, 0xe0, 0xd5, 0xa9, 0x9c, + 0xfa, 0x80, 0x4f, 0x39, 0x73, 0xff, 0x84, 0xff, 0x85, 0x53, 0xec, 0x1f, 0x31, 0x69, 0xfd, 0xc2, + 0x80, 0xba, 0x4d, 0xbd, 0xd9, 0x74, 0xe2, 0xd1, 0xc7, 0xd4, 0x19, 0x50, 0x97, 0x5c, 0x05, 0xe8, + 0x8f, 0xe6, 0x9e, 0x4f, 0xdd, 0xa3, 0xe1, 0xa0, 0x61, 0xdc, 0x30, 0xee, 0x15, 0xec, 0xb2, 0xa4, + 0x6c, 0x0f, 0xc8, 0x07, 0x50, 0x1e, 0xd3, 0x71, 0x4f, 0xcc, 0xe6, 0xf8, 0xec, 0x8a, 0x20, 0xe0, + 0xa4, 0x09, 0x2b, 0x2e, 0x3d, 0x1d, 0x7a, 0xc3, 0xe9, 0xa4, 0x91, 0xc7, 0xb9, 0xbc, 0x1d, 0x8c, + 0x99, 0xa0, 0xeb, 0xbc, 0xf4, 0x8f, 0x10, 0x66, 0xdc, 0x28, 0x08, 0x41, 0x46, 0xe8, 0xe2, 0xd8, + 0xfa, 0x65, 0x1e, 0xaa, 0xb6, 0x33, 0x39, 0xa6, 0x36, 0xfd, 0x66, 0x4e, 0x3d, 0x9f, 0xac, 0x42, + 0xfe, 0x15, 0x3d, 0xe3, 0xcb, 0x57, 0x6d, 0xf6, 0x29, 0xe4, 0x91, 0xe3, 0x88, 0x4e, 0xc4, 0xc2, + 0x55, 0x26, 0x8f, 0x84, 0xce, 0x64, 0x40, 0xd6, 0x61, 0x79, 0x34, 0x1c, 0x0f, 0x7d, 0xb9, 0xaa, + 0x18, 0x44, 0xd4, 0x29, 0xc4, 0xd4, 0xd9, 0x02, 0xf0, 0xa6, 0xae, 0x7f, 0x34, 0x75, 0x71, 0xd3, + 0x8d, 0x65, 0x9c, 0xad, 0x6f, 0xdc, 0x6a, 0xea, 0xa6, 0x6e, 0xea, 0x0a, 0x35, 0x0f, 0x90, 0x79, + 0x9f, 0xf1, 0xda, 0x65, 0x4f, 0x7d, 0x92, 0x2f, 0xa0, 0xc2, 0x41, 0x7c, 0xc7, 0x3d, 0xa6, 0x7e, + 0xa3, 0xc8, 0x51, 0x6e, 0xbf, 0x03, 0xa5, 0xcb, 0x99, 0x6d, 0xbe, 0xbc, 0xf8, 0x26, 0x16, 0x54, + 0x91, 0x7f, 0xe8, 0x8c, 0x86, 0x6f, 0x9d, 0xde, 0x88, 0x36, 0x4a, 0x08, 0xb4, 0x62, 0x47, 0x68, + 0x56, 0x13, 0xca, 0x81, 0x0e, 0x64, 0x05, 0x0a, 0x7b, 0xfb, 0x7b, 0x9d, 0xd5, 0x25, 0x02, 0x50, + 0x6c, 0x1d, 0x6c, 0x75, 0xf6, 0xda, 0xab, 0x06, 0xa9, 0x40, 0xa9, 0xdd, 0x11, 0x83, 0x9c, 0xb5, + 0x09, 0x10, 0xae, 0x46, 0x4a, 0x90, 0xdf, 0xe9, 0x7c, 0x8d, 0xfc, 0xc8, 0x73, 0xd8, 0xb1, 0x0f, + 0xb6, 0xf7, 0xf7, 0x50, 0x00, 0x85, 0xb7, 0xec, 0x4e, 0xab, 0xdb, 0x59, 0xcd, 0x31, 0x8e, 0x27, + 0xfb, 0xed, 0xd5, 0x3c, 0x29, 0xc3, 0xf2, 0x61, 0x6b, 0xf7, 0x79, 0x67, 0xb5, 0x60, 0xfd, 0x0c, + 0x6a, 0x52, 0x7d, 0xe1, 0x22, 0xe4, 0x53, 0x28, 0x9e, 0x70, 0x37, 0xe1, 0x27, 0x53, 0xd9, 0xf8, + 0x30, 0xb6, 0xd7, 0x88, 0x2b, 0xd9, 0x92, 0x17, 0xb7, 0x97, 0x7f, 0x75, 0xea, 0xe1, 0xa1, 0xe5, + 0x51, 0x64, 0xb5, 0x29, 0x3c, 0xb4, 0xb9, 0x43, 0xcf, 0x0e, 0x9d, 0xd1, 0x9c, 0xda, 0x6c, 0x92, + 0x10, 0x28, 0x8c, 0xa7, 0x2e, 0xe5, 0x07, 0xb8, 0x62, 0xf3, 0x6f, 0xeb, 0x4b, 0x80, 0xa7, 0x73, + 0x3f, 0xdd, 0x25, 0xf0, 0xd4, 0x4f, 0x19, 0x82, 0x74, 0x07, 0x31, 0xe0, 0xbe, 0x40, 0x1d, 0x8f, + 0x06, 0xbe, 0xc0, 0x06, 0xd6, 0x16, 0x54, 0x38, 0x56, 0x96, 0x8d, 0x20, 0x08, 0x69, 0xd3, 0x11, + 0xf5, 0x69, 0x06, 0x5f, 0xb5, 0x28, 0xac, 0x45, 0x40, 0x32, 0x99, 0xb6, 0x01, 0xa5, 0x01, 0x07, + 0x13, 0xeb, 0xe4, 0x6d, 0x35, 0xb4, 0xfe, 0x61, 0x40, 0x59, 0x6a, 0xb8, 0x3f, 0x23, 0x2d, 0xa8, + 0xb9, 0x62, 0x70, 0xc4, 0x15, 0x91, 0x8b, 0x98, 0xe9, 0xbe, 0xfa, 0x78, 0xc9, 0xae, 0x4a, 0x11, + 0x4e, 0x26, 0x3f, 0x86, 0x8a, 0x82, 0x98, 0xcd, 0x7d, 0xbe, 0x5c, 0x65, 0xa3, 0x11, 0x05, 0x08, + 0x8f, 0x0b, 0xc5, 0x41, 0xb2, 0x23, 0x91, 0x74, 0x61, 0x5d, 0x09, 0x0b, 0x05, 0xa5, 0x1a, 0x79, + 0x8e, 0x72, 0x23, 0x8a, 0xb2, 0x68, 0x63, 0x44, 0x23, 0x52, 0x5e, 0x9b, 0xdc, 0x2c, 0x43, 0x49, + 0x52, 0xad, 0x7f, 0x1a, 0x00, 0xca, 0x46, 0xb8, 0xdf, 0x36, 0xd4, 0x5d, 0x39, 0x8a, 0x6c, 0xf8, + 0x83, 0xc4, 0x0d, 0x4b, 0xd3, 0x2e, 0xd9, 0x35, 0x25, 0x24, 0xb6, 0xfc, 0x39, 0x54, 0x03, 0x94, + 0x70, 0xcf, 0x57, 0x12, 0xf6, 0x1c, 0x20, 0x54, 0x94, 0x00, 0xdb, 0xf5, 0x0b, 0xb8, 0x14, 0xc8, + 0x27, 0x6c, 0xfb, 0xa3, 0x73, 0xb6, 0x1d, 0x00, 0xae, 0x29, 0x04, 0x7d, 0xe3, 0xc0, 0x22, 0x9b, + 0x20, 0x5b, 0xbf, 0xce, 0x43, 0x69, 0x6b, 0x3a, 0x9e, 0x39, 0x2e, 0x3b, 0xa3, 0x22, 0xd2, 0xe7, + 0x23, 0x9f, 0x6f, 0xb7, 0xbe, 0x71, 0x33, 0xba, 0x82, 0x64, 0x53, 0xff, 0xda, 0x9c, 0xd5, 0x96, + 0x22, 0x4c, 0x58, 0x06, 0xb2, 0xdc, 0x7b, 0x08, 0xcb, 0x30, 0x26, 0x45, 0xd4, 0x25, 0xc8, 0x87, + 0x97, 0xc0, 0x84, 0x12, 0x0a, 0x86, 0xc1, 0x17, 0xf7, 0xa2, 0x08, 0xe4, 0xff, 0xe1, 0x42, 0xdf, + 0xa5, 0x0e, 0xb3, 0x87, 0x0a, 0xd0, 0xcb, 0x92, 0xa7, 0x2e, 0x26, 0x6c, 0x15, 0xa8, 0x6f, 0x42, + 0x75, 0x3c, 0x1d, 0x84, 0x7c, 0x45, 0xc9, 0x57, 0x41, 0x6a, 0xc0, 0x74, 0x59, 0x45, 0x02, 0x16, + 0x39, 0xab, 0x38, 0x2b, 0x86, 0xd6, 0x43, 0xa8, 0x45, 0xf6, 0xca, 0x82, 0x5b, 0xe7, 0xd9, 0xf3, + 0xd6, 0xae, 0x88, 0x84, 0x8f, 0x78, 0xf0, 0xb3, 0x31, 0x12, 0x62, 0x40, 0xdd, 0xed, 0x1c, 0x1c, + 0x60, 0xdc, 0xfc, 0x2c, 0x10, 0x91, 0xa1, 0x53, 0x8b, 0x98, 0x4b, 0x5a, 0xc4, 0x34, 0x54, 0xc4, + 0xcc, 0x85, 0x11, 0x33, 0xbf, 0x59, 0x87, 0xaa, 0x30, 0xc8, 0xd1, 0x7c, 0x82, 0x8a, 0x59, 0xbf, + 0x41, 0xb7, 0xec, 0xbe, 0x99, 0xa8, 0x50, 0xf1, 0x00, 0x4a, 0x7d, 0x01, 0x8e, 0x07, 0xc4, 0xa2, + 0xe1, 0xa5, 0x44, 0x1b, 0xdb, 0x8a, 0x8b, 0x3c, 0x84, 0x92, 0x37, 0xef, 0xf7, 0xa9, 0xa7, 0xc2, + 0xe7, 0xff, 0xc5, 0xc3, 0x82, 0xbc, 0xe1, 0xb6, 0xe2, 0x63, 0x22, 0x2f, 0x9d, 0xe1, 0x68, 0xce, + 0x83, 0xe9, 0xf9, 0x22, 0x92, 0xcf, 0xfa, 0x95, 0x01, 0x15, 0xae, 0x65, 0xa6, 0x58, 0xf4, 0x21, + 0x94, 0xb9, 0x0e, 0x74, 0x20, 0xa3, 0xd1, 0x8a, 0x1d, 0x12, 0xc8, 0x8f, 0x30, 0x26, 0x4a, 0x39, + 0x4f, 0x2a, 0xd6, 0x48, 0x86, 0x45, 0xcd, 0x42, 0x56, 0x6b, 0x07, 0x2e, 0x72, 0xab, 0xf4, 0x7d, + 0xb4, 0xa7, 0xb2, 0xa3, 0xfe, 0xb2, 0x1b, 0xb1, 0x97, 0x1d, 0xe7, 0x66, 0x27, 0x67, 0xde, 0xb0, + 0xef, 0x8c, 0xa4, 0x16, 0xc1, 0x18, 0x5f, 0x14, 0xa2, 0x83, 0x65, 0x7a, 0x0c, 0x6a, 0x50, 0x79, + 0xec, 0x78, 0x27, 0x52, 0x25, 0xeb, 0x2b, 0xa8, 0x8a, 0x61, 0x26, 0x1b, 0xe2, 0x33, 0x78, 0x82, + 0x28, 0x5c, 0xf1, 0x9a, 0xcd, 0xbf, 0xad, 0x8b, 0x70, 0xe1, 0x60, 0xe2, 0xcc, 0xbc, 0x93, 0xa9, + 0x0a, 0xae, 0x2c, 0x6f, 0x5b, 0x0d, 0x69, 0x99, 0x56, 0xbc, 0x0b, 0x17, 0x5c, 0x3a, 0x76, 0x86, + 0x93, 0xe1, 0xe4, 0xf8, 0xa8, 0x77, 0xe6, 0x53, 0x4f, 0xa6, 0x75, 0xf5, 0x80, 0xbc, 0xc9, 0xa8, + 0x4c, 0xb5, 0xde, 0x68, 0xda, 0x93, 0x57, 0x9c, 0x7f, 0x5b, 0xbf, 0x33, 0xa0, 0xfa, 0xc2, 0xf1, + 0xfb, 0xca, 0x0a, 0x64, 0x1b, 0xea, 0xc1, 0xc5, 0xe6, 0x14, 0xa9, 0x4b, 0x2c, 0xc2, 0x73, 0x99, + 0x2d, 0x79, 0xd1, 0x55, 0x84, 0xaf, 0xf5, 0x75, 0x02, 0x87, 0x72, 0x26, 0x7d, 0x3a, 0x0a, 0xa0, + 0x72, 0xe9, 0x50, 0x9c, 0x51, 0x87, 0xd2, 0x09, 0x9b, 0x17, 0xc2, 0xd7, 0x4f, 0x5c, 0xcb, 0x6f, + 0x0d, 0x20, 0x8b, 0x3a, 0x7c, 0xd7, 0xac, 0xf3, 0x36, 0xd4, 0x3d, 0xbc, 0xed, 0xfe, 0x51, 0x2c, + 0xe9, 0xad, 0x71, 0x6a, 0x10, 0x9c, 0xd0, 0xc2, 0x98, 0x6d, 0x1f, 0xa3, 0x4b, 0x7b, 0x47, 0x93, + 0xa9, 0x3f, 0x7c, 0x79, 0xc6, 0x03, 0xe2, 0x8a, 0x5d, 0x57, 0xe4, 0x3d, 0x4e, 0xb5, 0x1e, 0x28, + 0xa5, 0x74, 0xe5, 0xc9, 0x15, 0x58, 0x79, 0xcd, 0xa8, 0x2a, 0x1d, 0xc7, 0x37, 0x9e, 0x8f, 0xb7, + 0x07, 0xd6, 0xdf, 0x0c, 0xa8, 0x49, 0xf3, 0x67, 0xf2, 0x01, 0x7d, 0x89, 0x5c, 0x64, 0x09, 0x96, + 0x60, 0x88, 0x63, 0x19, 0xc8, 0xd4, 0x4c, 0x0d, 0xd9, 0x3d, 0x13, 0x56, 0xc6, 0x29, 0xb1, 0x9f, + 0x60, 0x8c, 0xf1, 0x7d, 0xb5, 0x2f, 0xee, 0x59, 0x2c, 0xc0, 0xdb, 0x17, 0x24, 0x3d, 0xb0, 0xce, + 0x6d, 0x28, 0xd2, 0x53, 0x3a, 0xf1, 0xbd, 0x46, 0x85, 0x07, 0x85, 0x9a, 0xca, 0x0f, 0x3b, 0x8c, + 0x6a, 0xcb, 0x49, 0xeb, 0x87, 0x70, 0x71, 0x97, 0x25, 0x72, 0x8f, 0xd0, 0xfa, 0x7a, 0x4a, 0xd8, + 0xed, 0xee, 0x4a, 0xab, 0xe4, 0xfd, 0xee, 0x2e, 0xa9, 0x43, 0x6e, 0xbb, 0x2d, 0xf7, 0x90, 0x1b, + 0xb6, 0xad, 0x9f, 0xe3, 0x41, 0xeb, 0x72, 0x99, 0xcc, 0x14, 0x03, 0x57, 0xcb, 0xe7, 0xc3, 0xe5, + 0x31, 0xf7, 0xa4, 0xae, 0x3b, 0x75, 0xb9, 0x41, 0xca, 0xb6, 0x18, 0x58, 0xb7, 0xa4, 0x0e, 0xb8, + 0xe7, 0xe9, 0xab, 0xc0, 0xd9, 0x04, 0x9a, 0x11, 0xa8, 0xba, 0x03, 0x6b, 0x11, 0xae, 0x4c, 0xc1, + 0xe9, 0x2e, 0x5c, 0xe2, 0x60, 0x3b, 0x94, 0xce, 0x5a, 0xa3, 0xe1, 0x69, 0xea, 0xaa, 0x33, 0xb8, + 0x1c, 0x67, 0xfc, 0xdf, 0xda, 0xc8, 0x3a, 0x81, 0xe2, 0x13, 0x5e, 0x30, 0x6a, 0xba, 0x14, 0x38, + 0x2f, 0x46, 0x98, 0x89, 0x33, 0x16, 0xe9, 0x7c, 0xd9, 0xe6, 0xdf, 0x3c, 0x9a, 0x53, 0xea, 0x3e, + 0xb7, 0x77, 0xc5, 0xab, 0x51, 0xb6, 0x83, 0x31, 0xb9, 0xc6, 0x4a, 0xd5, 0x21, 0xba, 0x07, 0x9f, + 0x2d, 0xf0, 0x59, 0x8d, 0x82, 0x25, 0xd3, 0xaa, 0x58, 0xa9, 0x35, 0x18, 0x68, 0x2f, 0x47, 0x80, + 0x67, 0x44, 0xf1, 0xac, 0xd7, 0x70, 0x51, 0xe3, 0xcf, 0x64, 0x86, 0xfb, 0x50, 0x14, 0x55, 0xb1, + 0x0c, 0x5a, 0xeb, 0x51, 0x29, 0xb1, 0x8c, 0x2d, 0x79, 0xac, 0xdb, 0xb0, 0x26, 0x29, 0x74, 0x3c, + 0x4d, 0x3a, 0x2b, 0x6e, 0x1f, 0x6b, 0x17, 0xd6, 0xa3, 0x6c, 0x99, 0x5c, 0xa4, 0xa5, 0x16, 0x7d, + 0x3e, 0x1b, 0x68, 0x31, 0x30, 0x7e, 0x28, 0xba, 0xc1, 0x72, 0x31, 0x83, 0x05, 0x0a, 0x29, 0x88, + 0x4c, 0x0a, 0xad, 0x29, 0xf3, 0xef, 0x0e, 0xbd, 0xe0, 0xa5, 0x7b, 0x0b, 0x44, 0x27, 0x66, 0x3a, + 0x94, 0x26, 0x94, 0x84, 0xc1, 0x55, 0x32, 0x95, 0x7c, 0x2a, 0x8a, 0x89, 0x29, 0xd4, 0xa6, 0x2f, + 0x5d, 0xe7, 0x78, 0x4c, 0x83, 0x98, 0xc3, 0x52, 0x08, 0x9d, 0x98, 0x69, 0xc7, 0x7f, 0xc4, 0xe7, + 0xb3, 0x35, 0x72, 0xdc, 0xb1, 0x32, 0xfe, 0xe7, 0x50, 0x14, 0xb9, 0x89, 0xcc, 0xdf, 0xef, 0x44, + 0x61, 0x74, 0x5e, 0x31, 0x68, 0x89, 0x4c, 0x46, 0x4a, 0xb1, 0xc3, 0x92, 0xcd, 0x98, 0x76, 0xac, + 0x39, 0xd3, 0x26, 0x9f, 0xc0, 0xb2, 0xc3, 0x44, 0xf8, 0x5d, 0xac, 0xc7, 0xb3, 0x42, 0x8e, 0xd6, + 0x3d, 0x9b, 0x51, 0x5b, 0x70, 0x59, 0x9f, 0x42, 0x45, 0x5b, 0x81, 0x25, 0xbb, 0x8f, 0x3a, 0x5d, + 0xcc, 0x80, 0xab, 0xb0, 0xd2, 0xda, 0xea, 0x6e, 0x1f, 0x8a, 0x1c, 0xb8, 0x0e, 0xd0, 0xee, 0x04, + 0xe3, 0x1c, 0x66, 0x41, 0x42, 0x4a, 0xde, 0x70, 0x5d, 0x1f, 0x23, 0x4d, 0x9f, 0xdc, 0x7b, 0xe9, + 0xf3, 0x06, 0x6a, 0x72, 0xfb, 0x99, 0x7c, 0xe0, 0x21, 0x5a, 0x98, 0xc1, 0x28, 0x17, 0xb8, 0x92, + 0xb0, 0xac, 0xba, 0x9d, 0x82, 0xd1, 0xc2, 0xec, 0xe1, 0xc0, 0x77, 0xfc, 0xb9, 0xa7, 0x5c, 0xe0, + 0x0f, 0x06, 0xd4, 0x15, 0x25, 0x6b, 0xf5, 0xae, 0x4a, 0x24, 0x11, 0xf3, 0x82, 0x02, 0xe9, 0x32, + 0x14, 0x07, 0xbd, 0x83, 0xe1, 0x5b, 0xd5, 0xc5, 0x90, 0x23, 0x46, 0x1f, 0x89, 0x75, 0x44, 0x0b, + 0x4d, 0x8e, 0x58, 0xee, 0xcd, 0x9a, 0x69, 0xdb, 0x93, 0x01, 0x7d, 0xc3, 0x5f, 0xda, 0x82, 0x1d, + 0x12, 0x78, 0xba, 0x2c, 0x5b, 0x6d, 0xbc, 0x7e, 0xd2, 0x5b, 0x6f, 0xe8, 0xe4, 0xad, 0xb9, 0x7f, + 0xd2, 0x99, 0xb0, 0x2e, 0x93, 0xda, 0xe1, 0x3a, 0x10, 0x46, 0x6c, 0x0f, 0x3d, 0x9d, 0xda, 0x81, + 0x35, 0x46, 0x45, 0xbf, 0xc7, 0x64, 0x3a, 0x8c, 0x18, 0x2a, 0x6c, 0x1b, 0xb1, 0xb0, 0xed, 0x78, + 0xde, 0xeb, 0xa9, 0x3b, 0x90, 0x5b, 0x0b, 0xc6, 0x56, 0x5b, 0x80, 0x3f, 0xf7, 0x22, 0x81, 0xf9, + 0xbb, 0xa2, 0xdc, 0x0b, 0x51, 0x1e, 0x51, 0xff, 0x1c, 0x14, 0xeb, 0x63, 0xb8, 0xa4, 0x38, 0x65, + 0x0d, 0x7d, 0x0e, 0xf3, 0x3e, 0x5c, 0x55, 0xcc, 0x5b, 0x27, 0x2c, 0xd1, 0x7b, 0x2a, 0x17, 0xfc, + 0x4f, 0xf5, 0xdc, 0x84, 0x46, 0xa0, 0x27, 0xcf, 0x41, 0xa6, 0x23, 0x5d, 0x81, 0xb9, 0x27, 0x7d, + 0x06, 0xb1, 0xd8, 0x37, 0xa3, 0xb9, 0xc8, 0xa2, 0x1e, 0x41, 0xf6, 0x6d, 0x6d, 0xc1, 0x15, 0x85, + 0x21, 0xb3, 0x83, 0x28, 0xc8, 0x82, 0x42, 0x49, 0x20, 0xd2, 0x60, 0x4c, 0xf4, 0x7c, 0xb3, 0xeb, + 0x9c, 0x51, 0xd3, 0x72, 0x4c, 0x43, 0xc3, 0x94, 0xa6, 0x65, 0x9c, 0x0b, 0xa6, 0x5d, 0x60, 0xfe, + 0x29, 0x5c, 0x0b, 0x60, 0x99, 0x25, 0x9e, 0xa2, 0xfb, 0x0d, 0x3d, 0x4f, 0x2b, 0xeb, 0x92, 0xb6, + 0x72, 0x07, 0x0a, 0x33, 0x2a, 0xa3, 0x44, 0x65, 0x83, 0x34, 0x45, 0x13, 0xbb, 0xa9, 0x09, 0xf3, + 0x79, 0x6b, 0x00, 0xd7, 0x15, 0xba, 0xb0, 0x51, 0x22, 0x7c, 0x5c, 0x29, 0x95, 0xf2, 0x0b, 0x43, + 0x2d, 0xa6, 0xfc, 0x79, 0x71, 0x9a, 0x41, 0xf3, 0xee, 0x4b, 0x61, 0x1a, 0x75, 0x5b, 0x32, 0x45, + 0xff, 0x1d, 0x71, 0x9d, 0x82, 0x4b, 0x96, 0x09, 0xac, 0x07, 0xeb, 0xd1, 0xbb, 0x99, 0x29, 0x30, + 0x61, 0x1e, 0xeb, 0xa3, 0x09, 0x55, 0x58, 0x12, 0x03, 0xa5, 0x70, 0x70, 0x71, 0x33, 0x29, 0xec, + 0x84, 0x60, 0xdc, 0xc9, 0xb2, 0xea, 0xcb, 0x4e, 0x53, 0x65, 0x28, 0x62, 0x60, 0xed, 0xc1, 0xe5, + 0xf8, 0xc5, 0xcf, 0xa4, 0xf2, 0xa1, 0x70, 0xe0, 0xa4, 0xd8, 0x90, 0x09, 0xf7, 0x59, 0x78, 0xbd, + 0xb5, 0x10, 0x91, 0x09, 0xd2, 0x06, 0x33, 0x29, 0x62, 0xfc, 0x37, 0xfc, 0x35, 0x08, 0x20, 0x99, + 0xc0, 0xbc, 0x10, 0x2c, 0xfb, 0xf1, 0x87, 0x31, 0x22, 0x7f, 0x6e, 0x8c, 0x90, 0x0e, 0xa1, 0x87, + 0xab, 0x4c, 0x9b, 0x78, 0x11, 0xc6, 0x9c, 0x85, 0x88, 0x96, 0x09, 0xf8, 0x2b, 0xb8, 0x91, 0x1e, + 0xcc, 0xb2, 0x20, 0x7f, 0xcf, 0x82, 0x72, 0x90, 0x5a, 0x69, 0x3f, 0x23, 0x55, 0xa0, 0xb4, 0xb7, + 0x7f, 0xf0, 0xb4, 0xb5, 0x85, 0x49, 0xdd, 0xc6, 0xdf, 0x73, 0x90, 0xdb, 0x39, 0x24, 0x9b, 0xb0, + 0x2c, 0xda, 0xe0, 0xe7, 0xfc, 0x4a, 0x60, 0x9e, 0xd7, 0x50, 0xb7, 0x96, 0xc8, 0x67, 0x90, 0x67, + 0x8d, 0xf0, 0xd4, 0x9f, 0x09, 0xcc, 0xf4, 0x66, 0x3a, 0x4a, 0x77, 0xa1, 0xa2, 0x75, 0xbd, 0xc9, + 0x3b, 0x7f, 0x26, 0x30, 0xdf, 0xdd, 0x51, 0x17, 0x3a, 0x75, 0xdf, 0x4c, 0xe2, 0x3a, 0x85, 0x5d, + 0xda, 0xb8, 0x4e, 0x5a, 0x67, 0x14, 0xa5, 0xf7, 0x64, 0xb7, 0xbd, 0xef, 0x93, 0xeb, 0x09, 0xcd, + 0x5b, 0xbd, 0x4d, 0x69, 0xde, 0x48, 0x67, 0x50, 0x78, 0x1b, 0xfb, 0xb0, 0xcc, 0x5b, 0x38, 0xe4, + 0x0b, 0xf5, 0x61, 0x26, 0x34, 0xb8, 0x52, 0xcc, 0x1d, 0x69, 0xfe, 0x58, 0x4b, 0xf7, 0x8c, 0xef, + 0x1b, 0x1b, 0xdf, 0xe6, 0x60, 0x99, 0x97, 0xf4, 0xe4, 0x19, 0x40, 0xd8, 0xfb, 0x88, 0x6b, 0xbb, + 0xd0, 0x4d, 0x89, 0x6b, 0xbb, 0xd8, 0x36, 0x11, 0x27, 0xa2, 0x35, 0x29, 0x48, 0x92, 0x48, 0xa4, + 0xcb, 0x11, 0x3f, 0x91, 0x84, 0x0e, 0x07, 0xa2, 0x3a, 0x50, 0x8f, 0x36, 0x21, 0xc8, 0xcd, 0x04, + 0xb1, 0x78, 0x2f, 0xc3, 0xbc, 0x75, 0x3e, 0x53, 0xc4, 0x2a, 0x7f, 0xce, 0xe1, 0xb9, 0x89, 0x5f, + 0xb1, 0xf1, 0x08, 0xcb, 0x41, 0x9d, 0x4f, 0xae, 0x25, 0xd5, 0x80, 0x61, 0x82, 0x64, 0x5e, 0x4f, + 0x9d, 0x0f, 0xd4, 0x7f, 0x01, 0x55, 0xbd, 0x2e, 0x27, 0x1f, 0x25, 0x96, 0x95, 0x7a, 0x69, 0x6f, + 0x5a, 0xe7, 0xb1, 0x2c, 0x02, 0x8b, 0xfa, 0x3a, 0x19, 0x38, 0x52, 0xbe, 0x27, 0x03, 0x47, 0xcb, + 0x73, 0x04, 0x46, 0xcf, 0x08, 0xab, 0x6a, 0x92, 0xb8, 0x45, 0xad, 0x08, 0x8f, 0x7b, 0xc6, 0x62, + 0x41, 0x8e, 0x7e, 0xfc, 0xaf, 0x1c, 0x54, 0x9e, 0x38, 0xc3, 0x89, 0x4f, 0x27, 0xac, 0x0b, 0xc8, + 0xa2, 0x07, 0x0f, 0x34, 0x71, 0x77, 0xd6, 0x6b, 0xd8, 0xb8, 0x3b, 0x47, 0x0a, 0x3c, 0x54, 0xb3, + 0x03, 0x45, 0x51, 0x67, 0x91, 0x18, 0x63, 0xa4, 0x1e, 0x33, 0x3f, 0x4c, 0x9e, 0xd4, 0x77, 0x1b, + 0x96, 0xec, 0xf1, 0xdd, 0x2e, 0x54, 0xf8, 0xe6, 0x8d, 0x74, 0x86, 0x00, 0xf2, 0x27, 0x50, 0x60, + 0xdd, 0x7e, 0x12, 0x0b, 0x15, 0xda, 0x0f, 0x02, 0xa6, 0x99, 0x34, 0x15, 0x00, 0x3c, 0x81, 0x15, + 0xd5, 0xc0, 0x27, 0x57, 0x63, 0xfa, 0x47, 0x9b, 0xfd, 0xe6, 0xb5, 0xb4, 0x69, 0x05, 0x86, 0xee, + 0xfd, 0x5b, 0x80, 0x02, 0x7b, 0x31, 0xd8, 0x5e, 0xc3, 0x04, 0x35, 0xbe, 0xd7, 0x85, 0x42, 0x2f, + 0xbe, 0xd7, 0xc5, 0xdc, 0x56, 0xdc, 0x79, 0x2d, 0x4f, 0x25, 0x09, 0x22, 0xd1, 0x3a, 0x31, 0x7e, + 0xe7, 0x13, 0x92, 0x5c, 0xe1, 0xdb, 0x7a, 0xc2, 0x4a, 0x12, 0x84, 0x62, 0x85, 0x66, 0xdc, 0xb7, + 0x93, 0xf2, 0x5d, 0x04, 0x7e, 0x0a, 0x25, 0x99, 0xa1, 0x26, 0xa9, 0x1a, 0xad, 0x3a, 0x93, 0x54, + 0x8d, 0xa5, 0xb7, 0x21, 0x22, 0xe6, 0x29, 0x69, 0x88, 0x61, 0x99, 0x94, 0x86, 0xa8, 0x25, 0x39, + 0x88, 0xf8, 0x35, 0x40, 0x98, 0x95, 0xc6, 0x83, 0x5d, 0x62, 0xb1, 0x1a, 0x0f, 0x76, 0xc9, 0x89, + 0x2d, 0x42, 0x7f, 0x03, 0x64, 0x31, 0x41, 0x25, 0x1f, 0x27, 0x4b, 0x27, 0x96, 0xb8, 0xe6, 0xfd, + 0xf7, 0x63, 0x0e, 0x96, 0xec, 0x41, 0x2d, 0x92, 0xbb, 0x92, 0x3b, 0x29, 0x36, 0x88, 0xd5, 0xbf, + 0xe6, 0xdd, 0x77, 0xf2, 0x05, 0x6b, 0x50, 0xa8, 0x47, 0x93, 0x59, 0x92, 0x22, 0xbc, 0x50, 0x20, + 0x9b, 0xf7, 0xde, 0xcd, 0xa8, 0x1f, 0xb5, 0xcc, 0x6f, 0x93, 0x8e, 0x3a, 0x5a, 0x3b, 0x27, 0x1d, + 0x75, 0x2c, 0x39, 0x0e, 0x11, 0x53, 0x9c, 0x27, 0x5a, 0x63, 0xa7, 0x21, 0x2e, 0x38, 0x4f, 0x98, + 0xc1, 0x26, 0x39, 0xcf, 0x42, 0x39, 0x9e, 0xe4, 0x3c, 0x8b, 0x49, 0x30, 0x42, 0xfb, 0xb0, 0x96, + 0x90, 0xcc, 0x92, 0xfb, 0x29, 0x6a, 0x25, 0x56, 0xf1, 0xe6, 0x27, 0xef, 0xc9, 0x1d, 0xac, 0xfa, + 0x1a, 0xd6, 0x93, 0x32, 0x5d, 0x92, 0x02, 0x94, 0x52, 0xde, 0x9b, 0xcd, 0xf7, 0x65, 0x57, 0x0b, + 0x6f, 0x56, 0x7f, 0xff, 0xd7, 0x6b, 0xc6, 0x9f, 0xf0, 0xcf, 0x5f, 0xf0, 0x4f, 0xaf, 0xc8, 0xff, + 0x4f, 0xdc, 0x0f, 0xfe, 0x1d, 0x00, 0x00, 0xff, 0xff, 0xf4, 0x4d, 0x3d, 0xa0, 0x7c, 0x27, 0x00, + 0x00, } diff --git a/etcdserver/etcdserverpb/rpc.proto b/etcdserver/etcdserverpb/rpc.proto index 15962522a..361228510 100644 --- a/etcdserver/etcdserverpb/rpc.proto +++ b/etcdserver/etcdserverpb/rpc.proto @@ -622,6 +622,7 @@ message AuthRoleGrantPermissionRequest { message AuthRoleRevokePermissionRequest { string role = 1; string key = 2; + string range_end = 3; } message AuthEnableResponse {