Added AMS functionality to support on-demand ACL provisioning.
[platform/upstream/iotivity.git] / resource / csdk / security / src / secureresourcemanager.c
1 //******************************************************************
2 //
3 // Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 #include "ocstack.h"
22 #include "logger.h"
23 #include "cainterface.h"
24 #include "resourcemanager.h"
25 #include "credresource.h"
26 #include "policyengine.h"
27 #include "srmutility.h"
28 #include "amsmgr.h"
29 #include "oic_string.h"
30 #include "oic_malloc.h"
31 #include "securevirtualresourcetypes.h"
32 #include "secureresourcemanager.h"
33 #include <string.h>
34
35 #define TAG  "SRM"
36
37 //Request Callback handler
38 static CARequestCallback gRequestHandler = NULL;
39 //Response Callback handler
40 static CAResponseCallback gResponseHandler = NULL;
41 //Error Callback handler
42 static CAErrorCallback gErrorHandler = NULL;
43 //Persistent Storage callback handler for open/read/write/close/unlink
44 static OCPersistentStorage *gPersistentStorageHandler =  NULL;
45 //Provisioning response callback
46 static SPResponseCallback gSPResponseHandler = NULL;
47
48 /**
49  * A single global Policy Engine context will suffice as long
50  * as SRM is single-threaded.
51  */
52 PEContext_t g_policyEngineContext;
53
54 /**
55  * @brief function to register provisoning API's response callback.
56  * @param respHandler response handler callback.
57  */
58 void SRMRegisterProvisioningResponseHandler(SPResponseCallback respHandler)
59 {
60     gSPResponseHandler = respHandler;
61 }
62
63
64 static void SRMSendUnAuthorizedAccessresponse(PEContext_t *context)
65 {
66     CAResponseInfo_t responseInfo = {.result = CA_EMPTY};
67     memcpy(&responseInfo.info, &(context->amsMgrContext->requestInfo->info),
68             sizeof(responseInfo.info));
69     responseInfo.info.payload = NULL;
70     responseInfo.result = CA_UNAUTHORIZED_REQ;
71     if (CA_STATUS_OK != CASendResponse(context->amsMgrContext->endpoint, &responseInfo))
72     {
73         OC_LOG(ERROR, TAG, "Failed in sending response to a unauthorized request!");
74     }
75     else
76     {
77         OC_LOG(INFO, TAG, "Succeed in sending response to a unauthorized request!");
78     }
79 }
80
81
82 void SRMSendResponse(SRMAccessResponse_t responseVal)
83 {
84     OC_LOG(INFO, TAG, "Sending response to remote device");
85
86     if (IsAccessGranted(responseVal) && gRequestHandler)
87     {
88         OC_LOG_V(INFO, TAG, "%s : Access granted. Passing Request to RI layer", __func__);
89         if (!g_policyEngineContext.amsMgrContext->endpoint ||
90                 !g_policyEngineContext.amsMgrContext->requestInfo)
91         {
92             OC_LOG_V(ERROR, TAG, "%s : Invalid arguments", __func__);
93             SRMSendUnAuthorizedAccessresponse(&g_policyEngineContext);
94             goto exit;
95         }
96         gRequestHandler(g_policyEngineContext.amsMgrContext->endpoint,
97                 g_policyEngineContext.amsMgrContext->requestInfo);
98     }
99     else
100     {
101         OC_LOG_V(INFO, TAG, "%s : ACCESS_DENIED.", __func__);
102         SRMSendUnAuthorizedAccessresponse(&g_policyEngineContext);
103     }
104
105 exit:
106     //Resting PE state to AWAITING_REQUEST
107     SetPolicyEngineState(&g_policyEngineContext, AWAITING_REQUEST);
108 }
109
110
111 /**
112  * @brief   Handle the request from the SRM.
113  * @param   endPoint       [IN] Endpoint object from which the response is received.
114  * @param   requestInfo    [IN] Information for the request.
115  * @return  NONE
116  */
117 void SRMRequestHandler(const CAEndpoint_t *endPoint, const CARequestInfo_t *requestInfo)
118 {
119     OC_LOG(INFO, TAG, "Received request from remote device");
120
121     if (!endPoint || !requestInfo)
122     {
123         OC_LOG(ERROR, TAG, "Invalid arguments");
124         return;
125     }
126
127     // Copy the subjectID
128     OicUuid_t subjectId = {.id = {0}};
129     memcpy(subjectId.id, requestInfo->info.identity.id, sizeof(subjectId.id));
130
131     //Check the URI has the query and skip it before checking the permission
132     char *uri = strstr(requestInfo->info.resourceUri, "?");
133     int position = 0;
134     if (uri)
135     {
136         //Skip query and pass the resource uri
137         position = uri - requestInfo->info.resourceUri;
138     }
139     else
140     {
141         position = strlen(requestInfo->info.resourceUri);
142     }
143     if (MAX_URI_LENGTH < position  || 0 > position)
144     {
145         OC_LOG(ERROR, TAG, "Incorrect URI length");
146         return;
147     }
148     SRMAccessResponse_t response = ACCESS_DENIED;
149     char newUri[MAX_URI_LENGTH + 1];
150     OICStrcpyPartial(newUri, MAX_URI_LENGTH + 1, requestInfo->info.resourceUri, position);
151
152     //New request are only processed if the policy engine state is AWAITING_REQUEST.
153     if(AWAITING_REQUEST == g_policyEngineContext.state)
154     {
155         OC_LOG_V(INFO, TAG, "Processing request with uri, %s for method, %d",
156                 requestInfo->info.resourceUri, requestInfo->method);
157         response = CheckPermission(&g_policyEngineContext, &subjectId, newUri,
158                 GetPermissionFromCAMethod_t(requestInfo->method));
159     }
160     else
161     {
162         OC_LOG_V(INFO, TAG, "PE state %d. Ignoring request with uri, %s for method, %d",
163                 g_policyEngineContext.state, requestInfo->info.resourceUri, requestInfo->method);
164     }
165
166     if (IsAccessGranted(response) && gRequestHandler)
167     {
168         return (gRequestHandler(endPoint, requestInfo));
169     }
170
171     // Form a 'Error', 'slow response' or 'access deny' response and send to peer
172     CAResponseInfo_t responseInfo = {.result = CA_EMPTY};
173     memcpy(&responseInfo.info, &(requestInfo->info), sizeof(responseInfo.info));
174     responseInfo.info.payload = NULL;
175
176     VERIFY_NON_NULL(TAG, gRequestHandler, ERROR);
177
178     if(ACCESS_WAITING_FOR_AMS == response)
179     {
180         OC_LOG(INFO, TAG, "Sending slow response");
181
182         UpdateAmsMgrContext(&g_policyEngineContext, endPoint, requestInfo);
183         responseInfo.result = CA_EMPTY;
184         responseInfo.info.type = CA_MSG_ACKNOWLEDGE;
185     }
186     else
187     {
188         /*
189          * TODO Enhance this logic more to decide between
190          * CA_UNAUTHORIZED_REQ or CA_FORBIDDEN_REQ depending
191          * upon SRMAccessResponseReasonCode_t
192          */
193         OC_LOG(INFO, TAG, "Sending for regular response");
194         responseInfo.result = CA_UNAUTHORIZED_REQ;
195     }
196
197     if (CA_STATUS_OK != CASendResponse(endPoint, &responseInfo))
198     {
199         OC_LOG(ERROR, TAG, "Failed in sending response to a unauthorized request!");
200     }
201     return;
202 exit:
203     responseInfo.result = CA_INTERNAL_SERVER_ERROR;
204     if (CA_STATUS_OK != CASendResponse(endPoint, &responseInfo))
205     {
206         OC_LOG(ERROR, TAG, "Failed in sending response to a unauthorized request!");
207     }
208 }
209
210 /**
211  * @brief   Handle the response from the SRM.
212  * @param   endPoint     [IN] The remote endpoint.
213  * @param   responseInfo [IN] Response information from the endpoint.
214  * @return  NONE
215  */
216 void SRMResponseHandler(const CAEndpoint_t *endPoint, const CAResponseInfo_t *responseInfo)
217 {
218     OC_LOG(INFO, TAG, "Received response from remote device");
219
220     // isProvResponse flag is to check whether response is catered by provisioning APIs or not.
221     // When token sent by CA response matches with token generated by provisioning request,
222     // gSPResponseHandler returns true and response is not sent to RI layer. In case
223     // gSPResponseHandler is null and isProvResponse is false response then the response is for
224     // RI layer.
225     bool isProvResponse = false;
226
227     if (gSPResponseHandler)
228     {
229         isProvResponse = gSPResponseHandler(endPoint, responseInfo);
230     }
231     if (!isProvResponse && gResponseHandler)
232     {
233         gResponseHandler(endPoint, responseInfo);
234     }
235 }
236
237
238 /**
239  * @brief   Handle the error from the SRM.
240  * @param   endPoint  [IN] The remote endpoint.
241  * @param   errorInfo [IN] Error information from the endpoint.
242  * @return  NONE
243  */
244 void SRMErrorHandler(const CAEndpoint_t *endPoint, const CAErrorInfo_t *errorInfo)
245 {
246     OC_LOG_V(INFO, TAG, "Received error from remote device with result, %d for request uri, %s",
247             errorInfo->result, errorInfo->info.resourceUri);
248     if (gErrorHandler)
249     {
250         gErrorHandler(endPoint, errorInfo);
251     }
252 }
253
254
255 /**
256  * @brief   Register request and response callbacks.
257  *          Requests and responses are delivered in these callbacks.
258  * @param   reqHandler   [IN] Request handler callback ( for GET,PUT ..etc)
259  * @param   respHandler  [IN] Response handler callback.
260  * @return
261  *     OC_STACK_OK    - No errors; Success
262  *     OC_STACK_INVALID_PARAM - invalid parameter
263  */
264 OCStackResult SRMRegisterHandler(CARequestCallback reqHandler,
265                                  CAResponseCallback respHandler,
266                                  CAErrorCallback errHandler)
267 {
268     OC_LOG(INFO, TAG, "SRMRegisterHandler !!");
269     if( !reqHandler || !respHandler || !errHandler)
270     {
271         OC_LOG(ERROR, TAG, "Callback handlers are invalid");
272         return OC_STACK_INVALID_PARAM;
273     }
274     gRequestHandler = reqHandler;
275     gResponseHandler = respHandler;
276     gErrorHandler = errHandler;
277
278
279 #if defined(__WITH_DTLS__)
280     CARegisterHandler(SRMRequestHandler, SRMResponseHandler, SRMErrorHandler);
281 #else
282     CARegisterHandler(reqHandler, respHandler, errHandler);
283 #endif /* __WITH_DTLS__ */
284     return OC_STACK_OK;
285 }
286
287 /**
288  * @brief   Register Persistent storage callback.
289  * @param   persistentStorageHandler [IN] Pointers to open, read, write, close & unlink handlers.
290  * @return
291  *     OC_STACK_OK    - No errors; Success
292  *     OC_STACK_INVALID_PARAM - Invalid parameter
293  */
294 OCStackResult SRMRegisterPersistentStorageHandler(OCPersistentStorage* persistentStorageHandler)
295 {
296     OC_LOG(INFO, TAG, "SRMRegisterPersistentStorageHandler !!");
297     if(!persistentStorageHandler)
298     {
299         OC_LOG(ERROR, TAG, "The persistent storage handler is invalid");
300         return OC_STACK_INVALID_PARAM;
301     }
302     gPersistentStorageHandler = persistentStorageHandler;
303     return OC_STACK_OK;
304 }
305
306 /**
307  * @brief   Get Persistent storage handler pointer.
308  * @return
309  *     The pointer to Persistent Storage callback handler
310  */
311
312 OCPersistentStorage* SRMGetPersistentStorageHandler()
313 {
314     return gPersistentStorageHandler;
315 }
316
317
318 /**
319  * @brief   Initialize all secure resources ( /oic/sec/cred, /oic/sec/acl, /oic/sec/pstat etc).
320  * @retval  OC_STACK_OK for Success, otherwise some error value
321  */
322 OCStackResult SRMInitSecureResources()
323 {
324     // TODO: temporarily returning OC_STACK_OK every time until default
325     // behavior (for when SVR DB is missing) is settled.
326     InitSecureResources();
327
328 #if defined(__WITH_DTLS__)
329     CARegisterDTLSCredentialsHandler(GetDtlsPskCredentials);
330 #endif // (__WITH_DTLS__)
331
332     return OC_STACK_OK;
333 }
334
335 /**
336  * @brief   Perform cleanup for secure resources ( /oic/sec/cred, /oic/sec/acl, /oic/sec/pstat etc).
337  * @retval  none
338  */
339 void SRMDeInitSecureResources()
340 {
341     DestroySecureResources();
342 }
343
344 /**
345  * @brief   Initialize Policy Engine.
346  * @return  OC_STACK_OK for Success, otherwise some error value.
347  */
348 OCStackResult SRMInitPolicyEngine()
349 {
350     return InitPolicyEngine(&g_policyEngineContext);
351 }
352
353 /**
354  * @brief   Cleanup Policy Engine.
355  * @return  none
356  */
357 void SRMDeInitPolicyEngine()
358 {
359     return DeInitPolicyEngine(&g_policyEngineContext);
360 }