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