]> git.proxmox.com Git - ceph.git/blob - ceph/src/rgw/services/svc_cls.cc
984d92a5ee95f7c16c7dc8c202f64c0394018d33
[ceph.git] / ceph / src / rgw / services / svc_cls.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab ft=cpp
3
4
5 #include "svc_cls.h"
6 #include "svc_rados.h"
7 #include "svc_zone.h"
8
9 #include "rgw/rgw_zone.h"
10
11 #include "cls/otp/cls_otp_client.h"
12 #include "cls/log/cls_log_client.h"
13 #include "cls/lock/cls_lock_client.h"
14
15
16 #define dout_subsys ceph_subsys_rgw
17
18 static string log_lock_name = "rgw_log_lock";
19
20 int RGWSI_Cls::do_start(optional_yield y)
21 {
22 int r = mfa.do_start(y);
23 if (r < 0) {
24 ldout(cct, 0) << "ERROR: failed to start mfa service" << dendl;
25 return r;
26 }
27
28 return 0;
29 }
30
31 int RGWSI_Cls::MFA::get_mfa_obj(const rgw_user& user, std::optional<RGWSI_RADOS::Obj> *obj)
32 {
33 string oid = get_mfa_oid(user);
34 rgw_raw_obj o(zone_svc->get_zone_params().otp_pool, oid);
35
36 obj->emplace(rados_svc->obj(o));
37 int r = (*obj)->open();
38 if (r < 0) {
39 ldout(cct, 4) << "failed to open rados context for " << o << dendl;
40 return r;
41 }
42
43 return 0;
44 }
45
46 int RGWSI_Cls::MFA::get_mfa_ref(const rgw_user& user, rgw_rados_ref *ref)
47 {
48 std::optional<RGWSI_RADOS::Obj> obj;
49 int r = get_mfa_obj(user, &obj);
50 if (r < 0) {
51 return r;
52 }
53 *ref = obj->get_ref();
54 return 0;
55 }
56
57 int RGWSI_Cls::MFA::check_mfa(const rgw_user& user, const string& otp_id, const string& pin, optional_yield y)
58 {
59 rgw_rados_ref ref;
60 int r = get_mfa_ref(user, &ref);
61 if (r < 0) {
62 return r;
63 }
64
65 rados::cls::otp::otp_check_t result;
66
67 r = rados::cls::otp::OTP::check(cct, ref.pool.ioctx(), ref.obj.oid, otp_id, pin, &result);
68 if (r < 0)
69 return r;
70
71 ldout(cct, 20) << "OTP check, otp_id=" << otp_id << " result=" << (int)result.result << dendl;
72
73 return (result.result == rados::cls::otp::OTP_CHECK_SUCCESS ? 0 : -EACCES);
74 }
75
76 void RGWSI_Cls::MFA::prepare_mfa_write(librados::ObjectWriteOperation *op,
77 RGWObjVersionTracker *objv_tracker,
78 const ceph::real_time& mtime)
79 {
80 RGWObjVersionTracker ot;
81
82 if (objv_tracker) {
83 ot = *objv_tracker;
84 }
85
86 if (ot.write_version.tag.empty()) {
87 if (ot.read_version.tag.empty()) {
88 ot.generate_new_write_ver(cct);
89 } else {
90 ot.write_version = ot.read_version;
91 ot.write_version.ver++;
92 }
93 }
94
95 ot.prepare_op_for_write(op);
96 struct timespec mtime_ts = real_clock::to_timespec(mtime);
97 op->mtime2(&mtime_ts);
98 }
99
100 int RGWSI_Cls::MFA::create_mfa(const rgw_user& user, const rados::cls::otp::otp_info_t& config,
101 RGWObjVersionTracker *objv_tracker, const ceph::real_time& mtime, optional_yield y)
102 {
103 std::optional<RGWSI_RADOS::Obj> obj;
104 int r = get_mfa_obj(user, &obj);
105 if (r < 0) {
106 return r;
107 }
108
109 librados::ObjectWriteOperation op;
110 prepare_mfa_write(&op, objv_tracker, mtime);
111 rados::cls::otp::OTP::create(&op, config);
112 r = obj->operate(&op, y);
113 if (r < 0) {
114 ldout(cct, 20) << "OTP create, otp_id=" << config.id << " result=" << (int)r << dendl;
115 return r;
116 }
117
118 return 0;
119 }
120
121 int RGWSI_Cls::MFA::remove_mfa(const rgw_user& user, const string& id,
122 RGWObjVersionTracker *objv_tracker,
123 const ceph::real_time& mtime,
124 optional_yield y)
125 {
126 std::optional<RGWSI_RADOS::Obj> obj;
127 int r = get_mfa_obj(user, &obj);
128 if (r < 0) {
129 return r;
130 }
131
132 librados::ObjectWriteOperation op;
133 prepare_mfa_write(&op, objv_tracker, mtime);
134 rados::cls::otp::OTP::remove(&op, id);
135 r = obj->operate(&op, y);
136 if (r < 0) {
137 ldout(cct, 20) << "OTP remove, otp_id=" << id << " result=" << (int)r << dendl;
138 return r;
139 }
140
141 return 0;
142 }
143
144 int RGWSI_Cls::MFA::get_mfa(const rgw_user& user, const string& id, rados::cls::otp::otp_info_t *result,
145 optional_yield y)
146 {
147 rgw_rados_ref ref;
148
149 int r = get_mfa_ref(user, &ref);
150 if (r < 0) {
151 return r;
152 }
153
154 r = rados::cls::otp::OTP::get(nullptr, ref.pool.ioctx(), ref.obj.oid, id, result);
155 if (r < 0) {
156 return r;
157 }
158
159 return 0;
160 }
161
162 int RGWSI_Cls::MFA::list_mfa(const rgw_user& user, list<rados::cls::otp::otp_info_t> *result,
163 optional_yield y)
164 {
165 rgw_rados_ref ref;
166
167 int r = get_mfa_ref(user, &ref);
168 if (r < 0) {
169 return r;
170 }
171
172 r = rados::cls::otp::OTP::get_all(nullptr, ref.pool.ioctx(), ref.obj.oid, result);
173 if (r < 0) {
174 return r;
175 }
176
177 return 0;
178 }
179
180 int RGWSI_Cls::MFA::otp_get_current_time(const rgw_user& user, ceph::real_time *result,
181 optional_yield y)
182 {
183 rgw_rados_ref ref;
184
185 int r = get_mfa_ref(user, &ref);
186 if (r < 0) {
187 return r;
188 }
189
190 r = rados::cls::otp::OTP::get_current_time(ref.pool.ioctx(), ref.obj.oid, result);
191 if (r < 0) {
192 return r;
193 }
194
195 return 0;
196 }
197
198 int RGWSI_Cls::MFA::set_mfa(const string& oid, const list<rados::cls::otp::otp_info_t>& entries,
199 bool reset_obj, RGWObjVersionTracker *objv_tracker,
200 const real_time& mtime,
201 optional_yield y)
202 {
203 rgw_raw_obj o(zone_svc->get_zone_params().otp_pool, oid);
204 auto obj = rados_svc->obj(o);
205 int r = obj.open();
206 if (r < 0) {
207 ldout(cct, 4) << "failed to open rados context for " << o << dendl;
208 return r;
209 }
210 librados::ObjectWriteOperation op;
211 if (reset_obj) {
212 op.remove();
213 op.set_op_flags2(LIBRADOS_OP_FLAG_FAILOK);
214 op.create(false);
215 }
216 prepare_mfa_write(&op, objv_tracker, mtime);
217 rados::cls::otp::OTP::set(&op, entries);
218 r = obj.operate(&op, y);
219 if (r < 0) {
220 ldout(cct, 20) << "OTP set entries.size()=" << entries.size() << " result=" << (int)r << dendl;
221 return r;
222 }
223
224 return 0;
225 }
226
227 int RGWSI_Cls::MFA::list_mfa(const string& oid, list<rados::cls::otp::otp_info_t> *result,
228 RGWObjVersionTracker *objv_tracker, ceph::real_time *pmtime,
229 optional_yield y)
230 {
231 rgw_raw_obj o(zone_svc->get_zone_params().otp_pool, oid);
232 auto obj = rados_svc->obj(o);
233 int r = obj.open();
234 if (r < 0) {
235 ldout(cct, 4) << "failed to open rados context for " << o << dendl;
236 return r;
237 }
238 auto& ref = obj.get_ref();
239 librados::ObjectReadOperation op;
240 struct timespec mtime_ts;
241 if (pmtime) {
242 op.stat2(nullptr, &mtime_ts, nullptr);
243 }
244 objv_tracker->prepare_op_for_read(&op);
245 r = rados::cls::otp::OTP::get_all(&op, ref.pool.ioctx(), ref.obj.oid, result);
246 if (r < 0) {
247 return r;
248 }
249 if (pmtime) {
250 *pmtime = ceph::real_clock::from_timespec(mtime_ts);
251 }
252
253 return 0;
254 }
255
256 void RGWSI_Cls::TimeLog::prepare_entry(cls_log_entry& entry,
257 const real_time& ut,
258 const string& section,
259 const string& key,
260 bufferlist& bl)
261 {
262 cls_log_add_prepare_entry(entry, utime_t(ut), section, key, bl);
263 }
264
265 int RGWSI_Cls::TimeLog::init_obj(const string& oid, RGWSI_RADOS::Obj& obj)
266 {
267 rgw_raw_obj o(zone_svc->get_zone_params().log_pool, oid);
268 obj = rados_svc->obj(o);
269 return obj.open();
270
271 }
272 int RGWSI_Cls::TimeLog::add(const string& oid,
273 const real_time& ut,
274 const string& section,
275 const string& key,
276 bufferlist& bl,
277 optional_yield y)
278 {
279 RGWSI_RADOS::Obj obj;
280
281 int r = init_obj(oid, obj);
282 if (r < 0) {
283 return r;
284 }
285
286 librados::ObjectWriteOperation op;
287 utime_t t(ut);
288 cls_log_add(op, t, section, key, bl);
289
290 return obj.operate(&op, y);
291 }
292
293 int RGWSI_Cls::TimeLog::add(const string& oid,
294 std::list<cls_log_entry>& entries,
295 librados::AioCompletion *completion,
296 bool monotonic_inc,
297 optional_yield y)
298 {
299 RGWSI_RADOS::Obj obj;
300
301 int r = init_obj(oid, obj);
302 if (r < 0) {
303 return r;
304 }
305
306 librados::ObjectWriteOperation op;
307 cls_log_add(op, entries, monotonic_inc);
308
309 if (!completion) {
310 r = obj.operate(&op, y);
311 } else {
312 r = obj.aio_operate(completion, &op);
313 }
314 return r;
315 }
316
317 int RGWSI_Cls::TimeLog::list(const string& oid,
318 const real_time& start_time,
319 const real_time& end_time,
320 int max_entries, std::list<cls_log_entry>& entries,
321 const string& marker,
322 string *out_marker,
323 bool *truncated,
324 optional_yield y)
325 {
326 RGWSI_RADOS::Obj obj;
327
328 int r = init_obj(oid, obj);
329 if (r < 0) {
330 return r;
331 }
332
333 librados::ObjectReadOperation op;
334
335 utime_t st(start_time);
336 utime_t et(end_time);
337
338 cls_log_list(op, st, et, marker, max_entries, entries,
339 out_marker, truncated);
340
341 bufferlist obl;
342
343 int ret = obj.operate(&op, &obl, y);
344 if (ret < 0)
345 return ret;
346
347 return 0;
348 }
349
350 int RGWSI_Cls::TimeLog::info(const string& oid,
351 cls_log_header *header,
352 optional_yield y)
353 {
354 RGWSI_RADOS::Obj obj;
355
356 int r = init_obj(oid, obj);
357 if (r < 0) {
358 return r;
359 }
360
361 librados::ObjectReadOperation op;
362
363 cls_log_info(op, header);
364
365 bufferlist obl;
366
367 int ret = obj.operate(&op, &obl, y);
368 if (ret < 0)
369 return ret;
370
371 return 0;
372 }
373
374 int RGWSI_Cls::TimeLog::info_async(RGWSI_RADOS::Obj& obj,
375 const string& oid,
376 cls_log_header *header,
377 librados::AioCompletion *completion)
378 {
379 int r = init_obj(oid, obj);
380 if (r < 0) {
381 return r;
382 }
383
384 librados::ObjectReadOperation op;
385
386 cls_log_info(op, header);
387
388 int ret = obj.aio_operate(completion, &op, nullptr);
389 if (ret < 0)
390 return ret;
391
392 return 0;
393 }
394
395 int RGWSI_Cls::TimeLog::trim(const string& oid,
396 const real_time& start_time,
397 const real_time& end_time,
398 const string& from_marker,
399 const string& to_marker,
400 librados::AioCompletion *completion,
401 optional_yield y)
402 {
403 RGWSI_RADOS::Obj obj;
404
405 int r = init_obj(oid, obj);
406 if (r < 0) {
407 return r;
408 }
409
410 utime_t st(start_time);
411 utime_t et(end_time);
412
413 librados::ObjectWriteOperation op;
414 cls_log_trim(op, st, et, from_marker, to_marker);
415
416 if (!completion) {
417 r = obj.operate(&op, y);
418 } else {
419 r = obj.aio_operate(completion, &op);
420 }
421 return r;
422 }
423
424 int RGWSI_Cls::Lock::lock_exclusive(const rgw_pool& pool,
425 const string& oid,
426 timespan& duration,
427 string& zone_id,
428 string& owner_id,
429 std::optional<string> lock_name)
430 {
431 auto p = rados_svc->pool(pool);
432 int r = p.open();
433 if (r < 0) {
434 return r;
435 }
436
437 uint64_t msec = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
438 utime_t ut(msec / 1000, msec % 1000);
439
440 rados::cls::lock::Lock l(lock_name.value_or(log_lock_name));
441 l.set_duration(ut);
442 l.set_cookie(owner_id);
443 l.set_tag(zone_id);
444 l.set_may_renew(true);
445
446 return l.lock_exclusive(&p.ioctx(), oid);
447 }
448
449 int RGWSI_Cls::Lock::unlock(const rgw_pool& pool,
450 const string& oid,
451 string& zone_id,
452 string& owner_id,
453 std::optional<string> lock_name)
454 {
455 auto p = rados_svc->pool(pool);
456 int r = p.open();
457 if (r < 0) {
458 return r;
459 }
460
461 rados::cls::lock::Lock l(lock_name.value_or(log_lock_name));
462 l.set_tag(zone_id);
463 l.set_cookie(owner_id);
464
465 return l.unlock(&p.ioctx(), oid);
466 }
467