+++ /dev/null
-/** **************************************************************************
- * general.c
- *
- * Copyright 2008 Bryan Ischo <bryan@ischo.com>
- *
- * This file is part of libs3.
- *
- * libs3 is free software: you can redistribute it and/or modify it under the
- * terms of the GNU General Public License as published by the Free Software
- * Foundation, version 3 of the License.
- *
- * In addition, as a special exception, the copyright holders give
- * permission to link the code of this library and its programs with the
- * OpenSSL library, and distribute linked combinations including the two.
- *
- * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License version 3
- * along with libs3, in a file named COPYING. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- ************************************************************************** **/
-
-#include <ctype.h>
-#include <string.h>
-#include "request.h"
-#include "simplexml.h"
-#include "util.h"
-
-static int initializeCountG = 0;
-
-S3Status S3_initialize(const char *userAgentInfo, int flags)
-{
- if (initializeCountG++) {
- return S3StatusOK;
- }
-
- return request_api_initialize(userAgentInfo, flags);
-}
-
-
-void S3_deinitialize()
-{
- if (--initializeCountG) {
- return;
- }
-
- request_api_deinitialize();
-}
-
-const char *S3_get_status_name(S3Status status)
-{
- switch (status) {
-#define handlecase(s) \
- case S3Status##s: \
- return #s
-
- handlecase(OK);
- handlecase(InternalError);
- handlecase(OutOfMemory);
- handlecase(Interrupted);
- handlecase(InvalidBucketNameTooLong);
- handlecase(InvalidBucketNameFirstCharacter);
- handlecase(InvalidBucketNameCharacter);
- handlecase(InvalidBucketNameCharacterSequence);
- handlecase(InvalidBucketNameTooShort);
- handlecase(InvalidBucketNameDotQuadNotation);
- handlecase(QueryParamsTooLong);
- handlecase(FailedToInitializeRequest);
- handlecase(MetaDataHeadersTooLong);
- handlecase(BadMetaData);
- handlecase(BadContentType);
- handlecase(ContentTypeTooLong);
- handlecase(BadMD5);
- handlecase(MD5TooLong);
- handlecase(BadCacheControl);
- handlecase(CacheControlTooLong);
- handlecase(BadContentDispositionFilename);
- handlecase(ContentDispositionFilenameTooLong);
- handlecase(BadContentEncoding);
- handlecase(ContentEncodingTooLong);
- handlecase(BadIfMatchETag);
- handlecase(IfMatchETagTooLong);
- handlecase(BadIfNotMatchETag);
- handlecase(IfNotMatchETagTooLong);
- handlecase(HeadersTooLong);
- handlecase(KeyTooLong);
- handlecase(UriTooLong);
- handlecase(XmlParseFailure);
- handlecase(EmailAddressTooLong);
- handlecase(UserIdTooLong);
- handlecase(UserDisplayNameTooLong);
- handlecase(GroupUriTooLong);
- handlecase(PermissionTooLong);
- handlecase(TargetBucketTooLong);
- handlecase(TargetPrefixTooLong);
- handlecase(TooManyGrants);
- handlecase(BadGrantee);
- handlecase(BadPermission);
- handlecase(XmlDocumentTooLarge);
- handlecase(NameLookupError);
- handlecase(FailedToConnect);
- handlecase(ServerFailedVerification);
- handlecase(ConnectionFailed);
- handlecase(AbortedByCallback);
- handlecase(ErrorAccessDenied);
- handlecase(ErrorAccountProblem);
- handlecase(ErrorAmbiguousGrantByEmailAddress);
- handlecase(ErrorBadDigest);
- handlecase(ErrorBucketAlreadyExists);
- handlecase(ErrorBucketAlreadyOwnedByYou);
- handlecase(ErrorBucketNotEmpty);
- handlecase(ErrorCredentialsNotSupported);
- handlecase(ErrorCrossLocationLoggingProhibited);
- handlecase(ErrorEntityTooSmall);
- handlecase(ErrorEntityTooLarge);
- handlecase(ErrorExpiredToken);
- handlecase(ErrorIncompleteBody);
- handlecase(ErrorIncorrectNumberOfFilesInPostRequest);
- handlecase(ErrorInlineDataTooLarge);
- handlecase(ErrorInternalError);
- handlecase(ErrorInvalidAccessKeyId);
- handlecase(ErrorInvalidAddressingHeader);
- handlecase(ErrorInvalidArgument);
- handlecase(ErrorInvalidBucketName);
- handlecase(ErrorInvalidDigest);
- handlecase(ErrorInvalidLocationConstraint);
- handlecase(ErrorInvalidPayer);
- handlecase(ErrorInvalidPolicyDocument);
- handlecase(ErrorInvalidRange);
- handlecase(ErrorInvalidSecurity);
- handlecase(ErrorInvalidSOAPRequest);
- handlecase(ErrorInvalidStorageClass);
- handlecase(ErrorInvalidTargetBucketForLogging);
- handlecase(ErrorInvalidToken);
- handlecase(ErrorInvalidURI);
- handlecase(ErrorKeyTooLong);
- handlecase(ErrorMalformedACLError);
- handlecase(ErrorMalformedXML);
- handlecase(ErrorMaxMessageLengthExceeded);
- handlecase(ErrorMaxPostPreDataLengthExceededError);
- handlecase(ErrorMetadataTooLarge);
- handlecase(ErrorMethodNotAllowed);
- handlecase(ErrorMissingAttachment);
- handlecase(ErrorMissingContentLength);
- handlecase(ErrorMissingSecurityElement);
- handlecase(ErrorMissingSecurityHeader);
- handlecase(ErrorNoLoggingStatusForKey);
- handlecase(ErrorNoSuchBucket);
- handlecase(ErrorNoSuchKey);
- handlecase(ErrorNotImplemented);
- handlecase(ErrorNotSignedUp);
- handlecase(ErrorOperationAborted);
- handlecase(ErrorPermanentRedirect);
- handlecase(ErrorPreconditionFailed);
- handlecase(ErrorRedirect);
- handlecase(ErrorRequestIsNotMultiPartContent);
- handlecase(ErrorRequestTimeout);
- handlecase(ErrorRequestTimeTooSkewed);
- handlecase(ErrorRequestTorrentOfBucketError);
- handlecase(ErrorSignatureDoesNotMatch);
- handlecase(ErrorSlowDown);
- handlecase(ErrorTemporaryRedirect);
- handlecase(ErrorTokenRefreshRequired);
- handlecase(ErrorTooManyBuckets);
- handlecase(ErrorUnexpectedContent);
- handlecase(ErrorUnresolvableGrantByEmailAddress);
- handlecase(ErrorUserKeyMustBeSpecified);
- handlecase(ErrorUnknown);
- handlecase(HttpErrorMovedTemporarily);
- handlecase(HttpErrorBadRequest);
- handlecase(HttpErrorForbidden);
- handlecase(HttpErrorNotFound);
- handlecase(HttpErrorConflict);
- handlecase(HttpErrorUnknown);
- }
-
- return "Unknown";
-}
-
-
-S3Status S3_validate_bucket_name(const char *bucketName, S3UriStyle uriStyle)
-{
- int virtualHostStyle = (uriStyle == S3UriStyleVirtualHost);
- int len = 0, maxlen = virtualHostStyle ? 63 : 255;
- const char *b = bucketName;
-
- int hasDot = 0;
- int hasNonDigit = 0;
-
- while (*b) {
- if (len == maxlen) {
- return S3StatusInvalidBucketNameTooLong;
- }
- else if (isalpha(*b)) {
- len++, b++;
- hasNonDigit = 1;
- }
- else if (isdigit(*b)) {
- len++, b++;
- }
- else if (len == 0) {
- return S3StatusInvalidBucketNameFirstCharacter;
- }
- else if (*b == '_') {
- /* Virtual host style bucket names cannot have underscores */
- if (virtualHostStyle) {
- return S3StatusInvalidBucketNameCharacter;
- }
- len++, b++;
- hasNonDigit = 1;
- }
- else if (*b == '-') {
- /* Virtual host style bucket names cannot have .- */
- if (virtualHostStyle && (b > bucketName) && (*(b - 1) == '.')) {
- return S3StatusInvalidBucketNameCharacterSequence;
- }
- len++, b++;
- hasNonDigit = 1;
- }
- else if (*b == '.') {
- /* Virtual host style bucket names cannot have -. */
- if (virtualHostStyle && (b > bucketName) && (*(b - 1) == '-')) {
- return S3StatusInvalidBucketNameCharacterSequence;
- }
- len++, b++;
- hasDot = 1;
- }
- else {
- return S3StatusInvalidBucketNameCharacter;
- }
- }
-
- if (len < 3) {
- return S3StatusInvalidBucketNameTooShort;
- }
-
- /* It's not clear from Amazon's documentation exactly what 'IP address
- style' means. In its strictest sense, it could mean 'could be a valid
- IP address', which would mean that 255.255.255.255 would be invalid,
- wherase 256.256.256.256 would be valid. Or it could mean 'has 4 sets
- of digits separated by dots'. Who knows. Let's just be really
- conservative here: if it has any dots, and no non-digit characters,
- then we reject it */
- if (hasDot && !hasNonDigit) {
- return S3StatusInvalidBucketNameDotQuadNotation;
- }
-
- return S3StatusOK;
-}
-
-
-typedef struct ConvertAclData
-{
- char *ownerId;
- int ownerIdLen;
- char *ownerDisplayName;
- int ownerDisplayNameLen;
- int *aclGrantCountReturn;
- S3AclGrant *aclGrants;
-
- string_buffer(emailAddress, S3_MAX_GRANTEE_EMAIL_ADDRESS_SIZE);
- string_buffer(userId, S3_MAX_GRANTEE_USER_ID_SIZE);
- string_buffer(userDisplayName, S3_MAX_GRANTEE_DISPLAY_NAME_SIZE);
- string_buffer(groupUri, 128);
- string_buffer(permission, 32);
-} ConvertAclData;
-
-
-static S3Status convertAclXmlCallback(const char *elementPath,
- const char *data, int dataLen,
- void *callbackData)
-{
- ConvertAclData *caData = (ConvertAclData *) callbackData;
-
- int fit;
-
- if (data) {
- if (!strcmp(elementPath, "AccessControlPolicy/Owner/ID")) {
- caData->ownerIdLen +=
- snprintf(&(caData->ownerId[caData->ownerIdLen]),
- S3_MAX_GRANTEE_USER_ID_SIZE - caData->ownerIdLen - 1,
- "%.*s", dataLen, data);
- if (caData->ownerIdLen >= S3_MAX_GRANTEE_USER_ID_SIZE) {
- return S3StatusUserIdTooLong;
- }
- }
- else if (!strcmp(elementPath, "AccessControlPolicy/Owner/"
- "DisplayName")) {
- caData->ownerDisplayNameLen +=
- snprintf(&(caData->ownerDisplayName
- [caData->ownerDisplayNameLen]),
- S3_MAX_GRANTEE_DISPLAY_NAME_SIZE -
- caData->ownerDisplayNameLen - 1,
- "%.*s", dataLen, data);
- if (caData->ownerDisplayNameLen >=
- S3_MAX_GRANTEE_DISPLAY_NAME_SIZE) {
- return S3StatusUserDisplayNameTooLong;
- }
- }
- else if (!strcmp(elementPath,
- "AccessControlPolicy/AccessControlList/Grant/"
- "Grantee/EmailAddress")) {
- // AmazonCustomerByEmail
- string_buffer_append(caData->emailAddress, data, dataLen, fit);
- if (!fit) {
- return S3StatusEmailAddressTooLong;
- }
- }
- else if (!strcmp(elementPath,
- "AccessControlPolicy/AccessControlList/Grant/"
- "Grantee/ID")) {
- // CanonicalUser
- string_buffer_append(caData->userId, data, dataLen, fit);
- if (!fit) {
- return S3StatusUserIdTooLong;
- }
- }
- else if (!strcmp(elementPath,
- "AccessControlPolicy/AccessControlList/Grant/"
- "Grantee/DisplayName")) {
- // CanonicalUser
- string_buffer_append(caData->userDisplayName, data, dataLen, fit);
- if (!fit) {
- return S3StatusUserDisplayNameTooLong;
- }
- }
- else if (!strcmp(elementPath,
- "AccessControlPolicy/AccessControlList/Grant/"
- "Grantee/URI")) {
- // Group
- string_buffer_append(caData->groupUri, data, dataLen, fit);
- if (!fit) {
- return S3StatusGroupUriTooLong;
- }
- }
- else if (!strcmp(elementPath,
- "AccessControlPolicy/AccessControlList/Grant/"
- "Permission")) {
- // Permission
- string_buffer_append(caData->permission, data, dataLen, fit);
- if (!fit) {
- return S3StatusPermissionTooLong;
- }
- }
- }
- else {
- if (!strcmp(elementPath, "AccessControlPolicy/AccessControlList/"
- "Grant")) {
- // A grant has just been completed; so add the next S3AclGrant
- // based on the values read
- if (*(caData->aclGrantCountReturn) == S3_MAX_ACL_GRANT_COUNT) {
- return S3StatusTooManyGrants;
- }
-
- S3AclGrant *grant = &(caData->aclGrants
- [*(caData->aclGrantCountReturn)]);
-
- if (caData->emailAddress[0]) {
- grant->granteeType = S3GranteeTypeAmazonCustomerByEmail;
- strcpy(grant->grantee.amazonCustomerByEmail.emailAddress,
- caData->emailAddress);
- }
- else if (caData->userId[0] && caData->userDisplayName[0]) {
- grant->granteeType = S3GranteeTypeCanonicalUser;
- strcpy(grant->grantee.canonicalUser.id, caData->userId);
- strcpy(grant->grantee.canonicalUser.displayName,
- caData->userDisplayName);
- }
- else if (caData->groupUri[0]) {
- if (!strcmp(caData->groupUri,
- "http://acs.amazonaws.com/groups/global/"
- "AuthenticatedUsers")) {
- grant->granteeType = S3GranteeTypeAllAwsUsers;
- }
- else if (!strcmp(caData->groupUri,
- "http://acs.amazonaws.com/groups/global/"
- "AllUsers")) {
- grant->granteeType = S3GranteeTypeAllUsers;
- }
- else if (!strcmp(caData->groupUri,
- "http://acs.amazonaws.com/groups/s3/"
- "LogDelivery")) {
- grant->granteeType = S3GranteeTypeLogDelivery;
- }
- else {
- return S3StatusBadGrantee;
- }
- }
- else {
- return S3StatusBadGrantee;
- }
-
- if (!strcmp(caData->permission, "READ")) {
- grant->permission = S3PermissionRead;
- }
- else if (!strcmp(caData->permission, "WRITE")) {
- grant->permission = S3PermissionWrite;
- }
- else if (!strcmp(caData->permission, "READ_ACP")) {
- grant->permission = S3PermissionReadACP;
- }
- else if (!strcmp(caData->permission, "WRITE_ACP")) {
- grant->permission = S3PermissionWriteACP;
- }
- else if (!strcmp(caData->permission, "FULL_CONTROL")) {
- grant->permission = S3PermissionFullControl;
- }
- else {
- return S3StatusBadPermission;
- }
-
- (*(caData->aclGrantCountReturn))++;
-
- string_buffer_initialize(caData->emailAddress);
- string_buffer_initialize(caData->userId);
- string_buffer_initialize(caData->userDisplayName);
- string_buffer_initialize(caData->groupUri);
- string_buffer_initialize(caData->permission);
- }
- }
-
- return S3StatusOK;
-}
-
-
-S3Status S3_convert_acl(char *aclXml, char *ownerId, char *ownerDisplayName,
- int *aclGrantCountReturn, S3AclGrant *aclGrants)
-{
- ConvertAclData data;
-
- data.ownerId = ownerId;
- data.ownerIdLen = 0;
- data.ownerId[0] = 0;
- data.ownerDisplayName = ownerDisplayName;
- data.ownerDisplayNameLen = 0;
- data.ownerDisplayName[0] = 0;
- data.aclGrantCountReturn = aclGrantCountReturn;
- data.aclGrants = aclGrants;
- *aclGrantCountReturn = 0;
- string_buffer_initialize(data.emailAddress);
- string_buffer_initialize(data.userId);
- string_buffer_initialize(data.userDisplayName);
- string_buffer_initialize(data.groupUri);
- string_buffer_initialize(data.permission);
-
- // Use a simplexml parser
- SimpleXml simpleXml;
- simplexml_initialize(&simpleXml, &convertAclXmlCallback, &data);
-
- S3Status status = simplexml_add(&simpleXml, aclXml, strlen(aclXml));
-
- simplexml_deinitialize(&simpleXml);
-
- return status;
-}
-
-
-int S3_status_is_retryable(S3Status status)
-{
- switch (status) {
- case S3StatusNameLookupError:
- case S3StatusFailedToConnect:
- case S3StatusConnectionFailed:
- case S3StatusErrorInternalError:
- case S3StatusErrorOperationAborted:
- case S3StatusErrorRequestTimeout:
- return 1;
- default:
- return 0;
- }
-}