summaryrefslogtreecommitdiffstats
path: root/src/mds/MDSAuthCaps.h
blob: bbb2589b3a8d719a41f6efb87f001a024788dfce (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- 
// vim: ts=8 sw=2 smarttab
/*
 * Ceph - scalable distributed file system
 *
 * Copyright (C) 2014 Red Hat
 *
 * This is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1, as published by the Free Software 
 * Foundation.  See file COPYING.
 * 
 */
#ifndef MDS_AUTH_CAPS_H
#define MDS_AUTH_CAPS_H

#include <ostream>
#include <string>
#include <string_view>
#include <vector>

#include "include/encoding.h"
#include "include/common_fwd.h"
#include "include/types.h"
#include "common/debug.h"

#include "mdstypes.h"

// unix-style capabilities
enum {
  MAY_READ	= (1 << 0),
  MAY_WRITE 	= (1 << 1),
  MAY_EXECUTE	= (1 << 2),
  MAY_CHOWN	= (1 << 4),
  MAY_CHGRP	= (1 << 5),
  MAY_SET_VXATTR = (1 << 6),
  MAY_SNAPSHOT	= (1 << 7),
  MAY_FULL	= (1 << 8),
};

// what we can do
struct MDSCapSpec {
  static const unsigned ALL		= (1 << 0);
  static const unsigned READ		= (1 << 1);
  static const unsigned WRITE		= (1 << 2);
  // if the capability permits setting vxattrs (layout, quota, etc)
  static const unsigned SET_VXATTR	= (1 << 3);
  // if the capability permits mksnap/rmsnap
  static const unsigned SNAPSHOT	= (1 << 4);
  // if the capability permits to bypass osd full check
  static const unsigned FULL	        = (1 << 5);

  static const unsigned RW		= (READ|WRITE);
  static const unsigned RWF		= (READ|WRITE|FULL);
  static const unsigned RWP		= (READ|WRITE|SET_VXATTR);
  static const unsigned RWS		= (READ|WRITE|SNAPSHOT);
  static const unsigned RWFP		= (READ|WRITE|FULL|SET_VXATTR);
  static const unsigned RWFS		= (READ|WRITE|FULL|SNAPSHOT);
  static const unsigned RWPS		= (READ|WRITE|SET_VXATTR|SNAPSHOT);
  static const unsigned RWFPS		= (READ|WRITE|FULL|SET_VXATTR|SNAPSHOT);

  MDSCapSpec() = default;
  MDSCapSpec(unsigned _caps) : caps(_caps) {
    if (caps & ALL)
      caps |= RWFPS;
  }

  bool allow_all() const {
    return (caps & ALL);
  }
  bool allow_read() const {
    return (caps & READ);
  }
  bool allow_write() const {
    return (caps & WRITE);
  }

  bool allows(bool r, bool w) const {
    if (allow_all())
      return true;
    if (r && !allow_read())
      return false;
    if (w && !allow_write())
      return false;
    return true;
  }

  bool allow_snapshot() const {
    return (caps & SNAPSHOT);
  }
  bool allow_set_vxattr() const {
    return (caps & SET_VXATTR);
  }
  bool allow_full() const {
    return (caps & FULL);
  }
private:
  unsigned caps = 0;
};

// conditions before we are allowed to do it
struct MDSCapMatch {
  static const int64_t MDS_AUTH_UID_ANY = -1;

  MDSCapMatch() {}

  MDSCapMatch(const std::string& fsname_, const std::string& path_,
	      bool root_squash_, int64_t uid_=MDS_AUTH_UID_ANY,
	      const std::vector<gid_t>& gids_={}) {
    fs_name = std::move(fsname_);
    path = std::move(path_);
    root_squash = root_squash_;
    uid = (uid_ == 0) ? -1 : uid_;
    gids = gids_;

    normalize_path();
  }

  const MDSCapMatch& operator=(const MDSCapMatch& m) {
    uid = m.uid;
    gids = m.gids;
    path = m.path;
    fs_name = m.fs_name;
    root_squash = m.root_squash;
    return *this;
  }

  void normalize_path();

  bool is_match_all() const
  {
    return uid == MDS_AUTH_UID_ANY && path == "";
  }

  // check whether this grant matches against a given file and caller uid:gid
  bool match(std::string_view target_path,
	     const int caller_uid,
	     const int caller_gid,
	     const std::vector<uint64_t> *caller_gid_list) const;

  /**
   * Check whether this path *might* be accessible (actual permission
   * depends on the stronger check in match()).
   *
   * @param target_path filesystem path without leading '/'
   */
  bool match_path(std::string_view target_path) const;

  void encode(ceph::buffer::list& bl) const {
    ENCODE_START(1, 1, bl);
    encode(uid, bl);
    encode(gids, bl);
    encode(path, bl);
    encode(fs_name, bl);
    encode(root_squash, bl);
    ENCODE_FINISH(bl);
  }

  void decode(ceph::buffer::list::const_iterator& p) {
    DECODE_START(1, p);
    decode(uid, p);
    decode(gids, p);
    decode(path, p);
    decode(fs_name, p);
    decode(root_squash, p);
    DECODE_FINISH(p);
  }

  // Require UID to be equal to this, if !=MDS_AUTH_UID_ANY
  int64_t uid = MDS_AUTH_UID_ANY;
  std::vector<gid_t> gids;  // Use these GIDs
  std::string path;  // Require path to be child of this (may be "" or "/" for any)
  std::string fs_name;
  bool root_squash=false;
};
WRITE_CLASS_ENCODER(MDSCapMatch)

struct MDSCapAuth {
  MDSCapAuth() {}
  MDSCapAuth(MDSCapMatch m, bool r, bool w) :
    match(m), readable(r), writeable(w) {}

  const MDSCapAuth& operator=(const MDSCapAuth& m) {
    match = m.match;
    readable = m.readable;
    writeable = m.writeable;
    return *this;
  }

  void encode(ceph::buffer::list& bl) const {
    ENCODE_START(1, 1, bl);
    encode(match, bl);
    encode(readable, bl);
    encode(writeable, bl);
    ENCODE_FINISH(bl);
  }

  void decode(ceph::buffer::list::const_iterator& p) {
    DECODE_START(1, p);
    decode(match, p);
    decode(readable, p);
    decode(writeable, p);
    DECODE_FINISH(p);
  }

  MDSCapMatch match;
  bool readable;
  bool writeable;
};
WRITE_CLASS_ENCODER(MDSCapAuth)

struct MDSCapGrant {
  MDSCapGrant(const MDSCapSpec &spec_, const MDSCapMatch &match_,
	      boost::optional<std::string> n)
    : spec(spec_), match(match_) {
    if (n) {
      network = *n;
      parse_network();
    }
  }
  MDSCapGrant() {}

  void parse_network();

  MDSCapSpec spec;
  MDSCapMatch match;

  std::string network;

  entity_addr_t network_parsed;
  unsigned network_prefix = 0;
  bool network_valid = true;
};

class MDSAuthCaps
{
public:
  MDSAuthCaps() = default;

  // this ctor is used by spirit/phoenix
  explicit MDSAuthCaps(const std::vector<MDSCapGrant>& grants_) : grants(grants_) {}

  void clear() {
    grants.clear();
  }

  void set_allow_all();
  bool parse(std::string_view str, std::ostream *err);

  bool allow_all() const;
  bool is_capable(std::string_view inode_path,
		  uid_t inode_uid, gid_t inode_gid, unsigned inode_mode,
		  uid_t uid, gid_t gid, const std::vector<uint64_t> *caller_gid_list,
		  unsigned mask, uid_t new_uid, gid_t new_gid,
		  const entity_addr_t& addr) const;
  bool path_capable(std::string_view inode_path) const;

  bool fs_name_capable(std::string_view fs_name, unsigned mask) const {
    if (allow_all()) {
      return true;
    }

    for (const MDSCapGrant &g : grants) {
      if (g.match.fs_name == fs_name || g.match.fs_name.empty() ||
	  g.match.fs_name == "*") {
	if (mask & MAY_READ && g.spec.allow_read()) {
	  return true;
	}

	if (mask & MAY_WRITE && g.spec.allow_write()) {
	  return true;
	}
      }
    }

    return false;
  }

  void get_cap_auths(std::vector<MDSCapAuth> *cap_auths)
  {
    for (const auto& grant : grants) {
      cap_auths->emplace_back(MDSCapAuth(grant.match,
                                grant.spec.allow_read(),
                                grant.spec.allow_write()));
    }
  }

  bool root_squash_in_caps() const {
    for (const MDSCapGrant &g : grants) {
      if (g.match.root_squash) {
        return true;
      }
    }
    return false;
  }

  friend std::ostream &operator<<(std::ostream &out, const MDSAuthCaps &cap);
private:
  std::vector<MDSCapGrant> grants;
};

std::ostream &operator<<(std::ostream &out, const MDSCapMatch &match);
std::ostream &operator<<(std::ostream &out, const MDSCapAuth &auth);
std::ostream &operator<<(std::ostream &out, const MDSCapSpec &spec);
std::ostream &operator<<(std::ostream &out, const MDSCapGrant &grant);
std::ostream &operator<<(std::ostream &out, const MDSAuthCaps &cap);

#endif // MDS_AUTH_CAPS_H