]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | /* | |
4 | * Ceph - scalable distributed file system | |
5 | * | |
6 | * Copyright (C) 2004-2009 Sage Weil <sage@newdream.net> | |
7 | * | |
8 | * This is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU Lesser General Public | |
10 | * License version 2.1, as published by the Free Software | |
11 | * Foundation. See file COPYING. | |
12 | * | |
13 | */ | |
14 | ||
15 | #ifndef CEPH_KEYSSERVER_H | |
16 | #define CEPH_KEYSSERVER_H | |
17 | ||
18 | #include "auth/KeyRing.h" | |
19 | #include "CephxProtocol.h" | |
11fdf7f2 | 20 | #include "common/ceph_mutex.h" |
9f95a23c | 21 | #include "include/common_fwd.h" |
7c673cae FG |
22 | |
23 | struct KeyServerData { | |
f51cf556 | 24 | version_t version{0}; |
7c673cae FG |
25 | |
26 | /* for each entity */ | |
f67539c2 | 27 | std::map<EntityName, EntityAuth> secrets; |
f51cf556 | 28 | KeyRing *extra_secrets = nullptr; |
7c673cae FG |
29 | |
30 | /* for each service type */ | |
f51cf556 | 31 | version_t rotating_ver{0}; |
f67539c2 | 32 | std::map<uint32_t, RotatingSecrets> rotating_secrets; |
f51cf556 | 33 | KeyServerData() {} |
7c673cae FG |
34 | |
35 | explicit KeyServerData(KeyRing *extra) | |
36 | : version(0), | |
37 | extra_secrets(extra), | |
38 | rotating_ver(0) {} | |
39 | ||
f67539c2 | 40 | void encode(ceph::buffer::list& bl) const { |
7c673cae | 41 | __u8 struct_v = 1; |
11fdf7f2 TL |
42 | using ceph::encode; |
43 | encode(struct_v, bl); | |
44 | encode(version, bl); | |
45 | encode(rotating_ver, bl); | |
46 | encode(secrets, bl); | |
47 | encode(rotating_secrets, bl); | |
7c673cae | 48 | } |
f67539c2 | 49 | void decode(ceph::buffer::list::const_iterator& bl) { |
11fdf7f2 | 50 | using ceph::decode; |
7c673cae | 51 | __u8 struct_v; |
11fdf7f2 TL |
52 | decode(struct_v, bl); |
53 | decode(version, bl); | |
54 | decode(rotating_ver, bl); | |
55 | decode(secrets, bl); | |
56 | decode(rotating_secrets, bl); | |
7c673cae FG |
57 | } |
58 | ||
f67539c2 | 59 | void encode_rotating(ceph::buffer::list& bl) const { |
11fdf7f2 | 60 | using ceph::encode; |
7c673cae | 61 | __u8 struct_v = 1; |
11fdf7f2 TL |
62 | encode(struct_v, bl); |
63 | encode(rotating_ver, bl); | |
64 | encode(rotating_secrets, bl); | |
7c673cae | 65 | } |
f67539c2 | 66 | void decode_rotating(ceph::buffer::list& rotating_bl) { |
11fdf7f2 TL |
67 | using ceph::decode; |
68 | auto iter = rotating_bl.cbegin(); | |
7c673cae | 69 | __u8 struct_v; |
11fdf7f2 TL |
70 | decode(struct_v, iter); |
71 | decode(rotating_ver, iter); | |
72 | decode(rotating_secrets, iter); | |
7c673cae | 73 | } |
f51cf556 TL |
74 | void dump(ceph::Formatter *f) const { |
75 | f->dump_unsigned("version", version); | |
76 | f->dump_unsigned("rotating_version", rotating_ver); | |
77 | encode_json("secrets", secrets, f); | |
78 | encode_json("rotating_secrets", rotating_secrets, f); | |
79 | } | |
80 | static void generate_test_instances(std::list<KeyServerData*>& ls) { | |
81 | ls.push_back(new KeyServerData); | |
82 | ls.push_back(new KeyServerData); | |
83 | ls.back()->version = 1; | |
84 | } | |
7c673cae FG |
85 | bool contains(const EntityName& name) const { |
86 | return (secrets.find(name) != secrets.end()); | |
87 | } | |
88 | ||
89 | void clear_secrets() { | |
494da23a | 90 | version = 0; |
7c673cae | 91 | secrets.clear(); |
494da23a TL |
92 | rotating_ver = 0; |
93 | rotating_secrets.clear(); | |
7c673cae FG |
94 | } |
95 | ||
96 | void add_auth(const EntityName& name, EntityAuth& auth) { | |
97 | secrets[name] = auth; | |
98 | } | |
99 | ||
100 | void remove_secret(const EntityName& name) { | |
f67539c2 | 101 | auto iter = secrets.find(name); |
7c673cae FG |
102 | if (iter == secrets.end()) |
103 | return; | |
104 | secrets.erase(iter); | |
105 | } | |
106 | ||
107 | bool get_service_secret(CephContext *cct, uint32_t service_id, | |
c5c27e9a TL |
108 | CryptoKey& secret, uint64_t& secret_id, |
109 | double& ttl) const; | |
7c673cae FG |
110 | bool get_service_secret(CephContext *cct, uint32_t service_id, |
111 | uint64_t secret_id, CryptoKey& secret) const; | |
112 | bool get_auth(const EntityName& name, EntityAuth& auth) const; | |
113 | bool get_secret(const EntityName& name, CryptoKey& secret) const; | |
114 | bool get_caps(CephContext *cct, const EntityName& name, | |
115 | const std::string& type, AuthCapsInfo& caps) const; | |
116 | ||
f67539c2 | 117 | std::map<EntityName, EntityAuth>::iterator secrets_begin() |
7c673cae | 118 | { return secrets.begin(); } |
f67539c2 | 119 | std::map<EntityName, EntityAuth>::const_iterator secrets_begin() const |
7c673cae | 120 | { return secrets.begin(); } |
f67539c2 | 121 | std::map<EntityName, EntityAuth>::iterator secrets_end() |
7c673cae | 122 | { return secrets.end(); } |
f67539c2 | 123 | std::map<EntityName, EntityAuth>::const_iterator secrets_end() const |
7c673cae | 124 | { return secrets.end(); } |
f67539c2 | 125 | std::map<EntityName, EntityAuth>::iterator find_name(const EntityName& name) |
7c673cae | 126 | { return secrets.find(name); } |
f67539c2 | 127 | std::map<EntityName, EntityAuth>::const_iterator find_name(const EntityName& name) const |
7c673cae FG |
128 | { return secrets.find(name); } |
129 | ||
130 | ||
131 | // -- incremental updates -- | |
132 | typedef enum { | |
133 | AUTH_INC_NOP, | |
134 | AUTH_INC_ADD, | |
135 | AUTH_INC_DEL, | |
136 | AUTH_INC_SET_ROTATING, | |
137 | } IncrementalOp; | |
138 | ||
139 | struct Incremental { | |
140 | IncrementalOp op; | |
f67539c2 | 141 | ceph::buffer::list rotating_bl; // if SET_ROTATING. otherwise, |
7c673cae FG |
142 | EntityName name; |
143 | EntityAuth auth; | |
f67539c2 TL |
144 | |
145 | void encode(ceph::buffer::list& bl) const { | |
11fdf7f2 | 146 | using ceph::encode; |
7c673cae | 147 | __u8 struct_v = 1; |
11fdf7f2 | 148 | encode(struct_v, bl); |
7c673cae | 149 | __u32 _op = (__u32)op; |
11fdf7f2 | 150 | encode(_op, bl); |
7c673cae | 151 | if (op == AUTH_INC_SET_ROTATING) { |
11fdf7f2 | 152 | encode(rotating_bl, bl); |
7c673cae | 153 | } else { |
11fdf7f2 TL |
154 | encode(name, bl); |
155 | encode(auth, bl); | |
7c673cae FG |
156 | } |
157 | } | |
f67539c2 | 158 | void decode(ceph::buffer::list::const_iterator& bl) { |
11fdf7f2 | 159 | using ceph::decode; |
7c673cae | 160 | __u8 struct_v; |
11fdf7f2 | 161 | decode(struct_v, bl); |
7c673cae | 162 | __u32 _op; |
11fdf7f2 | 163 | decode(_op, bl); |
7c673cae | 164 | op = (IncrementalOp)_op; |
11fdf7f2 | 165 | ceph_assert(op >= AUTH_INC_NOP && op <= AUTH_INC_SET_ROTATING); |
7c673cae | 166 | if (op == AUTH_INC_SET_ROTATING) { |
11fdf7f2 | 167 | decode(rotating_bl, bl); |
7c673cae | 168 | } else { |
11fdf7f2 TL |
169 | decode(name, bl); |
170 | decode(auth, bl); | |
7c673cae FG |
171 | } |
172 | } | |
f51cf556 TL |
173 | void dump(ceph::Formatter *f) const { |
174 | f->dump_unsigned("op", op); | |
175 | f->dump_object("name", name); | |
176 | f->dump_object("auth", auth); | |
177 | } | |
178 | static void generate_test_instances(std::list<Incremental*>& ls) { | |
179 | ls.push_back(new Incremental); | |
180 | ls.back()->op = AUTH_INC_DEL; | |
181 | ls.push_back(new Incremental); | |
182 | ls.back()->op = AUTH_INC_ADD; | |
183 | ls.push_back(new Incremental); | |
184 | ls.back()->op = AUTH_INC_SET_ROTATING; | |
185 | } | |
7c673cae | 186 | }; |
f51cf556 | 187 | |
7c673cae FG |
188 | void apply_incremental(Incremental& inc) { |
189 | switch (inc.op) { | |
190 | case AUTH_INC_ADD: | |
191 | add_auth(inc.name, inc.auth); | |
192 | break; | |
193 | ||
194 | case AUTH_INC_DEL: | |
195 | remove_secret(inc.name); | |
196 | break; | |
197 | ||
198 | case AUTH_INC_SET_ROTATING: | |
199 | decode_rotating(inc.rotating_bl); | |
200 | break; | |
201 | ||
202 | case AUTH_INC_NOP: | |
203 | break; | |
204 | ||
205 | default: | |
206 | ceph_abort(); | |
207 | } | |
208 | } | |
209 | ||
210 | }; | |
211 | WRITE_CLASS_ENCODER(KeyServerData) | |
212 | WRITE_CLASS_ENCODER(KeyServerData::Incremental) | |
213 | ||
214 | ||
7c673cae FG |
215 | class KeyServer : public KeyStore { |
216 | CephContext *cct; | |
217 | KeyServerData data; | |
39ae355f | 218 | std::map<EntityName, CryptoKey> used_pending_keys; |
11fdf7f2 | 219 | mutable ceph::mutex lock; |
7c673cae | 220 | |
a4b75251 | 221 | int _rotate_secret(uint32_t service_id, KeyServerData &pending_data); |
7c673cae FG |
222 | void _dump_rotating_secrets(); |
223 | int _build_session_auth_info(uint32_t service_id, | |
11fdf7f2 | 224 | const AuthTicket& parent_ticket, |
c5c27e9a TL |
225 | CephXSessionAuthInfo& info, |
226 | double ttl); | |
7c673cae FG |
227 | bool _get_service_caps(const EntityName& name, uint32_t service_id, |
228 | AuthCapsInfo& caps) const; | |
229 | public: | |
f51cf556 | 230 | KeyServer() : lock{ceph::make_mutex("KeyServer::lock")} {} |
7c673cae | 231 | KeyServer(CephContext *cct_, KeyRing *extra_secrets); |
f51cf556 | 232 | KeyServer& operator=(const KeyServer&) = delete; |
7c673cae FG |
233 | bool generate_secret(CryptoKey& secret); |
234 | ||
235 | bool get_secret(const EntityName& name, CryptoKey& secret) const override; | |
236 | bool get_auth(const EntityName& name, EntityAuth& auth) const; | |
f67539c2 | 237 | bool get_caps(const EntityName& name, const std::string& type, AuthCapsInfo& caps) const; |
7c673cae | 238 | bool get_active_rotating_secret(const EntityName& name, CryptoKey& secret) const; |
39ae355f TL |
239 | |
240 | void note_used_pending_key(const EntityName& name, const CryptoKey& key); | |
241 | void clear_used_pending_keys(); | |
242 | std::map<EntityName,CryptoKey> get_used_pending_keys(); | |
243 | ||
7c673cae FG |
244 | int start_server(); |
245 | void rotate_timeout(double timeout); | |
246 | ||
a4b75251 TL |
247 | void dump(); |
248 | ||
11fdf7f2 TL |
249 | int build_session_auth_info(uint32_t service_id, |
250 | const AuthTicket& parent_ticket, | |
251 | CephXSessionAuthInfo& info); | |
252 | int build_session_auth_info(uint32_t service_id, | |
253 | const AuthTicket& parent_ticket, | |
c5c27e9a TL |
254 | const CryptoKey& service_secret, |
255 | uint64_t secret_id, | |
256 | CephXSessionAuthInfo& info); | |
7c673cae FG |
257 | |
258 | /* get current secret for specific service type */ | |
c5c27e9a TL |
259 | bool get_service_secret(uint32_t service_id, CryptoKey& secret, |
260 | uint64_t& secret_id, double& ttl) const; | |
7c673cae FG |
261 | bool get_service_secret(uint32_t service_id, uint64_t secret_id, |
262 | CryptoKey& secret) const override; | |
263 | ||
264 | bool generate_secret(EntityName& name, CryptoKey& secret); | |
265 | ||
f67539c2 | 266 | void encode(ceph::buffer::list& bl) const { |
11fdf7f2 TL |
267 | using ceph::encode; |
268 | encode(data, bl); | |
7c673cae | 269 | } |
f67539c2 | 270 | void decode(ceph::buffer::list::const_iterator& bl) { |
11fdf7f2 TL |
271 | std::scoped_lock l{lock}; |
272 | using ceph::decode; | |
273 | decode(data, bl); | |
7c673cae | 274 | } |
f51cf556 TL |
275 | void dump(ceph::Formatter *f) const; |
276 | static void generate_test_instances(std::list<KeyServer*>& ls); | |
7c673cae | 277 | bool contains(const EntityName& name) const; |
f67539c2 TL |
278 | int encode_secrets(ceph::Formatter *f, std::stringstream *ds) const; |
279 | void encode_formatted(std::string label, ceph::Formatter *f, ceph::buffer::list &bl); | |
280 | void encode_plaintext(ceph::buffer::list &bl); | |
281 | int list_secrets(std::stringstream& ds) const { | |
7c673cae FG |
282 | return encode_secrets(NULL, &ds); |
283 | } | |
284 | version_t get_ver() const { | |
11fdf7f2 | 285 | std::scoped_lock l{lock}; |
f67539c2 | 286 | return data.version; |
7c673cae FG |
287 | } |
288 | ||
289 | void clear_secrets() { | |
11fdf7f2 | 290 | std::scoped_lock l{lock}; |
7c673cae FG |
291 | data.clear_secrets(); |
292 | } | |
293 | ||
294 | void apply_data_incremental(KeyServerData::Incremental& inc) { | |
11fdf7f2 | 295 | std::scoped_lock l{lock}; |
7c673cae FG |
296 | data.apply_incremental(inc); |
297 | } | |
298 | void set_ver(version_t ver) { | |
11fdf7f2 | 299 | std::scoped_lock l{lock}; |
7c673cae FG |
300 | data.version = ver; |
301 | } | |
302 | ||
303 | void add_auth(const EntityName& name, EntityAuth& auth) { | |
11fdf7f2 | 304 | std::scoped_lock l{lock}; |
7c673cae FG |
305 | data.add_auth(name, auth); |
306 | } | |
307 | ||
308 | void remove_secret(const EntityName& name) { | |
11fdf7f2 | 309 | std::scoped_lock l{lock}; |
7c673cae FG |
310 | data.remove_secret(name); |
311 | } | |
312 | ||
313 | bool has_secrets() { | |
f67539c2 | 314 | auto b = data.secrets_begin(); |
7c673cae FG |
315 | return (b != data.secrets_end()); |
316 | } | |
317 | int get_num_secrets() { | |
11fdf7f2 | 318 | std::scoped_lock l{lock}; |
7c673cae FG |
319 | return data.secrets.size(); |
320 | } | |
321 | ||
322 | void clone_to(KeyServerData& dst) const { | |
11fdf7f2 | 323 | std::scoped_lock l{lock}; |
7c673cae FG |
324 | dst = data; |
325 | } | |
326 | void export_keyring(KeyRing& keyring) { | |
11fdf7f2 | 327 | std::scoped_lock l{lock}; |
f67539c2 | 328 | for (auto p = data.secrets.begin(); p != data.secrets.end(); ++p) { |
7c673cae FG |
329 | keyring.add(p->first, p->second); |
330 | } | |
331 | } | |
332 | ||
a4b75251 | 333 | bool prepare_rotating_update(ceph::buffer::list& rotating_bl); |
7c673cae | 334 | |
f67539c2 | 335 | bool get_rotating_encrypted(const EntityName& name, ceph::buffer::list& enc_bl) const; |
7c673cae | 336 | |
11fdf7f2 | 337 | ceph::mutex& get_lock() const { return lock; } |
7c673cae FG |
338 | bool get_service_caps(const EntityName& name, uint32_t service_id, |
339 | AuthCapsInfo& caps) const; | |
340 | ||
f67539c2 | 341 | std::map<EntityName, EntityAuth>::iterator secrets_begin() |
7c673cae | 342 | { return data.secrets_begin(); } |
f67539c2 | 343 | std::map<EntityName, EntityAuth>::iterator secrets_end() |
7c673cae FG |
344 | { return data.secrets_end(); } |
345 | }; | |
346 | WRITE_CLASS_ENCODER(KeyServer) | |
347 | ||
348 | ||
349 | #endif |