1package plugin
2
3import (
4	"context"
5	"encoding/json"
6	"errors"
7	"fmt"
8	"time"
9
10	"github.com/hashicorp/vault/sdk/helper/consts"
11	"github.com/hashicorp/vault/sdk/helper/license"
12	"github.com/hashicorp/vault/sdk/helper/pluginutil"
13	"github.com/hashicorp/vault/sdk/helper/wrapping"
14	"github.com/hashicorp/vault/sdk/logical"
15	"github.com/hashicorp/vault/sdk/plugin/pb"
16	"google.golang.org/grpc"
17)
18
19func newGRPCSystemView(conn *grpc.ClientConn) *gRPCSystemViewClient {
20	return &gRPCSystemViewClient{
21		client: pb.NewSystemViewClient(conn),
22	}
23}
24
25type gRPCSystemViewClient struct {
26	client pb.SystemViewClient
27}
28
29func (s *gRPCSystemViewClient) DefaultLeaseTTL() time.Duration {
30	reply, err := s.client.DefaultLeaseTTL(context.Background(), &pb.Empty{})
31	if err != nil {
32		return 0
33	}
34
35	return time.Duration(reply.TTL)
36}
37
38func (s *gRPCSystemViewClient) MaxLeaseTTL() time.Duration {
39	reply, err := s.client.MaxLeaseTTL(context.Background(), &pb.Empty{})
40	if err != nil {
41		return 0
42	}
43
44	return time.Duration(reply.TTL)
45}
46
47func (s *gRPCSystemViewClient) SudoPrivilege(ctx context.Context, path string, token string) bool {
48	reply, err := s.client.SudoPrivilege(ctx, &pb.SudoPrivilegeArgs{
49		Path:  path,
50		Token: token,
51	})
52	if err != nil {
53		return false
54	}
55
56	return reply.Sudo
57}
58
59func (s *gRPCSystemViewClient) Tainted() bool {
60	reply, err := s.client.Tainted(context.Background(), &pb.Empty{})
61	if err != nil {
62		return false
63	}
64
65	return reply.Tainted
66}
67
68func (s *gRPCSystemViewClient) CachingDisabled() bool {
69	reply, err := s.client.CachingDisabled(context.Background(), &pb.Empty{})
70	if err != nil {
71		return false
72	}
73
74	return reply.Disabled
75}
76
77func (s *gRPCSystemViewClient) ReplicationState() consts.ReplicationState {
78	reply, err := s.client.ReplicationState(context.Background(), &pb.Empty{})
79	if err != nil {
80		return consts.ReplicationUnknown
81	}
82
83	return consts.ReplicationState(reply.State)
84}
85
86func (s *gRPCSystemViewClient) ResponseWrapData(ctx context.Context, data map[string]interface{}, ttl time.Duration, jwt bool) (*wrapping.ResponseWrapInfo, error) {
87	buf, err := json.Marshal(data)
88	if err != nil {
89		return nil, err
90	}
91
92	reply, err := s.client.ResponseWrapData(ctx, &pb.ResponseWrapDataArgs{
93		Data: string(buf[:]),
94		TTL:  int64(ttl),
95		JWT:  false,
96	})
97	if err != nil {
98		return nil, err
99	}
100	if reply.Err != "" {
101		return nil, errors.New(reply.Err)
102	}
103
104	info, err := pb.ProtoResponseWrapInfoToLogicalResponseWrapInfo(reply.WrapInfo)
105	if err != nil {
106		return nil, err
107	}
108
109	return info, nil
110}
111
112func (s *gRPCSystemViewClient) LookupPlugin(_ context.Context, _ string, _ consts.PluginType) (*pluginutil.PluginRunner, error) {
113	return nil, fmt.Errorf("cannot call LookupPlugin from a plugin backend")
114}
115
116func (s *gRPCSystemViewClient) MlockEnabled() bool {
117	reply, err := s.client.MlockEnabled(context.Background(), &pb.Empty{})
118	if err != nil {
119		return false
120	}
121
122	return reply.Enabled
123}
124
125func (s *gRPCSystemViewClient) HasFeature(feature license.Features) bool {
126	// Not implemented
127	return false
128}
129
130func (s *gRPCSystemViewClient) LocalMount() bool {
131	reply, err := s.client.LocalMount(context.Background(), &pb.Empty{})
132	if err != nil {
133		return false
134	}
135
136	return reply.Local
137}
138
139func (s *gRPCSystemViewClient) EntityInfo(entityID string) (*logical.Entity, error) {
140	reply, err := s.client.EntityInfo(context.Background(), &pb.EntityInfoArgs{
141		EntityID: entityID,
142	})
143	if err != nil {
144		return nil, err
145	}
146	if reply.Err != "" {
147		return nil, errors.New(reply.Err)
148	}
149
150	return reply.Entity, nil
151}
152
153func (s *gRPCSystemViewClient) PluginEnv(ctx context.Context) (*logical.PluginEnvironment, error) {
154	reply, err := s.client.PluginEnv(ctx, &pb.Empty{})
155	if err != nil {
156		return nil, err
157	}
158
159	return reply.PluginEnvironment, nil
160}
161
162type gRPCSystemViewServer struct {
163	impl logical.SystemView
164}
165
166func (s *gRPCSystemViewServer) DefaultLeaseTTL(ctx context.Context, _ *pb.Empty) (*pb.TTLReply, error) {
167	ttl := s.impl.DefaultLeaseTTL()
168	return &pb.TTLReply{
169		TTL: int64(ttl),
170	}, nil
171}
172
173func (s *gRPCSystemViewServer) MaxLeaseTTL(ctx context.Context, _ *pb.Empty) (*pb.TTLReply, error) {
174	ttl := s.impl.MaxLeaseTTL()
175	return &pb.TTLReply{
176		TTL: int64(ttl),
177	}, nil
178}
179
180func (s *gRPCSystemViewServer) SudoPrivilege(ctx context.Context, args *pb.SudoPrivilegeArgs) (*pb.SudoPrivilegeReply, error) {
181	sudo := s.impl.SudoPrivilege(ctx, args.Path, args.Token)
182	return &pb.SudoPrivilegeReply{
183		Sudo: sudo,
184	}, nil
185}
186
187func (s *gRPCSystemViewServer) Tainted(ctx context.Context, _ *pb.Empty) (*pb.TaintedReply, error) {
188	tainted := s.impl.Tainted()
189	return &pb.TaintedReply{
190		Tainted: tainted,
191	}, nil
192}
193
194func (s *gRPCSystemViewServer) CachingDisabled(ctx context.Context, _ *pb.Empty) (*pb.CachingDisabledReply, error) {
195	cachingDisabled := s.impl.CachingDisabled()
196	return &pb.CachingDisabledReply{
197		Disabled: cachingDisabled,
198	}, nil
199}
200
201func (s *gRPCSystemViewServer) ReplicationState(ctx context.Context, _ *pb.Empty) (*pb.ReplicationStateReply, error) {
202	replicationState := s.impl.ReplicationState()
203	return &pb.ReplicationStateReply{
204		State: int32(replicationState),
205	}, nil
206}
207
208func (s *gRPCSystemViewServer) ResponseWrapData(ctx context.Context, args *pb.ResponseWrapDataArgs) (*pb.ResponseWrapDataReply, error) {
209	data := map[string]interface{}{}
210	err := json.Unmarshal([]byte(args.Data), &data)
211	if err != nil {
212		return &pb.ResponseWrapDataReply{}, err
213	}
214
215	// Do not allow JWTs to be returned
216	info, err := s.impl.ResponseWrapData(ctx, data, time.Duration(args.TTL), false)
217	if err != nil {
218		return &pb.ResponseWrapDataReply{
219			Err: pb.ErrToString(err),
220		}, nil
221	}
222
223	pbInfo, err := pb.LogicalResponseWrapInfoToProtoResponseWrapInfo(info)
224	if err != nil {
225		return &pb.ResponseWrapDataReply{}, err
226	}
227
228	return &pb.ResponseWrapDataReply{
229		WrapInfo: pbInfo,
230	}, nil
231}
232
233func (s *gRPCSystemViewServer) MlockEnabled(ctx context.Context, _ *pb.Empty) (*pb.MlockEnabledReply, error) {
234	enabled := s.impl.MlockEnabled()
235	return &pb.MlockEnabledReply{
236		Enabled: enabled,
237	}, nil
238}
239
240func (s *gRPCSystemViewServer) LocalMount(ctx context.Context, _ *pb.Empty) (*pb.LocalMountReply, error) {
241	local := s.impl.LocalMount()
242	return &pb.LocalMountReply{
243		Local: local,
244	}, nil
245}
246
247func (s *gRPCSystemViewServer) EntityInfo(ctx context.Context, args *pb.EntityInfoArgs) (*pb.EntityInfoReply, error) {
248	entity, err := s.impl.EntityInfo(args.EntityID)
249	if err != nil {
250		return &pb.EntityInfoReply{
251			Err: pb.ErrToString(err),
252		}, nil
253	}
254	return &pb.EntityInfoReply{
255		Entity: entity,
256	}, nil
257}
258
259func (s *gRPCSystemViewServer) PluginEnv(ctx context.Context, _ *pb.Empty) (*pb.PluginEnvReply, error) {
260	pluginEnv, err := s.impl.PluginEnv(ctx)
261	if err != nil {
262		return &pb.PluginEnvReply{
263			Err: pb.ErrToString(err),
264		}, nil
265	}
266	return &pb.PluginEnvReply{
267		PluginEnvironment: pluginEnv,
268	}, nil
269}
270