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 ************************************************************************** **/
32 // Use a rather arbitrary max size for the document of 64K
33 #define ACL_XML_DOC_MAXSIZE (64 * 1024)
36 // get acl -------------------------------------------------------------------
38 typedef struct GetAclData
42 S3ResponsePropertiesCallback *responsePropertiesCallback;
43 S3ResponseCompleteCallback *responseCompleteCallback;
46 int *aclGrantCountReturn;
47 S3AclGrant *aclGrants;
49 char *ownerDisplayName;
50 string_buffer(aclXmlDocument, ACL_XML_DOC_MAXSIZE);
54 static S3Status getAclPropertiesCallback
55 (const S3ResponseProperties *responseProperties, void *callbackData)
57 GetAclData *gaData = (GetAclData *) callbackData;
59 return (*(gaData->responsePropertiesCallback))
60 (responseProperties, gaData->callbackData);
64 static S3Status getAclDataCallback(int bufferSize, const char *buffer,
67 GetAclData *gaData = (GetAclData *) callbackData;
71 string_buffer_append(gaData->aclXmlDocument, buffer, bufferSize, fit);
73 return fit ? S3StatusOK : S3StatusXmlDocumentTooLarge;
77 static void getAclCompleteCallback(S3Status requestStatus,
78 const S3ErrorDetails *s3ErrorDetails,
81 GetAclData *gaData = (GetAclData *) callbackData;
83 if (requestStatus == S3StatusOK) {
85 requestStatus = S3_convert_acl
86 (gaData->aclXmlDocument, gaData->ownerId, gaData->ownerDisplayName,
87 gaData->aclGrantCountReturn, gaData->aclGrants);
90 (*(gaData->responseCompleteCallback))
91 (requestStatus, s3ErrorDetails, gaData->callbackData);
97 void S3_get_acl(const S3BucketContext *bucketContext, const char *key,
98 char *ownerId, char *ownerDisplayName,
99 int *aclGrantCountReturn, S3AclGrant *aclGrants,
100 S3RequestContext *requestContext,
101 const S3ResponseHandler *handler, void *callbackData)
103 // Create the callback data
104 GetAclData *gaData = (GetAclData *) malloc(sizeof(GetAclData));
106 (*(handler->completeCallback))(S3StatusOutOfMemory, 0, callbackData);
110 gaData->responsePropertiesCallback = handler->propertiesCallback;
111 gaData->responseCompleteCallback = handler->completeCallback;
112 gaData->callbackData = callbackData;
114 gaData->aclGrantCountReturn = aclGrantCountReturn;
115 gaData->aclGrants = aclGrants;
116 gaData->ownerId = ownerId;
117 gaData->ownerDisplayName = ownerDisplayName;
118 string_buffer_initialize(gaData->aclXmlDocument);
119 *aclGrantCountReturn = 0;
121 // Set up the RequestParams
122 RequestParams params =
124 HttpRequestTypeGET, // httpRequestType
125 { bucketContext->bucketName, // bucketName
126 bucketContext->protocol, // protocol
127 bucketContext->uriStyle, // uriStyle
128 bucketContext->accessKeyId, // accessKeyId
129 bucketContext->secretAccessKey }, // secretAccessKey
132 "acl", // subResource
133 0, // copySourceBucketName
139 &getAclPropertiesCallback, // propertiesCallback
141 0, // toS3CallbackTotalSize
142 &getAclDataCallback, // fromS3Callback
143 &getAclCompleteCallback, // completeCallback
144 gaData // callbackData
147 // Perform the request
148 request_perform(¶ms, requestContext);
152 // set acl -------------------------------------------------------------------
154 static S3Status generateAclXmlDocument(const char *ownerId,
155 const char *ownerDisplayName,
157 const S3AclGrant *aclGrants,
158 int *xmlDocumentLenReturn,
160 int xmlDocumentBufferSize)
162 *xmlDocumentLenReturn = 0;
164 #define append(fmt, ...) \
166 *xmlDocumentLenReturn += snprintf \
167 (&(xmlDocument[*xmlDocumentLenReturn]), \
168 xmlDocumentBufferSize - *xmlDocumentLenReturn - 1, \
170 if (*xmlDocumentLenReturn >= xmlDocumentBufferSize) { \
171 return S3StatusXmlDocumentTooLarge; \
175 append("<AccessControlPolicy><Owner><ID>%s</ID><DisplayName>%s"
176 "</DisplayName></Owner><AccessControlList>", ownerId,
180 for (i = 0; i < aclGrantCount; i++) {
181 append("%s", "<Grant><Grantee xmlns:xsi=\"http://www.w3.org/2001/"
182 "XMLSchema-instance\" xsi:type=\"");
183 const S3AclGrant *grant = &(aclGrants[i]);
184 switch (grant->granteeType) {
185 case S3GranteeTypeAmazonCustomerByEmail:
186 append("AmazonCustomerByEmail\"><EmailAddress>%s</EmailAddress>",
187 grant->grantee.amazonCustomerByEmail.emailAddress);
189 case S3GranteeTypeCanonicalUser:
190 append("CanonicalUser\"><ID>%s</ID><DisplayName>%s</DisplayName>",
191 grant->grantee.canonicalUser.id,
192 grant->grantee.canonicalUser.displayName);
194 default: { // case S3GranteeTypeAllAwsUsers/S3GranteeTypeAllUsers:
196 switch (grant->granteeType) {
197 case S3GranteeTypeAllAwsUsers:
198 grantee = "http://acs.amazonaws.com/groups/global/"
199 "AuthenticatedUsers";
201 case S3GranteeTypeAllUsers:
202 grantee = "http://acs.amazonaws.com/groups/global/"
206 grantee = "http://acs.amazonaws.com/groups/s3/"
210 append("Group\"><URI>%s</URI>", grantee);
214 append("</Grantee><Permission>%s</Permission></Grant>",
215 ((grant->permission == S3PermissionRead) ? "READ" :
216 (grant->permission == S3PermissionWrite) ? "WRITE" :
217 (grant->permission == S3PermissionReadACP) ? "READ_ACP" :
218 (grant->permission == S3PermissionWriteACP) ? "WRITE_ACP" :
222 append("%s", "</AccessControlList></AccessControlPolicy>");
228 typedef struct SetAclData
230 S3ResponsePropertiesCallback *responsePropertiesCallback;
231 S3ResponseCompleteCallback *responseCompleteCallback;
234 int aclXmlDocumentLen;
235 char aclXmlDocument[ACL_XML_DOC_MAXSIZE];
236 int aclXmlDocumentBytesWritten;
241 static S3Status setAclPropertiesCallback
242 (const S3ResponseProperties *responseProperties, void *callbackData)
244 SetAclData *paData = (SetAclData *) callbackData;
246 return (*(paData->responsePropertiesCallback))
247 (responseProperties, paData->callbackData);
251 static int setAclDataCallback(int bufferSize, char *buffer, void *callbackData)
253 SetAclData *paData = (SetAclData *) callbackData;
255 int remaining = (paData->aclXmlDocumentLen -
256 paData->aclXmlDocumentBytesWritten);
258 int toCopy = bufferSize > remaining ? remaining : bufferSize;
264 memcpy(buffer, &(paData->aclXmlDocument
265 [paData->aclXmlDocumentBytesWritten]), toCopy);
267 paData->aclXmlDocumentBytesWritten += toCopy;
273 static void setAclCompleteCallback(S3Status requestStatus,
274 const S3ErrorDetails *s3ErrorDetails,
277 SetAclData *paData = (SetAclData *) callbackData;
279 (*(paData->responseCompleteCallback))
280 (requestStatus, s3ErrorDetails, paData->callbackData);
286 void S3_set_acl(const S3BucketContext *bucketContext, const char *key,
287 const char *ownerId, const char *ownerDisplayName,
288 int aclGrantCount, const S3AclGrant *aclGrants,
289 S3RequestContext *requestContext,
290 const S3ResponseHandler *handler, void *callbackData)
292 if (aclGrantCount > S3_MAX_ACL_GRANT_COUNT) {
293 (*(handler->completeCallback))
294 (S3StatusTooManyGrants, 0, callbackData);
298 SetAclData *data = (SetAclData *) malloc(sizeof(SetAclData));
300 (*(handler->completeCallback))(S3StatusOutOfMemory, 0, callbackData);
304 // Convert aclGrants to XML document
305 S3Status status = generateAclXmlDocument
306 (ownerId, ownerDisplayName, aclGrantCount, aclGrants,
307 &(data->aclXmlDocumentLen), data->aclXmlDocument,
308 sizeof(data->aclXmlDocument));
309 if (status != S3StatusOK) {
311 (*(handler->completeCallback))(status, 0, callbackData);
315 data->responsePropertiesCallback = handler->propertiesCallback;
316 data->responseCompleteCallback = handler->completeCallback;
317 data->callbackData = callbackData;
319 data->aclXmlDocumentBytesWritten = 0;
321 // Set up the RequestParams
322 RequestParams params =
324 HttpRequestTypePUT, // httpRequestType
325 { bucketContext->bucketName, // bucketName
326 bucketContext->protocol, // protocol
327 bucketContext->uriStyle, // uriStyle
328 bucketContext->accessKeyId, // accessKeyId
329 bucketContext->secretAccessKey }, // secretAccessKey
332 "acl", // subResource
333 0, // copySourceBucketName
339 &setAclPropertiesCallback, // propertiesCallback
340 &setAclDataCallback, // toS3Callback
341 data->aclXmlDocumentLen, // toS3CallbackTotalSize
343 &setAclCompleteCallback, // completeCallback
347 // Perform the request
348 request_perform(¶ms, requestContext);