From e5d4e7aa9d7ba16bbf0c0fe135eb05102132b528 Mon Sep 17 00:00:00 2001 From: Harshavardhana Date: Fri, 3 Mar 2017 03:01:42 -0800 Subject: [PATCH] web: Validate if bucket names are reserved (#3841) Both '.minio.sys' and 'minio' should be never allowed to be created from web-ui and then fail to list it by filtering them out. Fixes #3840 --- cmd/generic-handlers.go | 11 +++++------ cmd/object-api-utils.go | 12 +++++++++++- cmd/typed-errors.go | 4 ++++ cmd/web-handlers.go | 22 +++++++++++++++++++++- cmd/web-handlers_test.go | 2 ++ 5 files changed, 43 insertions(+), 8 deletions(-) diff --git a/cmd/generic-handlers.go b/cmd/generic-handlers.go index 9af4d6d14..3f94789f5 100644 --- a/cmd/generic-handlers.go +++ b/cmd/generic-handlers.go @@ -20,7 +20,6 @@ import ( "bufio" "net" "net/http" - "path" "strings" "time" @@ -161,17 +160,17 @@ func (h cacheControlHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Adds verification for incoming paths. type minioPrivateBucketHandler struct { - handler http.Handler - reservedBucketPath string + handler http.Handler } func setPrivateBucketHandler(h http.Handler) http.Handler { - return minioPrivateBucketHandler{h, minioReservedBucketPath} + return minioPrivateBucketHandler{h} } func (h minioPrivateBucketHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - // For all non browser requests, reject access to 'reservedBucketPath'. - if !guessIsBrowserReq(r) && path.Clean(r.URL.Path) == h.reservedBucketPath { + // For all non browser requests, reject access to 'minioReservedBucketPath'. + bucketName, _ := urlPath2BucketObjectName(r.URL) + if !guessIsBrowserReq(r) && isMinioReservedBucket(bucketName) && isMinioMetaBucket(bucketName) { writeErrorResponse(w, ErrAllAccessDisabled, r.URL) return } diff --git a/cmd/object-api-utils.go b/cmd/object-api-utils.go index 9c1878a23..40047657d 100644 --- a/cmd/object-api-utils.go +++ b/cmd/object-api-utils.go @@ -194,7 +194,17 @@ func isReservedOrInvalidBucket(bucketEntry string) bool { if !IsValidBucketName(bucketEntry) { return true } - return bucketEntry == minioMetaBucket || bucketEntry == minioReservedBucket + return isMinioMetaBucket(bucketEntry) || isMinioReservedBucket(bucketEntry) +} + +// Returns true if input bucket is a reserved minio meta bucket '.minio.sys'. +func isMinioMetaBucket(bucketName string) bool { + return bucketName == minioMetaBucket +} + +// Returns true if input bucket is a reserved minio bucket 'minio'. +func isMinioReservedBucket(bucketName string) bool { + return bucketName == minioReservedBucket } // byBucketName is a collection satisfying sort.Interface. diff --git a/cmd/typed-errors.go b/cmd/typed-errors.go index 5a7568568..4b561bf22 100644 --- a/cmd/typed-errors.go +++ b/cmd/typed-errors.go @@ -50,3 +50,7 @@ var errServerVersionMismatch = errors.New("Server versions do not match") // errServerTimeMismatch - server times are too far apart. var errServerTimeMismatch = errors.New("Server times are too far apart") + +// errReservedBucket - bucket name is reserved for Minio, usually +// returned for 'minio', '.minio.sys' +var errReservedBucket = errors.New("All access to this bucket is disabled") diff --git a/cmd/web-handlers.go b/cmd/web-handlers.go index 0170adc6a..cfe9cbb48 100644 --- a/cmd/web-handlers.go +++ b/cmd/web-handlers.go @@ -113,7 +113,7 @@ type MakeBucketArgs struct { BucketName string `json:"bucketName"` } -// MakeBucket - make a bucket. +// MakeBucket - creates a new bucket. func (web *webAPIHandlers) MakeBucket(r *http.Request, args *MakeBucketArgs, reply *WebGenericRep) error { objectAPI := web.ObjectAPI() if objectAPI == nil { @@ -122,12 +122,19 @@ func (web *webAPIHandlers) MakeBucket(r *http.Request, args *MakeBucketArgs, rep if !isHTTPRequestValid(r) { return toJSONError(errAuthentication) } + + // Check if bucket is a reserved bucket name. + if isMinioMetaBucket(args.BucketName) || isMinioReservedBucket(args.BucketName) { + return toJSONError(errReservedBucket) + } + bucketLock := globalNSMutex.NewNSLock(args.BucketName, "") bucketLock.Lock() defer bucketLock.Unlock() if err := objectAPI.MakeBucket(args.BucketName); err != nil { return toJSONError(err, args.BucketName) } + reply.UIVersion = browser.UIVersion return nil } @@ -890,6 +897,13 @@ func toJSONError(err error, params ...string) (jerr *json2.Error) { Message: apiErr.Description, } switch apiErr.Code { + // Reserved bucket name provided. + case "AllAccessDisabled": + if len(params) > 0 { + jerr = &json2.Error{ + Message: fmt.Sprintf("All access to this bucket %s has been disabled.", params[0]), + } + } // Bucket name invalid with custom error message. case "InvalidBucketName": if len(params) > 0 { @@ -961,6 +975,12 @@ func toWebAPIError(err error) APIError { HTTPStatusCode: http.StatusMethodNotAllowed, Description: err.Error(), } + } else if err == errReservedBucket { + return APIError{ + Code: "AllAccessDisabled", + HTTPStatusCode: http.StatusForbidden, + Description: err.Error(), + } } // Convert error type to api error code. var apiErrCode APIErrorCode diff --git a/cmd/web-handlers_test.go b/cmd/web-handlers_test.go index 15ec48a4f..5c33334ed 100644 --- a/cmd/web-handlers_test.go +++ b/cmd/web-handlers_test.go @@ -265,6 +265,8 @@ func testMakeBucketWebHandler(obj ObjectLayer, instanceType string, t TestErrHan {"", false}, {".", false}, {"ab", false}, + {"minio", false}, + {".minio.sys", false}, {bucketName, true}, }