summaryrefslogtreecommitdiffstats
path: root/src/mds/MDSAuthCaps.h
blob: 395c921fd5fe25f1dc0ab33afc51067d747892a2 (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
// -*- 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/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() : uid(MDS_AUTH_UID_ANY), fs_name(std::string()) {}

  MDSCapMatch(int64_t uid_, std::vector<gid_t>& gids_) :
    uid(uid_), gids(gids_), fs_name(std::string()) {}

  explicit MDSCapMatch(const std::string &path_)
    : uid(MDS_AUTH_UID_ANY), path(path_), fs_name(std::string()) {
    normalize_path();
  }

  explicit MDSCapMatch(std::string path, std::string fs_name) :
    uid(MDS_AUTH_UID_ANY), path(std::move(path)), fs_name(std::move(fs_name))
  {
    normalize_path();
  }

  explicit MDSCapMatch(std::string path, std::string fs_name, bool root_squash_) :
    uid(MDS_AUTH_UID_ANY), path(std::move(path)), fs_name(std::move(fs_name)), root_squash(root_squash_)
  {
    normalize_path();
  }

  MDSCapMatch(const std::string& path_, int64_t uid_, std::vector<gid_t>& gids_)
    : uid(uid_), gids(gids_), path(path_), fs_name(std::string()) {
    normalize_path();
  }

  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;

  int64_t uid;       // Require UID to be equal to this, if !=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;
};

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;
  explicit MDSAuthCaps(CephContext *cct_) : cct(cct_) {}

  // this ctor is used by spirit/phoenix; doesn't need cct.
  explicit MDSAuthCaps(const std::vector<MDSCapGrant>& grants_) : grants(grants_) {}

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

  void set_allow_all();
  bool parse(CephContext *cct, 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;
  }

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

std::ostream &operator<<(std::ostream &out, const MDSCapMatch &match);
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