1 /** **************************************************************************
4 * Copyright 2008 Bryan Ischo <bryan@ischo.com>
6 * This file is part of libs3.
8 * libs3 is free software: you can redistribute it and/or modify it under the
9 * terms of the GNU General Public License as published by the Free Software
10 * Foundation, version 3 of the License.
12 * In addition, as a special exception, the copyright holders give
13 * permission to link the code of this library and its programs with the
14 * OpenSSL library, and distribute linked combinations including the two.
16 * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY
17 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
21 * You should have received a copy of the GNU General Public License version 3
22 * along with libs3, in a file named COPYING. If not, see
23 * <http://www.gnu.org/licenses/>.
25 ************************************************************************** **/
30 #include "simplexml.h"
33 static int initializeCountG = 0;
35 S3Status S3_initialize(const char *userAgentInfo, int flags)
37 if (initializeCountG++) {
41 return request_api_initialize(userAgentInfo, flags);
45 void S3_deinitialize()
47 if (--initializeCountG) {
51 request_api_deinitialize();
54 const char *S3_get_status_name(S3Status status)
57 #define handlecase(s) \
62 handlecase(InternalError);
63 handlecase(OutOfMemory);
64 handlecase(Interrupted);
65 handlecase(InvalidBucketNameTooLong);
66 handlecase(InvalidBucketNameFirstCharacter);
67 handlecase(InvalidBucketNameCharacter);
68 handlecase(InvalidBucketNameCharacterSequence);
69 handlecase(InvalidBucketNameTooShort);
70 handlecase(InvalidBucketNameDotQuadNotation);
71 handlecase(QueryParamsTooLong);
72 handlecase(FailedToInitializeRequest);
73 handlecase(MetaDataHeadersTooLong);
74 handlecase(BadMetaData);
75 handlecase(BadContentType);
76 handlecase(ContentTypeTooLong);
78 handlecase(MD5TooLong);
79 handlecase(BadCacheControl);
80 handlecase(CacheControlTooLong);
81 handlecase(BadContentDispositionFilename);
82 handlecase(ContentDispositionFilenameTooLong);
83 handlecase(BadContentEncoding);
84 handlecase(ContentEncodingTooLong);
85 handlecase(BadIfMatchETag);
86 handlecase(IfMatchETagTooLong);
87 handlecase(BadIfNotMatchETag);
88 handlecase(IfNotMatchETagTooLong);
89 handlecase(HeadersTooLong);
90 handlecase(KeyTooLong);
91 handlecase(UriTooLong);
92 handlecase(XmlParseFailure);
93 handlecase(EmailAddressTooLong);
94 handlecase(UserIdTooLong);
95 handlecase(UserDisplayNameTooLong);
96 handlecase(GroupUriTooLong);
97 handlecase(PermissionTooLong);
98 handlecase(TargetBucketTooLong);
99 handlecase(TargetPrefixTooLong);
100 handlecase(TooManyGrants);
101 handlecase(BadGrantee);
102 handlecase(BadPermission);
103 handlecase(XmlDocumentTooLarge);
104 handlecase(NameLookupError);
105 handlecase(FailedToConnect);
106 handlecase(ServerFailedVerification);
107 handlecase(ConnectionFailed);
108 handlecase(AbortedByCallback);
109 handlecase(ErrorAccessDenied);
110 handlecase(ErrorAccountProblem);
111 handlecase(ErrorAmbiguousGrantByEmailAddress);
112 handlecase(ErrorBadDigest);
113 handlecase(ErrorBucketAlreadyExists);
114 handlecase(ErrorBucketAlreadyOwnedByYou);
115 handlecase(ErrorBucketNotEmpty);
116 handlecase(ErrorCredentialsNotSupported);
117 handlecase(ErrorCrossLocationLoggingProhibited);
118 handlecase(ErrorEntityTooSmall);
119 handlecase(ErrorEntityTooLarge);
120 handlecase(ErrorExpiredToken);
121 handlecase(ErrorIncompleteBody);
122 handlecase(ErrorIncorrectNumberOfFilesInPostRequest);
123 handlecase(ErrorInlineDataTooLarge);
124 handlecase(ErrorInternalError);
125 handlecase(ErrorInvalidAccessKeyId);
126 handlecase(ErrorInvalidAddressingHeader);
127 handlecase(ErrorInvalidArgument);
128 handlecase(ErrorInvalidBucketName);
129 handlecase(ErrorInvalidDigest);
130 handlecase(ErrorInvalidLocationConstraint);
131 handlecase(ErrorInvalidPayer);
132 handlecase(ErrorInvalidPolicyDocument);
133 handlecase(ErrorInvalidRange);
134 handlecase(ErrorInvalidSecurity);
135 handlecase(ErrorInvalidSOAPRequest);
136 handlecase(ErrorInvalidStorageClass);
137 handlecase(ErrorInvalidTargetBucketForLogging);
138 handlecase(ErrorInvalidToken);
139 handlecase(ErrorInvalidURI);
140 handlecase(ErrorKeyTooLong);
141 handlecase(ErrorMalformedACLError);
142 handlecase(ErrorMalformedXML);
143 handlecase(ErrorMaxMessageLengthExceeded);
144 handlecase(ErrorMaxPostPreDataLengthExceededError);
145 handlecase(ErrorMetadataTooLarge);
146 handlecase(ErrorMethodNotAllowed);
147 handlecase(ErrorMissingAttachment);
148 handlecase(ErrorMissingContentLength);
149 handlecase(ErrorMissingSecurityElement);
150 handlecase(ErrorMissingSecurityHeader);
151 handlecase(ErrorNoLoggingStatusForKey);
152 handlecase(ErrorNoSuchBucket);
153 handlecase(ErrorNoSuchKey);
154 handlecase(ErrorNotImplemented);
155 handlecase(ErrorNotSignedUp);
156 handlecase(ErrorOperationAborted);
157 handlecase(ErrorPermanentRedirect);
158 handlecase(ErrorPreconditionFailed);
159 handlecase(ErrorRedirect);
160 handlecase(ErrorRequestIsNotMultiPartContent);
161 handlecase(ErrorRequestTimeout);
162 handlecase(ErrorRequestTimeTooSkewed);
163 handlecase(ErrorRequestTorrentOfBucketError);
164 handlecase(ErrorSignatureDoesNotMatch);
165 handlecase(ErrorSlowDown);
166 handlecase(ErrorTemporaryRedirect);
167 handlecase(ErrorTokenRefreshRequired);
168 handlecase(ErrorTooManyBuckets);
169 handlecase(ErrorUnexpectedContent);
170 handlecase(ErrorUnresolvableGrantByEmailAddress);
171 handlecase(ErrorUserKeyMustBeSpecified);
172 handlecase(ErrorUnknown);
173 handlecase(HttpErrorMovedTemporarily);
174 handlecase(HttpErrorBadRequest);
175 handlecase(HttpErrorForbidden);
176 handlecase(HttpErrorNotFound);
177 handlecase(HttpErrorConflict);
178 handlecase(HttpErrorUnknown);
185 S3Status S3_validate_bucket_name(const char *bucketName, S3UriStyle uriStyle)
187 int virtualHostStyle = (uriStyle == S3UriStyleVirtualHost);
188 int len = 0, maxlen = virtualHostStyle ? 63 : 255;
189 const char *b = bucketName;
196 return S3StatusInvalidBucketNameTooLong;
198 else if (isalpha(*b)) {
202 else if (isdigit(*b)) {
206 return S3StatusInvalidBucketNameFirstCharacter;
208 else if (*b == '_') {
209 /* Virtual host style bucket names cannot have underscores */
210 if (virtualHostStyle) {
211 return S3StatusInvalidBucketNameCharacter;
216 else if (*b == '-') {
217 /* Virtual host style bucket names cannot have .- */
218 if (virtualHostStyle && (b > bucketName) && (*(b - 1) == '.')) {
219 return S3StatusInvalidBucketNameCharacterSequence;
224 else if (*b == '.') {
225 /* Virtual host style bucket names cannot have -. */
226 if (virtualHostStyle && (b > bucketName) && (*(b - 1) == '-')) {
227 return S3StatusInvalidBucketNameCharacterSequence;
233 return S3StatusInvalidBucketNameCharacter;
238 return S3StatusInvalidBucketNameTooShort;
241 /* It's not clear from Amazon's documentation exactly what 'IP address
242 style' means. In its strictest sense, it could mean 'could be a valid
243 IP address', which would mean that 255.255.255.255 would be invalid,
244 wherase 256.256.256.256 would be valid. Or it could mean 'has 4 sets
245 of digits separated by dots'. Who knows. Let's just be really
246 conservative here: if it has any dots, and no non-digit characters,
248 if (hasDot && !hasNonDigit) {
249 return S3StatusInvalidBucketNameDotQuadNotation;
256 typedef struct ConvertAclData
260 char *ownerDisplayName;
261 int ownerDisplayNameLen;
262 int *aclGrantCountReturn;
263 S3AclGrant *aclGrants;
265 string_buffer(emailAddress, S3_MAX_GRANTEE_EMAIL_ADDRESS_SIZE);
266 string_buffer(userId, S3_MAX_GRANTEE_USER_ID_SIZE);
267 string_buffer(userDisplayName, S3_MAX_GRANTEE_DISPLAY_NAME_SIZE);
268 string_buffer(groupUri, 128);
269 string_buffer(permission, 32);
273 static S3Status convertAclXmlCallback(const char *elementPath,
274 const char *data, int dataLen,
277 ConvertAclData *caData = (ConvertAclData *) callbackData;
282 if (!strcmp(elementPath, "AccessControlPolicy/Owner/ID")) {
283 caData->ownerIdLen +=
284 snprintf(&(caData->ownerId[caData->ownerIdLen]),
285 S3_MAX_GRANTEE_USER_ID_SIZE - caData->ownerIdLen - 1,
286 "%.*s", dataLen, data);
287 if (caData->ownerIdLen >= S3_MAX_GRANTEE_USER_ID_SIZE) {
288 return S3StatusUserIdTooLong;
291 else if (!strcmp(elementPath, "AccessControlPolicy/Owner/"
293 caData->ownerDisplayNameLen +=
294 snprintf(&(caData->ownerDisplayName
295 [caData->ownerDisplayNameLen]),
296 S3_MAX_GRANTEE_DISPLAY_NAME_SIZE -
297 caData->ownerDisplayNameLen - 1,
298 "%.*s", dataLen, data);
299 if (caData->ownerDisplayNameLen >=
300 S3_MAX_GRANTEE_DISPLAY_NAME_SIZE) {
301 return S3StatusUserDisplayNameTooLong;
304 else if (!strcmp(elementPath,
305 "AccessControlPolicy/AccessControlList/Grant/"
306 "Grantee/EmailAddress")) {
307 // AmazonCustomerByEmail
308 string_buffer_append(caData->emailAddress, data, dataLen, fit);
310 return S3StatusEmailAddressTooLong;
313 else if (!strcmp(elementPath,
314 "AccessControlPolicy/AccessControlList/Grant/"
317 string_buffer_append(caData->userId, data, dataLen, fit);
319 return S3StatusUserIdTooLong;
322 else if (!strcmp(elementPath,
323 "AccessControlPolicy/AccessControlList/Grant/"
324 "Grantee/DisplayName")) {
326 string_buffer_append(caData->userDisplayName, data, dataLen, fit);
328 return S3StatusUserDisplayNameTooLong;
331 else if (!strcmp(elementPath,
332 "AccessControlPolicy/AccessControlList/Grant/"
335 string_buffer_append(caData->groupUri, data, dataLen, fit);
337 return S3StatusGroupUriTooLong;
340 else if (!strcmp(elementPath,
341 "AccessControlPolicy/AccessControlList/Grant/"
344 string_buffer_append(caData->permission, data, dataLen, fit);
346 return S3StatusPermissionTooLong;
351 if (!strcmp(elementPath, "AccessControlPolicy/AccessControlList/"
353 // A grant has just been completed; so add the next S3AclGrant
354 // based on the values read
355 if (*(caData->aclGrantCountReturn) == S3_MAX_ACL_GRANT_COUNT) {
356 return S3StatusTooManyGrants;
359 S3AclGrant *grant = &(caData->aclGrants
360 [*(caData->aclGrantCountReturn)]);
362 if (caData->emailAddress[0]) {
363 grant->granteeType = S3GranteeTypeAmazonCustomerByEmail;
364 strcpy(grant->grantee.amazonCustomerByEmail.emailAddress,
365 caData->emailAddress);
367 else if (caData->userId[0] && caData->userDisplayName[0]) {
368 grant->granteeType = S3GranteeTypeCanonicalUser;
369 strcpy(grant->grantee.canonicalUser.id, caData->userId);
370 strcpy(grant->grantee.canonicalUser.displayName,
371 caData->userDisplayName);
373 else if (caData->groupUri[0]) {
374 if (!strcmp(caData->groupUri,
375 "http://acs.amazonaws.com/groups/global/"
376 "AuthenticatedUsers")) {
377 grant->granteeType = S3GranteeTypeAllAwsUsers;
379 else if (!strcmp(caData->groupUri,
380 "http://acs.amazonaws.com/groups/global/"
382 grant->granteeType = S3GranteeTypeAllUsers;
384 else if (!strcmp(caData->groupUri,
385 "http://acs.amazonaws.com/groups/s3/"
387 grant->granteeType = S3GranteeTypeLogDelivery;
390 return S3StatusBadGrantee;
394 return S3StatusBadGrantee;
397 if (!strcmp(caData->permission, "READ")) {
398 grant->permission = S3PermissionRead;
400 else if (!strcmp(caData->permission, "WRITE")) {
401 grant->permission = S3PermissionWrite;
403 else if (!strcmp(caData->permission, "READ_ACP")) {
404 grant->permission = S3PermissionReadACP;
406 else if (!strcmp(caData->permission, "WRITE_ACP")) {
407 grant->permission = S3PermissionWriteACP;
409 else if (!strcmp(caData->permission, "FULL_CONTROL")) {
410 grant->permission = S3PermissionFullControl;
413 return S3StatusBadPermission;
416 (*(caData->aclGrantCountReturn))++;
418 string_buffer_initialize(caData->emailAddress);
419 string_buffer_initialize(caData->userId);
420 string_buffer_initialize(caData->userDisplayName);
421 string_buffer_initialize(caData->groupUri);
422 string_buffer_initialize(caData->permission);
430 S3Status S3_convert_acl(char *aclXml, char *ownerId, char *ownerDisplayName,
431 int *aclGrantCountReturn, S3AclGrant *aclGrants)
435 data.ownerId = ownerId;
438 data.ownerDisplayName = ownerDisplayName;
439 data.ownerDisplayNameLen = 0;
440 data.ownerDisplayName[0] = 0;
441 data.aclGrantCountReturn = aclGrantCountReturn;
442 data.aclGrants = aclGrants;
443 *aclGrantCountReturn = 0;
444 string_buffer_initialize(data.emailAddress);
445 string_buffer_initialize(data.userId);
446 string_buffer_initialize(data.userDisplayName);
447 string_buffer_initialize(data.groupUri);
448 string_buffer_initialize(data.permission);
450 // Use a simplexml parser
452 simplexml_initialize(&simpleXml, &convertAclXmlCallback, &data);
454 S3Status status = simplexml_add(&simpleXml, aclXml, strlen(aclXml));
456 simplexml_deinitialize(&simpleXml);
462 int S3_status_is_retryable(S3Status status)
465 case S3StatusNameLookupError:
466 case S3StatusFailedToConnect:
467 case S3StatusConnectionFailed:
468 case S3StatusErrorInternalError:
469 case S3StatusErrorOperationAborted:
470 case S3StatusErrorRequestTimeout: