// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab ft=cpp #include #include #include #include "rgw_torrent.h" #include "rgw_sal.h" #include "rgw_sal_rados.h" #include "include/str_list.h" #include "include/rados/librados.hpp" #include "services/svc_sys_obj.h" #define dout_subsys ceph_subsys_rgw using namespace std; using namespace librados; using namespace boost; using ceph::crypto::SHA1; seed::seed() { seed::info.piece_length = 0; seed::info.len = 0; sha_len = 0; is_torrent = false; } seed::~seed() { seed::info.sha1_bl.clear(); bl.clear(); s = NULL; driver = NULL; } void seed::init(req_state *_req, rgw::sal::Driver* _driver) { s = _req; driver = _driver; } int seed::get_torrent_file(rgw::sal::Object* object, uint64_t &total_len, ceph::bufferlist &bl_data, rgw_obj &obj) { /* add other field if config is set */ dencode.bencode_dict(bl); set_announce(); if (!comment.empty()) { dencode.bencode(COMMENT, comment, bl); } if (!create_by.empty()) { dencode.bencode(CREATED_BY, create_by, bl); } if (!encoding.empty()) { dencode.bencode(ENCODING, encoding, bl); } string oid, key; get_obj_bucket_and_oid_loc(obj, oid, key); ldpp_dout(s, 20) << "NOTICE: head obj oid= " << oid << dendl; const set obj_key{RGW_OBJ_TORRENT}; map m; const int r = object->omap_get_vals_by_keys(s, oid, obj_key, &m); if (r < 0) { ldpp_dout(s, 0) << "ERROR: omap_get_vals_by_keys failed: " << r << dendl; return r; } if (m.size() != 1) { ldpp_dout(s, 0) << "ERROR: omap key " RGW_OBJ_TORRENT " not found" << dendl; return -EINVAL; } bl.append(std::move(m.begin()->second)); dencode.bencode_end(bl); bl_data = bl; total_len = bl.length(); return 0; } bool seed::get_flag() { return is_torrent; } void seed::update(bufferlist &bl) { if (!is_torrent) { return; } info.len += bl.length(); sha1(&h, bl, bl.length()); } int seed::complete(optional_yield y) { uint64_t remain = info.len%info.piece_length; uint8_t remain_len = ((remain > 0)? 1 : 0); sha_len = (info.len/info.piece_length + remain_len)*CEPH_CRYPTO_SHA1_DIGESTSIZE; int ret = 0; /* produce torrent data */ do_encode(); /* save torrent data into OMAP */ ret = save_torrent_file(y); if (0 != ret) { ldpp_dout(s, 0) << "ERROR: failed to save_torrent_file() ret= "<< ret << dendl; return ret; } return 0; } off_t seed::get_data_len() { return info.len; } void seed::set_create_date(ceph::real_time& value) { utime_t date = ceph::real_clock::to_timespec(value); create_date = date.sec(); } void seed::set_info_pieces(char *buff) { info.sha1_bl.append(buff, CEPH_CRYPTO_SHA1_DIGESTSIZE); } void seed::set_info_name(const string& value) { info.name = value; } void seed::sha1(SHA1 *h, bufferlist &bl, off_t bl_len) { off_t num = bl_len/info.piece_length; off_t remain = 0; remain = bl_len%info.piece_length; char *pstr = bl.c_str(); char sha[25]; /* get sha1 */ for (off_t i = 0; i < num; i++) { // FIPS zeroization audit 20191116: this memset is not intended to // wipe out a secret after use. memset(sha, 0x00, sizeof(sha)); h->Update((unsigned char *)pstr, info.piece_length); h->Final((unsigned char *)sha); set_info_pieces(sha); pstr += info.piece_length; } /* process remain */ if (0 != remain) { // FIPS zeroization audit 20191116: this memset is not intended to // wipe out a secret after use. memset(sha, 0x00, sizeof(sha)); h->Update((unsigned char *)pstr, remain); h->Final((unsigned char *)sha); set_info_pieces(sha); } ::ceph::crypto::zeroize_for_security(sha, sizeof(sha)); } int seed::get_params() { is_torrent = true; info.piece_length = g_conf()->rgw_torrent_sha_unit; create_by = g_conf()->rgw_torrent_createby; encoding = g_conf()->rgw_torrent_encoding; origin = g_conf()->rgw_torrent_origin; comment = g_conf()->rgw_torrent_comment; announce = g_conf()->rgw_torrent_tracker; /* tracker and tracker list is empty, set announce to origin */ if (announce.empty() && !origin.empty()) { announce = origin; } return 0; } void seed::set_announce() { list announce_list; // used to get announce list from conf get_str_list(announce, ",", announce_list); if (announce_list.empty()) { ldpp_dout(s, 5) << "NOTICE: announce_list is empty " << dendl; return; } list::iterator iter = announce_list.begin(); dencode.bencode_key(ANNOUNCE, bl); dencode.bencode_key((*iter), bl); dencode.bencode_key(ANNOUNCE_LIST, bl); dencode.bencode_list(bl); for (; iter != announce_list.end(); ++iter) { dencode.bencode_list(bl); dencode.bencode_key((*iter), bl); dencode.bencode_end(bl); } dencode.bencode_end(bl); } void seed::do_encode() { /*Only encode create_date and sha1 info*/ /*Other field will be added if confi is set when run get torrent*/ dencode.bencode(CREATION_DATE, create_date, bl); dencode.bencode_key(INFO_PIECES, bl); dencode.bencode_dict(bl); dencode.bencode(LENGTH, info.len, bl); dencode.bencode(NAME, info.name, bl); dencode.bencode(PIECE_LENGTH, info.piece_length, bl); char info_sha[100] = { 0 }; sprintf(info_sha, "%" PRIu64, sha_len); string sha_len_str = info_sha; dencode.bencode_key(PIECES, bl); bl.append(sha_len_str.c_str(), sha_len_str.length()); bl.append(':'); bl.append(info.sha1_bl.c_str(), sha_len); dencode.bencode_end(bl); } int seed::save_torrent_file(optional_yield y) { int op_ret = 0; string key = RGW_OBJ_TORRENT; op_ret = s->object->omap_set_val_by_key(s, key, bl, false, y); if (op_ret < 0) { ldpp_dout(s, 0) << "ERROR: failed to omap_set() op_ret = " << op_ret << dendl; return op_ret; } return op_ret; }