diff --git a/src/rgw/rgw_file.cc b/src/rgw/rgw_file.cc index e0d7430bc94..405ee11a96e 100644 --- a/src/rgw/rgw_file.cc +++ b/src/rgw/rgw_file.cc @@ -588,6 +588,46 @@ int rgw_statfs(struct rgw_fs *rgw_fs, return 0; } +/* XXX can't call these virtual methods from non-REST handler */ +static int valid_s3_bucket_name(const string& name, bool relaxed=false) +{ + // This function enforces Amazon's spec for bucket names. + // (The requirements, not the recommendations.) + int len = name.size(); + if (len < 3) { + // Name too short + return -ERR_INVALID_BUCKET_NAME; + } else if (len > 255) { + // Name too long + return -ERR_INVALID_BUCKET_NAME; + } + + // bucket names must start with a number, letter, or underscore + if (!(isalpha(name[0]) || isdigit(name[0]))) { + if (!relaxed) + return -ERR_INVALID_BUCKET_NAME; + else if (!(name[0] == '_' || name[0] == '.' || name[0] == '-')) + return -ERR_INVALID_BUCKET_NAME; + } + + for (const char *s = name.c_str(); *s; ++s) { + char c = *s; + if (isdigit(c) || (c == '.')) + continue; + if (isalpha(c)) + continue; + if ((c == '-') || (c == '_')) + continue; + // Invalid character + return -ERR_INVALID_BUCKET_NAME; + } + + if (looks_like_ip_address(name.c_str())) + return -ERR_INVALID_BUCKET_NAME; + + return 0; +} + /* generic create -- creates a regular file */ @@ -658,8 +698,12 @@ int rgw_mkdir(struct rgw_fs *rgw_fs, if (parent->is_root()) { /* bucket */ - string uri = "/"; /* XXX get rid of URI some day soon */ - uri += name; + string bname{name}; + /* enforce S3 name restrictions */ + rc = valid_s3_bucket_name(bname, false /* relaxed */); + if (rc != 0) + return -EINVAL; + string uri = "/" + bname; /* XXX get rid of URI some day soon */ RGWCreateBucketRequest req(cct, fs->get_user(), uri); rc = rgwlib.get_fe()->execute_req(&req); rc2 = req.get_ret(); diff --git a/src/rgw/rgw_rest_s3.cc b/src/rgw/rgw_rest_s3.cc index be535c73c34..7c798f36019 100644 --- a/src/rgw/rgw_rest_s3.cc +++ b/src/rgw/rgw_rest_s3.cc @@ -2528,31 +2528,8 @@ int RGWHandler_REST_S3::postauth_init() return 0; } -static bool looks_like_ip_address(const char *bucket) -{ - int num_periods = 0; - bool expect_period = false; - for (const char *b = bucket; *b; ++b) { - if (*b == '.') { - if (!expect_period) - return false; - ++num_periods; - if (num_periods > 3) - return false; - expect_period = false; - } - else if (isdigit(*b)) { - expect_period = true; - } - else { - return false; - } - } - return (num_periods == 3); -} - int RGWHandler_REST_S3::validate_bucket_name(const string& bucket, - bool relaxed_names) + bool relaxed_names) { int ret = RGWHandler_REST::validate_bucket_name(bucket); if (ret < 0) diff --git a/src/rgw/rgw_rest_s3.h b/src/rgw/rgw_rest_s3.h index cde8581ef88..e7b23d08b17 100644 --- a/src/rgw/rgw_rest_s3.h +++ b/src/rgw/rgw_rest_s3.h @@ -2,6 +2,7 @@ // vim: ts=8 sw=2 smarttab #ifndef CEPH_RGW_REST_S3_H + #define CEPH_RGW_REST_S3_H #define TIME_BUF_SIZE 128 @@ -506,4 +507,27 @@ public: class RGWHandler_REST_Obj_S3Website; -#endif +static inline bool looks_like_ip_address(const char *bucket) +{ + int num_periods = 0; + bool expect_period = false; + for (const char *b = bucket; *b; ++b) { + if (*b == '.') { + if (!expect_period) + return false; + ++num_periods; + if (num_periods > 3) + return false; + expect_period = false; + } + else if (isdigit(*b)) { + expect_period = true; + } + else { + return false; + } + } + return (num_periods == 3); +} + +#endif /* CEPH_RGW_REST_S3_H */ diff --git a/src/test/librgw_file_nfsns.cc b/src/test/librgw_file_nfsns.cc index 9f72014b65c..470240c7398 100644 --- a/src/test/librgw_file_nfsns.cc +++ b/src/test/librgw_file_nfsns.cc @@ -44,7 +44,7 @@ namespace { CephContext* cct = nullptr; string bucket_name("nfsroot"); - string dirs1_bucket_name("b1"); + string dirs1_bucket_name("bdirs1"); class obj_rec {