2a8272b8b5b34d1cc30432e858277a63227c7205
[bluesky.git] / libs3-1.4 / src / acl.c
1 /** **************************************************************************
2  * acl.c
3  * 
4  * Copyright 2008 Bryan Ischo <bryan@ischo.com>
5  * 
6  * This file is part of libs3.
7  * 
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.
11  *
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.
15  *
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
19  * details.
20  *
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/>.
24  *
25  ************************************************************************** **/
26
27 #include <stdlib.h>
28 #include <string.h>
29 #include "libs3.h"
30 #include "request.h"
31
32 // Use a rather arbitrary max size for the document of 64K
33 #define ACL_XML_DOC_MAXSIZE (64 * 1024)
34
35
36 // get acl -------------------------------------------------------------------
37
38 typedef struct GetAclData
39 {
40     SimpleXml simpleXml;
41
42     S3ResponsePropertiesCallback *responsePropertiesCallback;
43     S3ResponseCompleteCallback *responseCompleteCallback;
44     void *callbackData;
45
46     int *aclGrantCountReturn;
47     S3AclGrant *aclGrants;
48     char *ownerId;
49     char *ownerDisplayName;
50     string_buffer(aclXmlDocument, ACL_XML_DOC_MAXSIZE);
51 } GetAclData;
52
53
54 static S3Status getAclPropertiesCallback
55     (const S3ResponseProperties *responseProperties, void *callbackData)
56 {
57     GetAclData *gaData = (GetAclData *) callbackData;
58     
59     return (*(gaData->responsePropertiesCallback))
60         (responseProperties, gaData->callbackData);
61 }
62
63
64 static S3Status getAclDataCallback(int bufferSize, const char *buffer,
65                                    void *callbackData)
66 {
67     GetAclData *gaData = (GetAclData *) callbackData;
68
69     int fit;
70
71     string_buffer_append(gaData->aclXmlDocument, buffer, bufferSize, fit);
72     
73     return fit ? S3StatusOK : S3StatusXmlDocumentTooLarge;
74 }
75
76
77 static void getAclCompleteCallback(S3Status requestStatus, 
78                                    const S3ErrorDetails *s3ErrorDetails,
79                                    void *callbackData)
80 {
81     GetAclData *gaData = (GetAclData *) callbackData;
82
83     if (requestStatus == S3StatusOK) {
84         // Parse the document
85         requestStatus = S3_convert_acl
86             (gaData->aclXmlDocument, gaData->ownerId, gaData->ownerDisplayName,
87              gaData->aclGrantCountReturn, gaData->aclGrants);
88     }
89
90     (*(gaData->responseCompleteCallback))
91         (requestStatus, s3ErrorDetails, gaData->callbackData);
92
93     free(gaData);
94 }
95
96
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)
102 {
103     // Create the callback data
104     GetAclData *gaData = (GetAclData *) malloc(sizeof(GetAclData));
105     if (!gaData) {
106         (*(handler->completeCallback))(S3StatusOutOfMemory, 0, callbackData);
107         return;
108     }
109
110     gaData->responsePropertiesCallback = handler->propertiesCallback;
111     gaData->responseCompleteCallback = handler->completeCallback;
112     gaData->callbackData = callbackData;
113
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;
120
121     // Set up the RequestParams
122     RequestParams params =
123     {
124         HttpRequestTypeGET,                           // httpRequestType
125         { bucketContext->bucketName,                  // bucketName
126           bucketContext->protocol,                    // protocol
127           bucketContext->uriStyle,                    // uriStyle
128           bucketContext->accessKeyId,                 // accessKeyId
129           bucketContext->secretAccessKey },           // secretAccessKey
130         key,                                          // key
131         0,                                            // queryParams
132         "acl",                                        // subResource
133         0,                                            // copySourceBucketName
134         0,                                            // copySourceKey
135         0,                                            // getConditions
136         0,                                            // startByte
137         0,                                            // byteCount
138         0,                                            // putProperties
139         &getAclPropertiesCallback,                    // propertiesCallback
140         0,                                            // toS3Callback
141         0,                                            // toS3CallbackTotalSize
142         &getAclDataCallback,                          // fromS3Callback
143         &getAclCompleteCallback,                      // completeCallback
144         gaData                                        // callbackData
145     };
146
147     // Perform the request
148     request_perform(&params, requestContext);
149 }
150
151
152 // set acl -------------------------------------------------------------------
153
154 static S3Status generateAclXmlDocument(const char *ownerId, 
155                                        const char *ownerDisplayName,
156                                        int aclGrantCount, 
157                                        const S3AclGrant *aclGrants,
158                                        int *xmlDocumentLenReturn,
159                                        char *xmlDocument,
160                                        int xmlDocumentBufferSize)
161 {
162     *xmlDocumentLenReturn = 0;
163
164 #define append(fmt, ...)                                        \
165     do {                                                        \
166         *xmlDocumentLenReturn += snprintf                       \
167             (&(xmlDocument[*xmlDocumentLenReturn]),             \
168              xmlDocumentBufferSize - *xmlDocumentLenReturn - 1, \
169              fmt, __VA_ARGS__);                                 \
170         if (*xmlDocumentLenReturn >= xmlDocumentBufferSize) {   \
171             return S3StatusXmlDocumentTooLarge;                 \
172         } \
173     } while (0)
174
175     append("<AccessControlPolicy><Owner><ID>%s</ID><DisplayName>%s"
176            "</DisplayName></Owner><AccessControlList>", ownerId,
177            ownerDisplayName);
178
179     int i;
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);
188             break;
189         case S3GranteeTypeCanonicalUser:
190             append("CanonicalUser\"><ID>%s</ID><DisplayName>%s</DisplayName>",
191                    grant->grantee.canonicalUser.id, 
192                    grant->grantee.canonicalUser.displayName);
193             break;
194         default: { // case S3GranteeTypeAllAwsUsers/S3GranteeTypeAllUsers:
195             const char *grantee;
196             switch (grant->granteeType) {
197             case S3GranteeTypeAllAwsUsers:
198                 grantee = "http://acs.amazonaws.com/groups/global/"
199                     "AuthenticatedUsers";
200                 break;
201             case S3GranteeTypeAllUsers:
202                 grantee = "http://acs.amazonaws.com/groups/global/"
203                     "AllUsers";
204                 break;
205             default:
206                 grantee = "http://acs.amazonaws.com/groups/s3/"
207                     "LogDelivery";
208                 break;
209             }
210             append("Group\"><URI>%s</URI>", grantee);
211         }
212             break;
213         }
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" :
219                 "FULL_CONTROL"));
220     }
221
222     append("%s", "</AccessControlList></AccessControlPolicy>");
223
224     return S3StatusOK;
225 }
226
227
228 typedef struct SetAclData
229 {
230     S3ResponsePropertiesCallback *responsePropertiesCallback;
231     S3ResponseCompleteCallback *responseCompleteCallback;
232     void *callbackData;
233
234     int aclXmlDocumentLen;
235     char aclXmlDocument[ACL_XML_DOC_MAXSIZE];
236     int aclXmlDocumentBytesWritten;
237
238 } SetAclData;
239
240
241 static S3Status setAclPropertiesCallback
242     (const S3ResponseProperties *responseProperties, void *callbackData)
243 {
244     SetAclData *paData = (SetAclData *) callbackData;
245     
246     return (*(paData->responsePropertiesCallback))
247         (responseProperties, paData->callbackData);
248 }
249
250
251 static int setAclDataCallback(int bufferSize, char *buffer, void *callbackData)
252 {
253     SetAclData *paData = (SetAclData *) callbackData;
254
255     int remaining = (paData->aclXmlDocumentLen - 
256                      paData->aclXmlDocumentBytesWritten);
257
258     int toCopy = bufferSize > remaining ? remaining : bufferSize;
259     
260     if (!toCopy) {
261         return 0;
262     }
263
264     memcpy(buffer, &(paData->aclXmlDocument
265                      [paData->aclXmlDocumentBytesWritten]), toCopy);
266
267     paData->aclXmlDocumentBytesWritten += toCopy;
268
269     return toCopy;
270 }
271
272
273 static void setAclCompleteCallback(S3Status requestStatus, 
274                                    const S3ErrorDetails *s3ErrorDetails,
275                                    void *callbackData)
276 {
277     SetAclData *paData = (SetAclData *) callbackData;
278
279     (*(paData->responseCompleteCallback))
280         (requestStatus, s3ErrorDetails, paData->callbackData);
281
282     free(paData);
283 }
284
285
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)
291 {
292     if (aclGrantCount > S3_MAX_ACL_GRANT_COUNT) {
293         (*(handler->completeCallback))
294             (S3StatusTooManyGrants, 0, callbackData);
295         return;
296     }
297
298     SetAclData *data = (SetAclData *) malloc(sizeof(SetAclData));
299     if (!data) {
300         (*(handler->completeCallback))(S3StatusOutOfMemory, 0, callbackData);
301         return;
302     }
303     
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) {
310         free(data);
311         (*(handler->completeCallback))(status, 0, callbackData);
312         return;
313     }
314
315     data->responsePropertiesCallback = handler->propertiesCallback;
316     data->responseCompleteCallback = handler->completeCallback;
317     data->callbackData = callbackData;
318
319     data->aclXmlDocumentBytesWritten = 0;
320
321     // Set up the RequestParams
322     RequestParams params =
323     {
324         HttpRequestTypePUT,                           // httpRequestType
325         { bucketContext->bucketName,                  // bucketName
326           bucketContext->protocol,                    // protocol
327           bucketContext->uriStyle,                    // uriStyle
328           bucketContext->accessKeyId,                 // accessKeyId
329           bucketContext->secretAccessKey },           // secretAccessKey
330         key,                                          // key
331         0,                                            // queryParams
332         "acl",                                        // subResource
333         0,                                            // copySourceBucketName
334         0,                                            // copySourceKey
335         0,                                            // getConditions
336         0,                                            // startByte
337         0,                                            // byteCount
338         0,                                            // putProperties
339         &setAclPropertiesCallback,                    // propertiesCallback
340         &setAclDataCallback,                          // toS3Callback
341         data->aclXmlDocumentLen,                      // toS3CallbackTotalSize
342         0,                                            // fromS3Callback
343         &setAclCompleteCallback,                      // completeCallback
344         data                                          // callbackData
345     };
346
347     // Perform the request
348     request_perform(&params, requestContext);
349 }