librgw: enforce S3 bucket name restrictions

Signed-off-by: Matt Benjamin <mbenjamin@redhat.com>
This commit is contained in:
Matt Benjamin 2016-01-09 17:45:45 -05:00
parent 54149b06c1
commit 66b6b1fd3e
4 changed files with 73 additions and 28 deletions

View File

@ -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();

View File

@ -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)

View File

@ -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 */

View File

@ -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
{