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