Common adapter for DTLS/TLS
[platform/upstream/iotivity.git] / resource / csdk / security / provisioning / src / ocprovisioningmanager.c
1 /* *****************************************************************
2  *
3  * Copyright 2015 Samsung Electronics 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 #include <stdint.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include "ocprovisioningmanager.h"
24 #include "pmutility.h"
25 #include "srmutility.h"
26 #include "ownershiptransfermanager.h"
27 #include "oic_malloc.h"
28 #include "logger.h"
29 #include "secureresourceprovider.h"
30 #include "provisioningdatabasemanager.h"
31 #include "credresource.h"
32 #include "utlist.h"
33 #include "aclresource.h" //Note: SRM internal header
34 #include "pconfresource.h"
35
36 #define TAG "OCPMAPI"
37
38 typedef struct Linkdata Linkdata_t;
39 struct Linkdata
40 {
41     void *ctx;
42     const OCProvisionDev_t *pDev1;
43     OicSecAcl_t *pDev1Acl;
44     const OCProvisionDev_t *pDev2;
45     OicSecAcl_t *pDev2Acl;
46     OCProvisionResult_t *resArr;
47     int numOfResults;
48     int currentCountResults;
49     OCProvisionResultCB resultCallback;
50
51 };
52
53 /**
54  * The function is responsible for initializaton of the provisioning manager. It will load
55  * provisioning database which have owned device's list and their linked status.
56  * TODO: In addition, if there is a device(s) which has not up-to-date credentials, this function will
57  * automatically try to update the deivce(s).
58  *
59  * @param[in] dbPath file path of the sqlite3 db
60  *
61  * @return OC_STACK_OK in case of success and other value otherwise.
62  */
63 OCStackResult OCInitPM(const char* dbPath)
64 {
65     return PDMInit(dbPath);
66 }
67
68 /**
69  * The function is responsible for discovery of owned/unowned device is specified endpoint/deviceID.
70  * And this function will only return the specified device's response.
71  *
72  * @param[in] timeout Timeout in seconds, value till which function will listen to responses from
73  *                    server before returning the device.
74  * @param[in] deviceID         deviceID of target device.
75  * @param[out] ppFoundDevice     OCProvisionDev_t of found device
76  * @return OTM_SUCCESS in case of success and other value otherwise.
77  */
78 OCStackResult OCDiscoverSingleDevice(unsigned short timeout, const OicUuid_t* deviceID,
79                              OCProvisionDev_t **ppFoundDevice)
80 {
81     if( NULL == ppFoundDevice || NULL != *ppFoundDevice || 0 == timeout || NULL == deviceID)
82     {
83         return OC_STACK_INVALID_PARAM;
84     }
85
86     return PMSingleDeviceDiscovery(timeout, deviceID, ppFoundDevice);
87 }
88
89 /**
90  * The function is responsible for discovery of device is current subnet. It will list
91  * all the device in subnet which are not yet owned. Please call OCInit with OC_CLIENT_SERVER as
92  * OCMode.
93  *
94  * @param[in] timeout Timeout in seconds, value till which function will listen to responses from
95  *                    server before returning the list of devices.
96  * @param[out] ppList List of candidate devices to be provisioned
97  * @return OTM_SUCCESS in case of success and other value otherwise.
98  */
99 OCStackResult OCDiscoverUnownedDevices(unsigned short timeout, OCProvisionDev_t **ppList)
100 {
101     if( ppList == NULL || *ppList != NULL || 0 == timeout)
102     {
103         return OC_STACK_INVALID_PARAM;
104     }
105
106     return PMDeviceDiscovery(timeout, false, ppList);
107 }
108
109 /**
110  * The function is responsible for discovery of owned device is current subnet. It will list
111  * all the device in subnet which are owned by calling provisioning client.
112  *
113  * @param[in] timeout Timeout in seconds, value till which function will listen to responses from
114  *                    server before returning the list of devices.
115  * @param[out] ppList List of device owned by provisioning tool.
116  * @return OTM_SUCCESS in case of success and other value otherwise.
117  */
118 OCStackResult OCDiscoverOwnedDevices(unsigned short timeout, OCProvisionDev_t **ppList)
119 {
120     if( ppList == NULL || *ppList != NULL || 0 == timeout)
121     {
122         return OC_STACK_INVALID_PARAM;
123     }
124
125     return PMDeviceDiscovery(timeout, true, ppList);
126 }
127
128 /**
129  * API to register for particular OxM.
130  *
131  * @param[in] Ownership transfer method.
132  * @param[in] Implementation of callback functions for owership transfer.
133  * @return  OC_STACK_OK in case of success and other value otherwise.
134  */
135 OCStackResult OCSetOwnerTransferCallbackData(OicSecOxm_t oxm, OTMCallbackData_t* callbackData)
136 {
137     if(NULL == callbackData)
138     {
139         return OC_STACK_INVALID_CALLBACK ;
140     }
141
142     return OTMSetOwnershipTransferCallbackData(oxm, callbackData);
143 }
144
145 OCStackResult OCDoOwnershipTransfer(void* ctx,
146                                       OCProvisionDev_t *targetDevices,
147                                       OCProvisionResultCB resultCallback)
148 {
149     if( NULL == targetDevices )
150     {
151         return OC_STACK_INVALID_PARAM;
152     }
153     if (!resultCallback)
154     {
155         OIC_LOG(INFO, TAG, "OCDoOwnershipTransfer : NULL Callback");
156         return OC_STACK_INVALID_CALLBACK;
157     }
158     return OTMDoOwnershipTransfer(ctx, targetDevices, resultCallback);
159 }
160
161 /**
162  * This function deletes memory allocated to linked list created by OCDiscover_XXX_Devices API.
163  *
164  * @param[in] pList Pointer to OCProvisionDev_t which should be deleted.
165  */
166 void OCDeleteDiscoveredDevices(OCProvisionDev_t *pList)
167 {
168     PMDeleteDeviceList(pList);
169 }
170
171 /**
172  * this function sends ACL information to resource.
173  *
174  * @param[in] ctx Application context would be returned in result callback.
175  * @param[in] selectedDeviceInfo Selected target device.
176  * @param[in] acl ACL to provision.
177  * @param[in] resultCallback callback provided by API user, callback will be called when provisioning
178               request recieves a response from resource server.
179  * @return  OC_STACK_OK in case of success and other value otherwise.
180  */
181 OCStackResult OCProvisionACL(void* ctx, const OCProvisionDev_t *selectedDeviceInfo, OicSecAcl_t *acl,
182                              OCProvisionResultCB resultCallback)
183 {
184     return SRPProvisionACL(ctx, selectedDeviceInfo, acl, resultCallback);
185 }
186
187 /**
188  * this function requests CRED information to resource.
189  *
190  * @param[in] ctx Application context would be returned in result callback.
191  * @param[in] selectedDeviceInfo Selected target device.
192  * @param[in] resultCallback callback provided by API user, callback will be called when provisioning
193               request recieves a response from resource server.
194  * @return  OC_STACK_OK in case of success and other value otherwise.
195  */
196 OCStackResult OCGetCredResource(void* ctx, const OCProvisionDev_t *selectedDeviceInfo,
197                              OCProvisionResultCB resultCallback)
198 {
199     return SRPGetCredResource(ctx, selectedDeviceInfo, resultCallback);
200 }
201
202 /**
203  * this function requests ACL information to resource.
204  *
205  * @param[in] ctx Application context would be returned in result callback.
206  * @param[in] selectedDeviceInfo Selected target device.
207  * @param[in] resultCallback callback provided by API user, callback will be called when provisioning
208               request recieves a response from resource server.
209  * @return  OC_STACK_OK in case of success and other value otherwise.
210  */
211 OCStackResult OCGetACLResource(void* ctx, const OCProvisionDev_t *selectedDeviceInfo,
212                              OCProvisionResultCB resultCallback)
213 {
214     return SRPGetACLResource(ctx, selectedDeviceInfo, resultCallback);
215 }
216
217 /**
218  * function to provision credential to devices.
219  *
220  * @param[in] ctx Application context would be returned in result callback.
221  * @param[in] type Type of credentials to be provisioned to the device.
222  * @param[in] pDev1 Pointer to OCProvisionDev_t instance,respresenting resource to be provsioned.
223    @param[in] pDev2 Pointer to OCProvisionDev_t instance,respresenting resource to be provsioned.
224  * @param[in] resultCallback callback provided by API user, callback will be called when
225  *            provisioning request recieves a response from first resource server.
226  * @return  OC_STACK_OK in case of success and other value otherwise.
227  */
228 OCStackResult OCProvisionCredentials(void *ctx, OicSecCredType_t type, size_t keySize,
229                                       const OCProvisionDev_t *pDev1,
230                                       const OCProvisionDev_t *pDev2,
231                                       OCProvisionResultCB resultCallback)
232 {
233     return SRPProvisionCredentials(ctx, type, keySize,
234                                       pDev1, pDev2, resultCallback);
235
236 }
237
238 /**
239  * this function sends Direct-Pairing Configuration to a device.
240  *
241  * @param[in] ctx Application context would be returned in result callback.
242  * @param[in] selectedDeviceInfo Selected target device.
243  * @param[in] pconf PCONF pointer.
244  * @param[in] resultCallback callback provided by API user, callback will be called when provisioning
245               request recieves a response from resource server.
246  * @return  OC_STACK_OK in case of success and other value otherwise.
247  */
248 OCStackResult OCProvisionDirectPairing(void* ctx, const OCProvisionDev_t *selectedDeviceInfo, OicSecPconf_t *pconf,
249                              OCProvisionResultCB resultCallback)
250 {
251     return SRPProvisionDirectPairing(ctx, selectedDeviceInfo, pconf, resultCallback);
252 }
253
254 /*
255 * Function to unlink devices.
256 * This function will remove the credential & relationship between the two devices.
257 *
258 * @param[in] ctx Application context would be returned in result callback
259 * @param[in] pTargetDev1 first device information to be unlinked.
260 * @param[in] pTargetDev2 second device information to be unlinked.
261 * @param[in] resultCallback callback provided by API user, callback will be called when
262 *            device unlink is finished.
263  * @return  OC_STACK_OK in case of success and other value otherwise.
264 */
265 OCStackResult OCUnlinkDevices(void* ctx,
266                               const OCProvisionDev_t* pTargetDev1,
267                               const OCProvisionDev_t* pTargetDev2,
268                               OCProvisionResultCB resultCallback)
269 {
270     OIC_LOG(INFO, TAG, "IN OCUnlinkDevices");
271     OCUuidList_t* idList = NULL;
272     size_t numOfDev = 0;
273
274     if (!pTargetDev1 || !pTargetDev2 || !pTargetDev1->doxm || !pTargetDev2->doxm)
275     {
276         OIC_LOG(ERROR, TAG, "OCUnlinkDevices : NULL parameters");
277         return OC_STACK_INVALID_PARAM;
278     }
279     if (!resultCallback)
280     {
281         OIC_LOG(INFO, TAG, "OCUnlinkDevices : NULL Callback");
282         return OC_STACK_INVALID_CALLBACK;
283     }
284     if (0 == memcmp(&pTargetDev1->doxm->deviceID, &pTargetDev2->doxm->deviceID, sizeof(OicUuid_t)))
285     {
286         OIC_LOG(INFO, TAG, "OCUnlinkDevices : Same device ID");
287         return OC_STACK_INVALID_PARAM;
288     }
289
290     // Get linked devices with the first device.
291     OCStackResult res = PDMGetLinkedDevices(&(pTargetDev1->doxm->deviceID), &idList, &numOfDev);
292     if (OC_STACK_OK != res)
293     {
294         OIC_LOG(ERROR, TAG, "OCUnlinkDevices : PDMgetOwnedDevices failed");
295         goto error;
296     }
297     if (1 > numOfDev)
298     {
299         OIC_LOG(DEBUG, TAG, "OCUnlinkDevices : Can not find linked devices");
300         res = OC_STACK_INVALID_PARAM; // Input devices are not linked, No request is made
301         goto error;
302     }
303
304     // Check the linked devices contains the second device. If yes send credential DELETE request.
305     OCUuidList_t* curDev = idList;
306     while (NULL != curDev)
307     {
308         if (memcmp(pTargetDev2->doxm->deviceID.id, curDev->dev.id, sizeof(curDev->dev.id)) == 0)
309         {
310             res = SRPUnlinkDevices(ctx, pTargetDev1, pTargetDev2, resultCallback);
311             if (OC_STACK_OK != res)
312             {
313                 OIC_LOG(ERROR, TAG, "OCUnlinkDevices : Failed to unlink devices.");
314             }
315             goto error;
316         }
317         curDev = curDev->next;
318     }
319     OIC_LOG(DEBUG, TAG, "No matched pair found from provisioning database");
320     res = OC_STACK_INVALID_PARAM; // Input devices are not linked, No request is made
321
322 error:
323     OIC_LOG(INFO, TAG, "OUT OCUnlinkDevices");
324
325     PDMDestoryOicUuidLinkList(idList);
326     return res;
327 }
328
329 static OCStackResult RemoveDeviceInfoFromLocal(const OCProvisionDev_t* pTargetDev)
330 {
331     // Remove credential of revoked device from SVR database
332     OCStackResult res = OC_STACK_ERROR;
333     const OicSecCred_t *cred = NULL;
334
335     OIC_LOG(DEBUG, TAG, "IN RemoveDeviceInfoFromLocal");
336     cred = GetCredResourceData(&pTargetDev->doxm->deviceID);
337     if (NULL != cred)
338     {
339         res = RemoveCredential(&cred->subject);
340         if (res != OC_STACK_RESOURCE_DELETED)
341         {
342             OIC_LOG(ERROR, TAG, "RemoveDeviceInfoFromLocal : Failed to remove credential.");
343             goto error;
344         }
345     }
346     /**
347      * Change the device status as stale status.
348      * If all request are successed, this device information will be deleted.
349      */
350     res = PDMSetDeviceStale(&pTargetDev->doxm->deviceID);
351     if (res != OC_STACK_OK)
352     {
353         OIC_LOG(WARNING, TAG, "OCRemoveDevice : Failed to set device status as stale");
354     }
355
356     // TODO: We need to add new mechanism to clean up the stale state of the device.
357
358     // Close the DTLS session of the removed device.
359     CAEndpoint_t *endpoint = (CAEndpoint_t *)&pTargetDev->endpoint;
360     endpoint->port = pTargetDev->securePort;
361     CAResult_t caResult = CAcloseSslSession(endpoint);
362     if(CA_STATUS_OK != caResult)
363     {
364         OIC_LOG_V(WARNING, TAG, "OCRemoveDevice : Failed to close DTLS session : %d", caResult);
365     }
366
367     OIC_LOG(DEBUG, TAG, "OUT RemoveDeviceInfoFromLocal");
368 error:
369     return res;
370 }
371
372 /*
373 * Function to device revocation
374 * This function will remove credential of target device from all devices in subnet.
375 *
376 * @param[in] ctx Application context would be returned in result callback
377 * @param[in] waitTimeForOwnedDeviceDiscovery Maximum wait time for owned device discovery.(seconds)
378 * @param[in] pTargetDev Device information to be revoked.
379 * @param[in] resultCallback callback provided by API user, callback will be called when
380 *            credential revocation is finished.
381  * @return  OC_STACK_OK in case of success and other value otherwise.
382 */
383 OCStackResult OCRemoveDevice(void* ctx, unsigned short waitTimeForOwnedDeviceDiscovery,
384                             const OCProvisionDev_t* pTargetDev,
385                             OCProvisionResultCB resultCallback)
386 {
387     OIC_LOG(INFO, TAG, "IN OCRemoveDevice");
388     OCStackResult res = OC_STACK_ERROR;
389     if (!pTargetDev || 0 == waitTimeForOwnedDeviceDiscovery)
390     {
391         OIC_LOG(INFO, TAG, "OCRemoveDevice : Invalied parameters");
392         return OC_STACK_INVALID_PARAM;
393     }
394     if (!resultCallback)
395     {
396         OIC_LOG(INFO, TAG, "OCRemoveDevice : NULL Callback");
397         return OC_STACK_INVALID_CALLBACK;
398     }
399
400     // Send DELETE requests to linked devices
401     OCStackResult resReq = OC_STACK_ERROR; // Check that we have to wait callback or not.
402     resReq = SRPRemoveDevice(ctx, waitTimeForOwnedDeviceDiscovery, pTargetDev, resultCallback);
403     if (OC_STACK_OK != resReq)
404     {
405         if (OC_STACK_CONTINUE == resReq)
406         {
407             OIC_LOG(DEBUG, TAG, "OCRemoveDevice : Revoked device has no linked device except PT.");
408         }
409         else
410         {
411             OIC_LOG(ERROR, TAG, "OCRemoveDevice : Failed to invoke SRPRemoveDevice");
412             res = resReq;
413             goto error;
414         }
415     }
416
417     res = RemoveDeviceInfoFromLocal(pTargetDev);
418     if(OC_STACK_OK != res)
419     {
420         OIC_LOG(ERROR, TAG, "Filed to remove the device information from local.");
421         goto error;
422     }
423
424     if(OC_STACK_CONTINUE == resReq)
425     {
426         /**
427           * If there is no linked device, PM does not send any request.
428           * So we should directly invoke the result callback to inform the result of OCRemoveDevice.
429           */
430         if(resultCallback)
431         {
432             resultCallback(ctx, 0, NULL, false);
433         }
434         res = OC_STACK_OK;
435     }
436
437 error:
438     OIC_LOG(INFO, TAG, "OUT OCRemoveDevice");
439     return res;
440 }
441
442 /*
443 * Function to device revocation
444 * This function will remove credential of target device from all devices in subnet.
445 *
446 * @param[in] ctx Application context would be returned in result callback
447 * @param[in] waitTimeForOwnedDeviceDiscovery Maximum wait time for owned device discovery.(seconds)
448 * @param[in] pTargetDev Device information to be revoked.
449 * @param[in] resultCallback callback provided by API user, callback will be called when
450 *            credential revocation is finished.
451  * @return  OC_STACK_OK in case of success and other value otherwise.
452 */
453 OCStackResult OCRemoveDeviceWithUuid(void* ctx, unsigned short waitTimeForOwnedDeviceDiscovery,
454                             const OicUuid_t* pTargetUuid,
455                             OCProvisionResultCB resultCallback)
456 {
457     OIC_LOG(INFO, TAG, "IN OCRemoveDeviceWithUuid");
458
459     OCStackResult res = OC_STACK_ERROR;
460     OCProvisionDev_t* pTargetDev = NULL;
461     bool discoverdFlag = false;
462     OCProvisionDev_t* pOwnedDevList = NULL;
463
464     if (!pTargetUuid || 0 == waitTimeForOwnedDeviceDiscovery)
465     {
466         OIC_LOG(INFO, TAG, "OCRemoveDeviceWithUuid : Invalied parameters");
467         return OC_STACK_INVALID_PARAM;
468     }
469     if (!resultCallback)
470     {
471         OIC_LOG(INFO, TAG, "OCRemoveDeviceWithUuid : NULL Callback");
472         return OC_STACK_INVALID_CALLBACK;
473     }
474
475     char* strUuid = NULL;
476     if(OC_STACK_OK != ConvertUuidToStr(pTargetUuid, &strUuid))
477     {
478         OIC_LOG(WARNING, TAG, "Failed to covert UUID to String.");
479         goto error;
480     }
481
482     //2. Find owned device from the network
483     res = PMDeviceDiscovery(waitTimeForOwnedDeviceDiscovery, true, &pOwnedDevList);
484     if (OC_STACK_OK != res)
485     {
486         OIC_LOG(ERROR, TAG, "OCRemoveDeviceWithUuid : Failed to PMDeviceDiscovery");
487         goto error;
488     }
489
490     LL_FOREACH(pOwnedDevList, pTargetDev)
491     {
492         if(memcmp(&pTargetDev->doxm->deviceID.id, pTargetUuid->id, sizeof(pTargetUuid->id)) == 0)
493         {
494             break;
495         }
496     }
497
498     if(NULL == pTargetDev)
499     {
500         OIC_LOG_V(WARNING, TAG, "Can not find [%s] on the network.", strUuid);
501         OIC_LOG(WARNING, TAG, "Device information will be deleted from local and other devices.");
502
503         pTargetDev = (OCProvisionDev_t*)OICCalloc(1, sizeof(OCProvisionDev_t));
504         if(NULL == pTargetDev)
505         {
506             OIC_LOG(ERROR, TAG, "Failed to memory allocation.");
507             goto error;
508         }
509
510         pTargetDev->doxm = (OicSecDoxm_t*)OICCalloc(1, sizeof(OicSecDoxm_t));
511         if(NULL == pTargetDev->doxm)
512         {
513             OIC_LOG(ERROR, TAG, "Failed to memory allocation.");
514             goto error;
515         }
516
517         //in case of can't find target device, the device id required only.
518         memcpy(pTargetDev->doxm->deviceID.id, pTargetUuid->id, sizeof(pTargetUuid->id));
519     }
520     else
521     {
522         discoverdFlag = true;
523         OIC_LOG_V(INFO, TAG, "[%s] is dectected on the network.", strUuid);
524     }
525
526     OIC_LOG_V(INFO, TAG, "Trying [%s] revocation.", strUuid);
527
528     // Send DELETE requests to linked devices
529     OCStackResult resReq = OC_STACK_ERROR; // Check that we have to wait callback or not.
530     resReq = SRPRemoveDeviceWithoutDiscovery(ctx, pOwnedDevList, pTargetDev, resultCallback);
531     if (OC_STACK_OK != resReq)
532     {
533         if (OC_STACK_CONTINUE == resReq)
534         {
535             OIC_LOG(DEBUG, TAG, "OCRemoveDeviceWithUuid : Revoked device has no linked device except PT.");
536         }
537         else
538         {
539             OIC_LOG(ERROR, TAG, "OCRemoveDeviceWithUuid : Failed to invoke SRPRemoveDevice");
540             res = resReq;
541             goto error;
542         }
543     }
544
545     res = RemoveDeviceInfoFromLocal(pTargetDev);
546     if(OC_STACK_OK != res)
547     {
548         OIC_LOG(ERROR, TAG, "OCRemoveDeviceWithUuid : Filed to remove the device information from local.");
549         goto error;
550     }
551
552     if(OC_STACK_CONTINUE == resReq)
553     {
554         /**
555           * If there is no linked device, PM does not send any request.
556           * So we should directly invoke the result callback to inform the result of OCRemoveDevice.
557           */
558         if(resultCallback)
559         {
560             resultCallback(ctx, 0, NULL, false);
561         }
562         res = OC_STACK_OK;
563     }
564
565 error:
566     OICFree(strUuid);
567     PMDeleteDeviceList(pOwnedDevList);
568     if(pTargetDev && false == discoverdFlag)
569     {
570         OICFree(pTargetDev->doxm);
571         OICFree(pTargetDev);
572     }
573     OIC_LOG(INFO, TAG, "OUT OCRemoveDeviceWithUuid");
574     return res;
575 }
576
577 /*
578  * Function to reset the target device.
579  * This function will remove credential and ACL of target device from all devices in subnet.
580  *
581  * @param[in] ctx Application context would be returned in result callback
582  * @param[in] waitTimeForOwnedDeviceDiscovery Maximum wait time for owned device discovery.(seconds)
583  * @param[in] pTargetDev Device information to be revoked.
584  * @param[in] resultCallback callback provided by API user, callback will be called when
585  *            credential revocation is finished.
586  * @return  OC_STACK_OK in case of success and other value otherwise.
587  */
588 OCStackResult OCResetDevice(void* ctx, unsigned short waitTimeForOwnedDeviceDiscovery,
589                             const OCProvisionDev_t* pTargetDev,
590                             OCProvisionResultCB resultCallback)
591 {
592     OIC_LOG(INFO, TAG, "IN OCResetDevice");
593     OCStackResult res = OC_STACK_ERROR;
594     if (!pTargetDev || 0 == waitTimeForOwnedDeviceDiscovery)
595     {
596         OIC_LOG(INFO, TAG, "OCResetDevice : Invalid parameters");
597         return OC_STACK_INVALID_PARAM;
598     }
599     if (!resultCallback)
600     {
601         OIC_LOG(INFO, TAG, "OCResetDevice : NULL Callback");
602         return OC_STACK_INVALID_CALLBACK;
603     }
604
605     // Send DELETE requests to linked devices
606     res = SRPSyncDevice(ctx, waitTimeForOwnedDeviceDiscovery, pTargetDev, resultCallback);
607     if (OC_STACK_CONTINUE == res)
608     {
609         OIC_LOG(DEBUG, TAG, "OCResetDevice : Target device has no linked device except PT.");
610         if(resultCallback)
611         {
612             resultCallback(ctx, 0, NULL, false);
613         }
614         SRPResetDevice(pTargetDev, resultCallback);
615         res = OC_STACK_OK;
616     }
617     else if(OC_STACK_OK != res)
618     {
619         OIC_LOG(ERROR, TAG, "OCResetDevice : Failed to invoke SRPSyncDevice");
620     }
621     OIC_LOG(INFO, TAG, "OUT OCResetDevice");
622     return res;
623 }
624
625 /**
626  * Internal Function to update result in link result array.
627  */
628 static void UpdateLinkResults(Linkdata_t *link, int device, OCStackResult stackresult)
629 {
630
631     OIC_LOG_V(INFO,TAG,"value of link->currentCountResults is %d",link->currentCountResults);
632     if (1 == device)
633     {
634         memcpy(link->resArr[(link->currentCountResults)].deviceId.id, link->pDev1->doxm->deviceID.id,UUID_LENGTH);
635     }
636     else
637     {
638         memcpy(link->resArr[(link->currentCountResults)].deviceId.id, link->pDev2->doxm->deviceID.id,UUID_LENGTH);
639     }
640     link->resArr[(link->currentCountResults)].res = stackresult;
641     ++(link->currentCountResults);
642
643 }
644
645 /**
646  * Callback to handle ACL provisioning for device 2.
647  */
648 static void AclProv2CB(void* ctx, int nOfRes, OCProvisionResult_t *arr, bool hasError)
649 {
650
651     if (NULL == ctx)
652     {
653         OIC_LOG(ERROR,TAG,"Context is Null in ACLProv 2");
654         return;
655     }
656     (void)nOfRes;
657     Linkdata_t *link = (Linkdata_t*)ctx;
658     OCProvisionResultCB resultCallback = link->resultCallback;
659
660
661     if (hasError)
662     {
663         UpdateLinkResults(link, 2,arr[0].res);
664         OIC_LOG(ERROR,TAG,"Error occured while ACL provisioning device 1");
665         ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults,
666                                                 link->resArr,
667                                                 true);
668         OICFree(link->resArr);
669         OICFree(link) ;
670         return;
671     }
672     UpdateLinkResults(link, 2, arr[0].res);
673    ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults,
674                                            link->resArr,
675                                            false);
676     OICFree(link->resArr);
677     OICFree(link);
678     return;
679 }
680
681 /**
682  * Callback to handle ACL provisioning for device 1
683  */
684 static void AclProv1CB(void* ctx, int nOfRes, OCProvisionResult_t *arr, bool hasError)
685 {
686
687     if (NULL == ctx)
688     {
689         OIC_LOG(ERROR,TAG,"Context is Null in ACLProv1");
690         return;
691     }
692     (void)nOfRes;
693     Linkdata_t *link = (Linkdata_t*)ctx;
694     OCProvisionResultCB resultCallback = link->resultCallback;
695
696     if (hasError)
697     {
698         OIC_LOG(ERROR,TAG,"Error occured while ACL provisioning device 1");
699         UpdateLinkResults(link, 1, arr[0].res);
700         ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults,
701                                                 link->resArr,
702                                                 true);
703         OICFree(link->resArr);
704         OICFree(link);
705         return;
706     }
707     UpdateLinkResults(link, 1, arr[0].res);
708     if (NULL != link->pDev2Acl)
709     {
710         OCStackResult res =  SRPProvisionACL(ctx, link->pDev2, link->pDev2Acl, &AclProv2CB);
711         if (OC_STACK_OK!=res)
712         {
713              UpdateLinkResults(link, 2, res);
714              ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults,
715                                                      link->resArr,
716                                                      true);
717
718         }
719     }
720     else
721     {
722         ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults,
723                                                 link->resArr,
724                                                 false);
725         OICFree(link->resArr);
726         OICFree(link);
727     }
728
729     return;
730 }
731
732 /**
733  * Callback to handle credential provisioning.
734  */
735 static void ProvisionCredsCB(void* ctx, int nOfRes, OCProvisionResult_t *arr, bool hasError)
736 {
737     if (NULL == ctx)
738     {
739         OIC_LOG(ERROR,TAG,"Error occured while credential provisioning");
740         return;
741     }
742     Linkdata_t *link = (Linkdata_t*)ctx;
743     OCProvisionResultCB resultCallback = link->resultCallback;
744     OIC_LOG_V(INFO, TAG, "has error returned %d",hasError);
745     UpdateLinkResults(link, 1, arr[0].res);
746     UpdateLinkResults(link, 2, arr[1].res);
747     if (hasError)
748     {
749         OIC_LOG(ERROR,TAG,"Error occured while credential provisioning");
750         ((OCProvisionResultCB)(resultCallback))(link->ctx, nOfRes,
751                                                 link->resArr,
752                                                 true);
753          OICFree(link->resArr);
754          OICFree(link);
755          return;
756     }
757     if (NULL != link->pDev1Acl)
758     {
759
760         OCStackResult res =  SRPProvisionACL(ctx, link->pDev1, link->pDev1Acl, &AclProv1CB);
761         if (OC_STACK_OK!=res)
762         {
763              OIC_LOG(ERROR, TAG, "Error while provisioning ACL for device 1");
764              UpdateLinkResults(link, 1, res);
765              ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults,
766                                                      link->resArr,
767                                                      true);
768               OICFree(link->resArr);
769               OICFree(link);
770         }
771     }
772     else if (NULL!=link->pDev2Acl)
773     {
774         OIC_LOG(ERROR, TAG, "ACL for device 1 is NULL");
775         OCStackResult res =  SRPProvisionACL(ctx, link->pDev2, link->pDev2Acl, &AclProv2CB);
776         if (OC_STACK_OK!=res)
777         {
778              OIC_LOG(ERROR, TAG, "Error while provisioning ACL for device 2");
779               UpdateLinkResults(link, 2, res);
780              ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults,
781                                                      link->resArr,
782                                                      true);
783               OICFree(link->resArr);
784               OICFree(link);
785         }
786     }
787     else
788     {
789         OIC_LOG(INFO, TAG, "ACLs of both devices are NULL");
790         ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults,
791                                                 link->resArr,
792                                                 false);
793         OICFree(link->resArr);
794         OICFree(link);
795     }
796     return;
797 }
798 /**
799  * function to provision credentials between two devices and ACLs for the devices who act as a server.
800  *
801  * @param[in] ctx Application context would be returned in result callback.
802  * @param[in] type Type of credentials to be provisioned to the device.
803  * @param[in] pDev1 Pointer to OCProvisionDev_t instance,respresenting resource to be provsioned.
804  * @param[in] acl ACL for device 1. If this is not required set NULL.
805  * @param[in] pDev2 Pointer to OCProvisionDev_t instance,respresenting resource to be provsioned.
806  * @param[in] acl ACL for device 2. If this is not required set NULL.
807  * @param[in] resultCallback callback provided by API user, callback will be called when
808  *            provisioning request recieves a response from first resource server.
809  * @return  OC_STACK_OK in case of success and other value otherwise.
810  */
811 OCStackResult OCProvisionPairwiseDevices(void* ctx, OicSecCredType_t type, size_t keySize,
812                                          const OCProvisionDev_t *pDev1, OicSecAcl_t *pDev1Acl,
813                                          const OCProvisionDev_t *pDev2, OicSecAcl_t *pDev2Acl,
814                                          OCProvisionResultCB resultCallback)
815 {
816
817     if (!pDev1 || !pDev2 || !pDev1->doxm || !pDev2->doxm)
818     {
819         OIC_LOG(ERROR, TAG, "OCProvisionPairwiseDevices : Invalid parameters");
820         return OC_STACK_INVALID_PARAM;
821     }
822     if (!resultCallback)
823     {
824         OIC_LOG(INFO, TAG, "OCProvisionPairwiseDevices : NULL Callback");
825         return OC_STACK_INVALID_CALLBACK;
826     }
827     if (!(keySize == OWNER_PSK_LENGTH_128 || keySize == OWNER_PSK_LENGTH_256))
828     {
829         OIC_LOG(INFO, TAG, "OCProvisionPairwiseDevices : Invalid key size");
830         return OC_STACK_INVALID_PARAM;
831     }
832     if (0 == memcmp(&pDev1->doxm->deviceID, &pDev2->doxm->deviceID, sizeof(OicUuid_t)))
833     {
834         OIC_LOG(INFO, TAG, "OCProvisionPairwiseDevices : Same device ID");
835         return OC_STACK_INVALID_PARAM;
836     }
837
838     OIC_LOG(DEBUG, TAG, "Checking link in DB");
839     bool linkExists = true;
840     OCStackResult res = PDMIsLinkExists(&pDev1->doxm->deviceID, &pDev2->doxm->deviceID, &linkExists);
841     if(res != OC_STACK_OK)
842     {
843         OIC_LOG(ERROR, TAG, "Internal Error Occured");
844         return res;
845     }
846     if (linkExists)
847     {
848         OIC_LOG(ERROR, TAG, "Link already exists");
849         return OC_STACK_INVALID_PARAM;
850     }
851
852     int noOfResults = 2; // Initial Value
853     if (NULL != pDev1Acl)
854     {
855         ++noOfResults;
856     }
857     if (NULL != pDev2Acl)
858     {
859        ++noOfResults;
860     }
861     Linkdata_t *link = (Linkdata_t*) OICMalloc(sizeof(Linkdata_t));
862     if (!link)
863     {
864         OIC_LOG(ERROR, TAG, "Failed to memory allocation");
865         return OC_STACK_NO_MEMORY;
866     }
867     OIC_LOG_V(INFO,TAG, "Maximum no od results %d",noOfResults);
868
869     link->pDev1 = pDev1;
870     link->pDev1Acl = pDev1Acl;
871     link->pDev2 = pDev2;
872     link->pDev2Acl = pDev2Acl;
873     link->ctx = ctx;
874     // 1 call for each device for credential provisioning. implict call by SRPProvisioning credential
875     // 1 call for ACL provisioning for device 1 and 1 call for ACL provisioning for device 2.
876     link->numOfResults = noOfResults;
877     link->resultCallback = resultCallback;
878     link->currentCountResults = 0;
879     link->resArr = (OCProvisionResult_t*) OICMalloc(sizeof(OCProvisionResult_t)*noOfResults);
880     res = SRPProvisionCredentials(link, type, keySize,
881                                      pDev1, pDev2, &ProvisionCredsCB);
882     if (res != OC_STACK_OK)
883     {
884         OICFree(link->resArr);
885         OICFree(link);
886     }
887     return res;
888
889 }
890
891 OCStackResult OCGetDevInfoFromNetwork(unsigned short waittime,
892                                        OCProvisionDev_t** pOwnedDevList,
893                                        OCProvisionDev_t** pUnownedDevList)
894 {
895     //TODO will be replaced by more efficient logic
896     if (pOwnedDevList == NULL || *pOwnedDevList != NULL || pUnownedDevList == NULL
897          || *pUnownedDevList != NULL || 0 == waittime)
898     {
899         return OC_STACK_INVALID_PARAM;
900     }
901
902     // Code for unowned discovery
903     OCProvisionDev_t *unownedDevice = NULL;
904     OCStackResult res =  OCDiscoverUnownedDevices(waittime/2, &unownedDevice);
905     if (OC_STACK_OK != res)
906     {
907         OIC_LOG(ERROR,TAG, "Error in unowned discovery");
908         return res;
909     }
910
911     // Code for owned discovery
912     OCProvisionDev_t *ownedDevice = NULL;
913     res =  OCDiscoverOwnedDevices(waittime/2, &ownedDevice);
914     if (OC_STACK_OK != res)
915     {
916         OIC_LOG(ERROR,TAG, "Error in owned discovery");
917         PMDeleteDeviceList(unownedDevice);
918         return res;
919     }
920
921     // Code to get list of all the owned devices.
922     OCUuidList_t *uuidList = NULL;
923     size_t numOfDevices = 0;
924     res =  PDMGetOwnedDevices(&uuidList, &numOfDevices);
925     if (OC_STACK_OK != res)
926     {
927         OIC_LOG(ERROR, TAG, "Error while getting info from DB");
928         PMDeleteDeviceList(unownedDevice);
929         PMDeleteDeviceList(ownedDevice);
930         return res;
931     }
932
933     // Code to compare devices in unowned list and deviceid from DB
934     // (In case of hard reset of the device)
935     OCProvisionDev_t* pUnownedList = unownedDevice;
936     while (pUnownedList && uuidList)
937     {
938         OCUuidList_t *tmp1 = NULL,*tmp2=NULL;
939         LL_FOREACH_SAFE(uuidList, tmp1, tmp2)
940         {
941             if(0 == memcmp(tmp1->dev.id, pUnownedList->doxm->deviceID.id,
942                             sizeof(pUnownedList->doxm->deviceID.id)))
943             {
944                 OIC_LOG_V(INFO, TAG, "OCGetDevInfoFromNetwork : \
945                             Removing device id = %s in PDM and dat.", pUnownedList->doxm->deviceID.id);
946                 if (OC_STACK_OK != PDMDeleteDevice(&pUnownedList->doxm->deviceID))
947                 {
948                     OIC_LOG(ERROR, TAG, "OCGetDevInfoFromNetwork : \
949                             Failed to remove device in PDM.");
950                 }
951                 //remove the cred entry from dat file
952                 if (OC_STACK_OK != RemoveDeviceInfoFromLocal(pUnownedList))
953                 {
954                     OIC_LOG(ERROR, TAG, "OCGetDevInfoFromNetwork : \
955                             Failed to remove cred entry device in dat file.");
956                 }
957                 LL_DELETE(uuidList, tmp1);
958                 OICFree(tmp1);
959             }
960         }
961         pUnownedList = pUnownedList->next;
962     }
963     // Code to compare devices in owned list and deviceid from DB.
964     OCProvisionDev_t* pCurDev = ownedDevice;
965     size_t deleteCnt = 0;
966     while (pCurDev)
967     {
968         if(true == PMDeleteFromUUIDList(&uuidList, &pCurDev->doxm->deviceID))
969         {
970             deleteCnt++;
971         }
972         pCurDev = pCurDev->next;
973     }
974     // If there is no remaind device in uuidList, we have to assign NULL to prevent free.
975     if (deleteCnt == numOfDevices)
976     {
977         uuidList = NULL;
978     }
979     // Code to add information of the devices which are currently off in owned list.
980     OCUuidList_t *powerOffDeviceList = uuidList;
981     while (powerOffDeviceList)
982     {
983         OCProvisionDev_t *ptr = (OCProvisionDev_t *)OICCalloc(1, sizeof (OCProvisionDev_t));
984         if (NULL == ptr)
985         {
986             OIC_LOG(ERROR,TAG,"Fail to allocate memory");
987             PMDeleteDeviceList(unownedDevice);
988             PMDeleteDeviceList(ownedDevice);
989             OCDeleteUuidList(uuidList);
990             return OC_STACK_NO_MEMORY;
991         }
992
993         ptr->doxm = (OicSecDoxm_t*)OICCalloc(1, sizeof(OicSecDoxm_t));
994         if (NULL == ptr->doxm)
995         {
996             OIC_LOG(ERROR,TAG,"Fail to allocate memory");
997             PMDeleteDeviceList(unownedDevice);
998             PMDeleteDeviceList(ownedDevice);
999             OCDeleteUuidList(uuidList);
1000             OICFree(ptr);
1001             return OC_STACK_NO_MEMORY;
1002         }
1003
1004         memcpy(ptr->doxm->deviceID.id, powerOffDeviceList->dev.id, sizeof(ptr->doxm->deviceID.id));
1005
1006         ptr->devStatus = DEV_STATUS_OFF;
1007         LL_PREPEND(ownedDevice, ptr);
1008         powerOffDeviceList = powerOffDeviceList->next;
1009
1010     }
1011     OCDeleteUuidList(uuidList);
1012     *pOwnedDevList = ownedDevice;
1013     *pUnownedDevList = unownedDevice;
1014     return OC_STACK_OK;
1015 }
1016
1017 OCStackResult OCGetLinkedStatus(const OicUuid_t* uuidOfDevice, OCUuidList_t** uuidList,
1018                                  size_t* numOfDevices)
1019 {
1020     return PDMGetLinkedDevices(uuidOfDevice, uuidList, numOfDevices);
1021 }
1022
1023 void OCDeleteUuidList(OCUuidList_t* pList)
1024 {
1025     PDMDestoryOicUuidLinkList(pList);
1026 }
1027
1028 /**
1029  * This function deletes ACL data.
1030  *
1031  * @param pAcl Pointer to OicSecAcl_t structure.
1032  */
1033 void OCDeleteACLList(OicSecAcl_t* pAcl)
1034 {
1035     DeleteACLList(pAcl);
1036 }
1037
1038 /**
1039  * This function deletes PDACL data.
1040  *
1041  * @param pPdAcl Pointer to OicSecPdAcl_t structure.
1042  */
1043 void OCDeletePdAclList(OicSecPdAcl_t* pPdAcl)
1044 {
1045     FreePdAclList(pPdAcl);
1046 }
1047 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
1048 /**
1049  * function to provision Trust certificate chain to devices.
1050  *
1051  * @param[in] ctx Application context would be returned in result callback.
1052  * @param[in] type Type of credentials to be provisioned to the device.
1053  * @param[in] credId CredId of trust certificate chain to be provisioned to the device.
1054  * @param[in] selectedDeviceInfo Pointer to OCProvisionDev_t instance,respresenting resource to be provsioned.
1055  * @param[in] resultCallback callback provided by API user, callback will be called when
1056  *            provisioning request recieves a response from first resource server.
1057  * @return  OC_STACK_OK in case of success and other value otherwise.
1058  */
1059 OCStackResult OCProvisionTrustCertChain(void *ctx, OicSecCredType_t type, uint16_t credId,
1060                                       const OCProvisionDev_t *selectedDeviceInfo,
1061                                       OCProvisionResultCB resultCallback)
1062 {
1063     return SRPProvisionTrustCertChain(ctx, type, credId,
1064                                       selectedDeviceInfo, resultCallback);
1065 }
1066 /**
1067  * function to save Trust certificate chain into Cred of SVR.
1068  *
1069  * @param[in] trustCertChain Trust certificate chain to be saved in Cred of SVR.
1070  * @param[in] chainSize Size of trust certificate chain to be saved in Cred of SVR
1071  * @param[in] encodingType Encoding type of trust certificate chain to be saved in Cred of SVR
1072  * @param[out] credId CredId of saved trust certificate chain in Cred of SVR.
1073  * @return  OC_STACK_OK in case of success and other value otherwise.
1074  */
1075 OCStackResult OCSaveTrustCertChain(uint8_t *trustCertChain, size_t chainSize,
1076                                     OicEncodingType_t encodingType, uint16_t *credId)
1077 {
1078     return SRPSaveTrustCertChain(trustCertChain, chainSize, encodingType, credId);
1079 }
1080
1081 #endif // __WITH_DTLS__ || __WITH_TLS__
1082