| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608 |
- /** **************************************************************************
- * bucket_metadata.c
- *
- * Copyright 2008 Bryan Ischo <[email protected]>
- *
- * This file is part of libs3.
- *
- * libs3 is free software: you can redistribute it and/or modify it under the
- * terms of the GNU Lesser General Public License as published by the Free
- * Software Foundation, version 3 or above of the License. You can also
- * redistribute and/or modify it under the terms of the GNU General Public
- * License, version 2 or above 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 Lesser General Public License
- * version 3 along with libs3, in a file named COPYING. If not, see
- * <https://www.gnu.org/licenses/>.
- *
- * You should also have received a copy of the GNU General Public License
- * version 2 along with libs3, in a file named COPYING-GPLv2. If not, see
- * <https://www.gnu.org/licenses/>.
- *
- ************************************************************************** **/
- #include <stdlib.h>
- #include <string.h>
- #ifndef __APPLE__
- #include <openssl/md5.h>
- #include <openssl/bio.h>
- #include <openssl/evp.h>
- #include <openssl/buffer.h>
- #endif
- #include "libs3.h"
- #include "request.h"
- // Use a rather arbitrary max size for the document of 64K
- #define ACL_XML_DOC_MAXSIZE (64 * 1024)
- // get acl -------------------------------------------------------------------
- typedef struct GetAclData
- {
- SimpleXml simpleXml;
- S3ResponsePropertiesCallback *responsePropertiesCallback;
- S3ResponseCompleteCallback *responseCompleteCallback;
- void *callbackData;
- int *aclGrantCountReturn;
- S3AclGrant *aclGrants;
- char *ownerId;
- char *ownerDisplayName;
- string_buffer(xmlDocument, ACL_XML_DOC_MAXSIZE);
- } GetAclData;
- static S3Status getAclPropertiesCallback
- (const S3ResponseProperties *responseProperties, void *callbackData)
- {
- GetAclData *gaData = (GetAclData *) callbackData;
- return (*(gaData->responsePropertiesCallback))
- (responseProperties, gaData->callbackData);
- }
- static S3Status getAclDataCallback(int bufferSize, const char *buffer,
- void *callbackData)
- {
- GetAclData *gaData = (GetAclData *) callbackData;
- int fit;
- string_buffer_append(gaData->xmlDocument, buffer, bufferSize, fit);
- return fit ? S3StatusOK : S3StatusXmlDocumentTooLarge;
- }
- static void getAclCompleteCallback(S3Status requestStatus,
- const S3ErrorDetails *s3ErrorDetails,
- void *callbackData)
- {
- GetAclData *gaData = (GetAclData *) callbackData;
- if (requestStatus == S3StatusOK) {
- // Parse the document
- requestStatus = S3_convert_acl
- (gaData->xmlDocument, gaData->ownerId, gaData->ownerDisplayName,
- gaData->aclGrantCountReturn, gaData->aclGrants);
- }
- (*(gaData->responseCompleteCallback))
- (requestStatus, s3ErrorDetails, gaData->callbackData);
- free(gaData);
- }
- void S3_get_acl(const S3BucketContext *bucketContext, const char *key,
- char *ownerId, char *ownerDisplayName,
- int *aclGrantCountReturn, S3AclGrant *aclGrants,
- S3RequestContext *requestContext,
- int timeoutMs,
- const S3ResponseHandler *handler, void *callbackData)
- {
- // Create the callback data
- GetAclData *gaData = (GetAclData *) malloc(sizeof(GetAclData));
- if (!gaData) {
- (*(handler->completeCallback))(S3StatusOutOfMemory, 0, callbackData);
- return;
- }
- gaData->responsePropertiesCallback = handler->propertiesCallback;
- gaData->responseCompleteCallback = handler->completeCallback;
- gaData->callbackData = callbackData;
- gaData->aclGrantCountReturn = aclGrantCountReturn;
- gaData->aclGrants = aclGrants;
- gaData->ownerId = ownerId;
- gaData->ownerDisplayName = ownerDisplayName;
- string_buffer_initialize(gaData->xmlDocument);
- *aclGrantCountReturn = 0;
- // Set up the RequestParams
- RequestParams params =
- {
- HttpRequestTypeGET, // httpRequestType
- { bucketContext->hostName, // hostName
- bucketContext->bucketName, // bucketName
- bucketContext->protocol, // protocol
- bucketContext->uriStyle, // uriStyle
- bucketContext->accessKeyId, // accessKeyId
- bucketContext->secretAccessKey, // secretAccessKey
- bucketContext->securityToken, // securityToken
- bucketContext->authRegion }, // authRegion
- key, // key
- 0, // queryParams
- "acl", // subResource
- 0, // copySourceBucketName
- 0, // copySourceKey
- 0, // getConditions
- 0, // startByte
- 0, // byteCount
- 0, // putProperties
- &getAclPropertiesCallback, // propertiesCallback
- 0, // toS3Callback
- 0, // toS3CallbackTotalSize
- &getAclDataCallback, // fromS3Callback
- &getAclCompleteCallback, // completeCallback
- gaData, // callbackData
- timeoutMs // timeoutMs
- };
- // Perform the request
- request_perform(¶ms, requestContext);
- }
- // set acl -------------------------------------------------------------------
- static S3Status generateAclXmlDocument(const char *ownerId,
- const char *ownerDisplayName,
- int aclGrantCount,
- const S3AclGrant *aclGrants,
- int *xmlDocumentLenReturn,
- char *xmlDocument,
- int xmlDocumentBufferSize)
- {
- *xmlDocumentLenReturn = 0;
- #define append(fmt, ...) \
- do { \
- *xmlDocumentLenReturn += snprintf \
- (&(xmlDocument[*xmlDocumentLenReturn]), \
- xmlDocumentBufferSize - *xmlDocumentLenReturn - 1, \
- fmt, __VA_ARGS__); \
- if (*xmlDocumentLenReturn >= xmlDocumentBufferSize) { \
- return S3StatusXmlDocumentTooLarge; \
- } \
- } while (0)
- append("<AccessControlPolicy><Owner><ID>%s</ID><DisplayName>%s"
- "</DisplayName></Owner><AccessControlList>", ownerId,
- ownerDisplayName);
- int i;
- for (i = 0; i < aclGrantCount; i++) {
- append("%s", "<Grant><Grantee xmlns:xsi=\"http://www.w3.org/2001/"
- "XMLSchema-instance\" xsi:type=\"");
- const S3AclGrant *grant = &(aclGrants[i]);
- switch (grant->granteeType) {
- case S3GranteeTypeAmazonCustomerByEmail:
- append("AmazonCustomerByEmail\"><EmailAddress>%s</EmailAddress>",
- grant->grantee.amazonCustomerByEmail.emailAddress);
- break;
- case S3GranteeTypeCanonicalUser:
- append("CanonicalUser\"><ID>%s</ID><DisplayName>%s</DisplayName>",
- grant->grantee.canonicalUser.id,
- grant->grantee.canonicalUser.displayName);
- break;
- default: { // case S3GranteeTypeAllAwsUsers/S3GranteeTypeAllUsers:
- const char *grantee;
- switch (grant->granteeType) {
- case S3GranteeTypeAllAwsUsers:
- grantee = ACS_GROUP_AWS_USERS;
- break;
- case S3GranteeTypeAllUsers:
- grantee = ACS_GROUP_ALL_USERS;
- break;
- default:
- grantee = ACS_GROUP_LOG_DELIVERY;
- break;
- }
- append("Group\"><URI>%s</URI>", grantee);
- }
- break;
- }
- append("</Grantee><Permission>%s</Permission></Grant>",
- ((grant->permission == S3PermissionRead) ? "READ" :
- (grant->permission == S3PermissionWrite) ? "WRITE" :
- (grant->permission == S3PermissionReadACP) ? "READ_ACP" :
- (grant->permission == S3PermissionWriteACP) ? "WRITE_ACP" :
- "FULL_CONTROL"));
- }
- append("%s", "</AccessControlList></AccessControlPolicy>");
- return S3StatusOK;
- }
- typedef struct SetXmlData
- {
- S3ResponsePropertiesCallback *responsePropertiesCallback;
- S3ResponseCompleteCallback *responseCompleteCallback;
- void *callbackData;
- int xmlDocumentLen;
- const char *xmlDocument;
- int xmlDocumentBytesWritten;
- } SetXmlData;
- static S3Status setXmlPropertiesCallback
- (const S3ResponseProperties *responseProperties, void *callbackData)
- {
- SetXmlData *paData = (SetXmlData *) callbackData;
- return (*(paData->responsePropertiesCallback))
- (responseProperties, paData->callbackData);
- }
- static int setXmlDataCallback(int bufferSize, char *buffer, void *callbackData)
- {
- SetXmlData *paData = (SetXmlData *) callbackData;
- int remaining = (paData->xmlDocumentLen -
- paData->xmlDocumentBytesWritten);
- int toCopy = bufferSize > remaining ? remaining : bufferSize;
- if (!toCopy) {
- return 0;
- }
- memcpy(buffer, &(paData->xmlDocument
- [paData->xmlDocumentBytesWritten]), toCopy);
- paData->xmlDocumentBytesWritten += toCopy;
- return toCopy;
- }
- static void setXmlCompleteCallback(S3Status requestStatus,
- const S3ErrorDetails *s3ErrorDetails,
- void *callbackData)
- {
- SetXmlData *paData = (SetXmlData *) callbackData;
- (*(paData->responseCompleteCallback))
- (requestStatus, s3ErrorDetails, paData->callbackData);
- free(paData);
- }
- void S3_set_acl(const S3BucketContext *bucketContext, const char *key,
- const char *ownerId, const char *ownerDisplayName,
- int aclGrantCount, const S3AclGrant *aclGrants,
- S3RequestContext *requestContext,
- int timeoutMs,
- const S3ResponseHandler *handler, void *callbackData)
- {
- char aclBuffer[ACL_XML_DOC_MAXSIZE];
- if (aclGrantCount > S3_MAX_ACL_GRANT_COUNT) {
- (*(handler->completeCallback))
- (S3StatusTooManyGrants, 0, callbackData);
- return;
- }
- SetXmlData *data = (SetXmlData *) malloc(sizeof(SetXmlData));
- if (!data) {
- (*(handler->completeCallback))(S3StatusOutOfMemory, 0, callbackData);
- return;
- }
- data->xmlDocument = aclBuffer;
- // Convert aclGrants to XML document
- S3Status status = generateAclXmlDocument
- (ownerId, ownerDisplayName, aclGrantCount, aclGrants,
- &(data->xmlDocumentLen), aclBuffer,
- sizeof(aclBuffer));
- if (status != S3StatusOK) {
- free(data);
- (*(handler->completeCallback))(status, 0, callbackData);
- return;
- }
- data->responsePropertiesCallback = handler->propertiesCallback;
- data->responseCompleteCallback = handler->completeCallback;
- data->callbackData = callbackData;
- data->xmlDocumentBytesWritten = 0;
- // Set up the RequestParams
- RequestParams params =
- {
- HttpRequestTypePUT, // httpRequestType
- { bucketContext->hostName, // hostName
- bucketContext->bucketName, // bucketName
- bucketContext->protocol, // protocol
- bucketContext->uriStyle, // uriStyle
- bucketContext->accessKeyId, // accessKeyId
- bucketContext->secretAccessKey, // secretAccessKey
- bucketContext->securityToken, // securityToken
- bucketContext->authRegion }, // authRegion
- key, // key
- 0, // queryParams
- "acl", // subResource
- 0, // copySourceBucketName
- 0, // copySourceKey
- 0, // getConditions
- 0, // startByte
- 0, // byteCount
- 0, // putProperties
- &setXmlPropertiesCallback, // propertiesCallback
- &setXmlDataCallback, // toS3Callback
- data->xmlDocumentLen, // toS3CallbackTotalSize
- 0, // fromS3Callback
- &setXmlCompleteCallback, // completeCallback
- data, // callbackData
- timeoutMs // timeoutMs
- };
- // Perform the request
- request_perform(¶ms, requestContext);
- }
- // get lifecycle -------------------------------------------------------------------
- typedef struct GetLifecycleData
- {
- S3ResponsePropertiesCallback *responsePropertiesCallback;
- S3ResponseCompleteCallback *responseCompleteCallback;
- void *callbackData;
- char *lifecycleXmlDocumentReturn;
- int lifecycleXmlDocumentBufferSize;
- int lifecycleXmlDocumentWritten;
- } GetLifecycleData;
- static S3Status getLifecyclePropertiesCallback
- (const S3ResponseProperties *responseProperties, void *callbackData)
- {
- GetLifecycleData *gaData = (GetLifecycleData *) callbackData;
- return (*(gaData->responsePropertiesCallback))
- (responseProperties, gaData->callbackData);
- }
- static S3Status getLifecycleDataCallback(int bufferSize, const char *buffer,
- void *callbackData)
- {
- GetLifecycleData *gaData = (GetLifecycleData *) callbackData;
- if ((gaData->lifecycleXmlDocumentWritten + bufferSize) >= gaData->lifecycleXmlDocumentBufferSize)
- return S3StatusXmlDocumentTooLarge;
- snprintf(gaData->lifecycleXmlDocumentReturn + gaData->lifecycleXmlDocumentWritten, bufferSize + 1, "%s", buffer);
- gaData->lifecycleXmlDocumentWritten += bufferSize;
- return S3StatusOK;
- }
- static void getLifecycleCompleteCallback(S3Status requestStatus,
- const S3ErrorDetails *s3ErrorDetails,
- void *callbackData)
- {
- GetLifecycleData *gaData = (GetLifecycleData *) callbackData;
- (*(gaData->responseCompleteCallback))
- (requestStatus, s3ErrorDetails, gaData->callbackData);
- free(gaData);
- }
- void S3_get_lifecycle(const S3BucketContext *bucketContext,
- char *lifecycleXmlDocumentReturn, int lifecycleXmlDocumentBufferSize,
- S3RequestContext *requestContext,
- int timeoutMs,
- const S3ResponseHandler *handler, void *callbackData)
- {
- // Create the callback data
- GetLifecycleData *gaData = (GetLifecycleData *) malloc(sizeof(GetLifecycleData));
- if (!gaData) {
- (*(handler->completeCallback))(S3StatusOutOfMemory, 0, callbackData);
- return;
- }
- gaData->responsePropertiesCallback = handler->propertiesCallback;
- gaData->responseCompleteCallback = handler->completeCallback;
- gaData->callbackData = callbackData;
- gaData->lifecycleXmlDocumentReturn = lifecycleXmlDocumentReturn;
- gaData->lifecycleXmlDocumentBufferSize = lifecycleXmlDocumentBufferSize;
- gaData->lifecycleXmlDocumentWritten = 0;
- // Set up the RequestParams
- RequestParams params =
- {
- HttpRequestTypeGET, // httpRequestType
- { bucketContext->hostName, // hostName
- bucketContext->bucketName, // bucketName
- bucketContext->protocol, // protocol
- bucketContext->uriStyle, // uriStyle
- bucketContext->accessKeyId, // accessKeyId
- bucketContext->secretAccessKey, // secretAccessKey
- bucketContext->securityToken, // securityToken
- bucketContext->authRegion }, // authRegion
- 0, // key
- 0, // queryParams
- "lifecycle", // subResource
- 0, // copySourceBucketName
- 0, // copySourceKey
- 0, // getConditions
- 0, // startByte
- 0, // byteCount
- 0, // putProperties
- &getLifecyclePropertiesCallback, // propertiesCallback
- 0, // toS3Callback
- 0, // toS3CallbackTotalSize
- &getLifecycleDataCallback, // fromS3Callback
- &getLifecycleCompleteCallback, // completeCallback
- gaData, // callbackData
- timeoutMs // timeoutMs
- };
- // Perform the request
- request_perform(¶ms, requestContext);
- }
- #ifndef __APPLE__
- // Calculate MD5 and encode it as base64
- void generate_content_md5(const char* data, int size,
- char* retBuffer, int retBufferSize) {
- MD5_CTX mdContext;
- BIO *bio, *b64;
- BUF_MEM *bufferPtr;
- char md5Buffer[MD5_DIGEST_LENGTH];
- MD5_Init(&mdContext);
- MD5_Update(&mdContext, data, size);
- MD5_Final((unsigned char*)md5Buffer, &mdContext);
- b64 = BIO_new(BIO_f_base64());
- bio = BIO_new(BIO_s_mem());
- bio = BIO_push(b64, bio);
- BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); //Ignore newlines - write everything in one line
- BIO_write(bio, md5Buffer, sizeof(md5Buffer));
- (void) BIO_flush(bio);
- BIO_get_mem_ptr(bio, &bufferPtr);
- (void) BIO_set_close(bio, BIO_NOCLOSE);
- if ((unsigned int)retBufferSize + 1 < bufferPtr->length) {
- retBuffer[0] = '\0';
- BIO_free_all(bio);
- return;
- }
- memcpy(retBuffer, bufferPtr->data, bufferPtr->length);
- retBuffer[bufferPtr->length] = '\0';
- BIO_free_all(bio);
- }
- #endif
- void S3_set_lifecycle(const S3BucketContext *bucketContext,
- const char *lifecycleXmlDocument,
- S3RequestContext *requestContext,
- int timeoutMs,
- const S3ResponseHandler *handler, void *callbackData)
- {
- #ifdef __APPLE__
- /* This request requires calculating MD5 sum.
- * MD5 sum requires OpenSSL library, which is not used on Apple.
- * TODO Implement some MD5+Base64 caculation on Apple
- */
- (*(handler->completeCallback))(S3StatusNotSupported, 0, callbackData);
- return;
- #else
- char md5Base64[MD5_DIGEST_LENGTH * 2];
- SetXmlData *data = (SetXmlData *) malloc(sizeof(SetXmlData));
- if (!data) {
- (*(handler->completeCallback))(S3StatusOutOfMemory, 0, callbackData);
- return;
- }
- data->xmlDocument = lifecycleXmlDocument;
- data->xmlDocumentLen = strlen(lifecycleXmlDocument);
- data->responsePropertiesCallback = handler->propertiesCallback;
- data->responseCompleteCallback = handler->completeCallback;
- data->callbackData = callbackData;
- data->xmlDocumentBytesWritten = 0;
- generate_content_md5(data->xmlDocument, data->xmlDocumentLen,
- md5Base64, sizeof (md5Base64));
- // Set up S3PutProperties
- S3PutProperties properties =
- {
- 0, // contentType
- md5Base64, // md5
- 0, // cacheControl
- 0, // contentDispositionFilename
- 0, // contentEncoding
- -1, // expires
- (S3CannedAcl)0, // cannedAcl WINSCP (cast)
- 0, // metaDataCount
- 0, // metaData
- 0 // useServerSideEncryption
- };
- // Set up the RequestParams
- RequestParams params =
- {
- HttpRequestTypePUT, // httpRequestType
- { bucketContext->hostName, // hostName
- bucketContext->bucketName, // bucketName
- bucketContext->protocol, // protocol
- bucketContext->uriStyle, // uriStyle
- bucketContext->accessKeyId, // accessKeyId
- bucketContext->secretAccessKey, // secretAccessKey
- bucketContext->securityToken, // securityToken
- bucketContext->authRegion }, // authRegion
- 0, // key
- 0, // queryParams
- "lifecycle", // subResource
- 0, // copySourceBucketName
- 0, // copySourceKey
- 0, // getConditions
- 0, // startByte
- 0, // byteCount
- &properties, // putProperties
- &setXmlPropertiesCallback, // propertiesCallback
- &setXmlDataCallback, // toS3Callback
- data->xmlDocumentLen, // toS3CallbackTotalSize
- 0, // fromS3Callback
- &setXmlCompleteCallback, // completeCallback
- data, // callbackData
- timeoutMs // timeoutMs
- };
- // Perform the request
- request_perform(¶ms, requestContext);
- #endif
- }
|