Merge branch 'simulator'.
[platform/upstream/iotivity.git] / resource / csdk / security / provisioning / sample / provisioningclient.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
21 #include <stdio.h>
22 #include <string.h>
23 #include <unistd.h>
24
25 #include "logger.h"
26 #include "oic_malloc.h"
27 #include "oic_string.h"
28 #include "ocprovisioningmanager.h"
29 #include "oxmjustworks.h"
30 #include "oxmrandompin.h"
31 #include "securevirtualresourcetypes.h"
32 #include "srmutility.h"
33 #include "pmtypes.h"
34
35 #ifdef __cplusplus
36 extern "C"
37 {
38 #endif //__cplusplus
39
40 // declaration(s) for provisioning client using C-level provisioning API
41 // user input definition for main loop on provisioning client
42 #define _10_DISCOV_ALL_DEVS_    10
43 #define _11_DISCOV_UNOWN_DEVS_  11
44 #define _12_DISCOV_OWN_DEVS_    12
45 #define _20_REGIST_DEVS_        20
46 #define _30_PROVIS_PAIR_DEVS_   30
47 #define _31_PROVIS_CRED_        31
48 #define _32_PROVIS_ACL_         32
49 #define _33_CHECK_LINK_STATUS_  33
50 #define _40_UNLINK_PAIR_DEVS_   40
51 #define _50_REMOVE_SELEC_DEV_   50
52 #define _99_EXIT_PRVN_CLT_      99
53
54 #define ACL_RESRC_MAX_NUM   16
55 #define ACL_RESRC_MAX_LEN   128
56 #define ACL_PEMISN_CNT      5
57 #define DISCOVERY_TIMEOUT   10  // 10 sec
58 #define CALLBACK_TIMEOUT    60  // 1 min
59 #define TAG "provisioningclient"
60
61 static const char* ACL_PEMISN[5] = {"CREATE", "READ", "WRITE", "DELETE", "NOTIFY"};
62 static const char* SVR_DB_FILE_NAME = "oic_svr_db_client.json";
63         // '_' for separaing from the same constant variable in |srmresourcestrings.c|
64 static const char* PRVN_DB_FILE_NAME = "oic_prvn_mng.db";
65 // |g_ctx| means provision manager application context and
66 // the following, includes |un/own_list|, could be variables, which |g_ctx| has,
67 // for accessing all function(s) for these, they are declared on global domain
68 static const char* g_ctx = "Provision Manager Client Application Context";
69 static char* g_svr_fname;
70 static char* g_prvn_fname;
71 static OCProvisionDev_t* g_own_list;
72 static OCProvisionDev_t* g_unown_list;
73 static int g_own_cnt;
74 static int g_unown_cnt;
75 static bool g_doneCB;
76
77 // function declaration(s) for calling them before implementing
78 static OicSecAcl_t* createAcl(const int);
79 static OCProvisionDev_t* getDevInst(const OCProvisionDev_t*, const int);
80 static int printDevList(const OCProvisionDev_t*);
81 static size_t printUuidList(const OCUuidList_t*);
82 static int printResultList(const OCProvisionResult_t*, const int);
83 static void printUuid(const OicUuid_t*);
84 static FILE* fopen_prvnMng(const char*, const char*);
85 static int waitCallbackRet(void);
86 static int selectTwoDiffNum(int*, int*, const int, const char*);
87
88 // callback function(s) for provisioning client using C-level provisioning API
89 static void ownershipTransferCB(void* ctx, int nOfRes, OCProvisionResult_t* arr, bool hasError)
90 {
91     if(!hasError)
92     {
93         OIC_LOG_V(INFO, TAG, "Ownership Transfer SUCCEEDED - ctx: %s", (char*) ctx);
94     }
95     else
96     {
97         OIC_LOG_V(ERROR, TAG, "Ownership Transfer FAILED - ctx: %s", (char*) ctx);
98         printResultList((const OCProvisionResult_t*) arr, nOfRes);
99     }
100     g_doneCB = true;
101 }
102
103 static void provisionPairwiseCB(void* ctx, int nOfRes, OCProvisionResult_t* arr, bool hasError)
104 {
105     if(!hasError)
106     {
107         OIC_LOG_V(INFO, TAG, "Provision Pairwise SUCCEEDED - ctx: %s", (char*) ctx);
108     }
109     else
110     {
111         OIC_LOG_V(ERROR, TAG, "Provision Pairwise FAILED - ctx: %s", (char*) ctx);
112         printResultList((const OCProvisionResult_t*) arr, nOfRes);
113     }
114     g_doneCB = true;
115 }
116
117 static void provisionCredCB(void* ctx, int nOfRes, OCProvisionResult_t* arr, bool hasError)
118 {
119     if(!hasError)
120     {
121         OIC_LOG_V(INFO, TAG, "Provision Credential SUCCEEDED - ctx: %s", (char*) ctx);
122     }
123     else
124     {
125         OIC_LOG_V(ERROR, TAG, "Provision Credential FAILED - ctx: %s", (char*) ctx);
126         printResultList((const OCProvisionResult_t*) arr, nOfRes);
127     }
128     g_doneCB = true;
129 }
130
131 static void provisionAclCB(void* ctx, int nOfRes, OCProvisionResult_t* arr, bool hasError)
132 {
133     if(!hasError)
134     {
135         OIC_LOG_V(INFO, TAG, "Provision ACL SUCCEEDED - ctx: %s", (char*) ctx);
136     }
137     else
138     {
139         OIC_LOG_V(ERROR, TAG, "Provision ACL FAILED - ctx: %s", (char*) ctx);
140         printResultList((const OCProvisionResult_t*) arr, nOfRes);
141     }
142     g_doneCB = true;
143 }
144
145 static void unlinkDevicesCB(void* ctx, int nOfRes, OCProvisionResult_t* arr, bool hasError)
146 {
147     if(!hasError)
148     {
149         OIC_LOG_V(INFO, TAG, "Unlink Devices SUCCEEDED - ctx: %s", (char*) ctx);
150     }
151     else
152     {
153         OIC_LOG_V(ERROR, TAG, "Unlink Devices FAILED - ctx: %s", (char*) ctx);
154         printResultList((const OCProvisionResult_t*) arr, nOfRes);
155     }
156     g_doneCB = true;
157 }
158
159 static void removeDeviceCB(void* ctx, int nOfRes, OCProvisionResult_t* arr, bool hasError)
160 {
161     if(!hasError)
162     {
163         OIC_LOG_V(INFO, TAG, "Remove Device SUCCEEDED - ctx: %s", (char*) ctx);
164     }
165     else
166     {
167         OIC_LOG_V(ERROR, TAG, "Remove Device FAILED - ctx: %s", (char*) ctx);
168         printResultList((const OCProvisionResult_t*) arr, nOfRes);
169     }
170     g_doneCB = true;
171 }
172
173 static void inputPinCB(char* pin, size_t len)
174 {
175     if(!pin || OXM_RANDOM_PIN_SIZE>=len)
176     {
177         OIC_LOG(ERROR, TAG, "inputPinCB invalid parameters");
178         return;
179     }
180
181     printf("   > INPUT PIN: ");
182     for(int ret=0; 1!=ret; )
183     {
184         ret = scanf("%8s", pin);
185         for( ; 0x20<=getchar(); );  // for removing overflow garbages
186                                     // '0x20<=code' is character region
187     }
188 }
189
190 // function(s) for provisioning client using C-level provisioning API
191 static int initProvisionClient(void)
192 {
193     // initialize persistent storage for SVR DB
194     static OCPersistentStorage pstStr =
195     {
196         .open = fopen_prvnMng,
197         .read = fread,
198         .write = fwrite,
199         .close = fclose,
200         .unlink = unlink
201     };
202     if(OC_STACK_OK != OCRegisterPersistentStorageHandler(&pstStr))
203     {
204         OIC_LOG(ERROR, TAG, "OCRegisterPersistentStorageHandler error");
205         return -1;
206     }
207
208     // initialize OC stack and provisioning manager
209     if(OC_STACK_OK != OCInit(NULL, 0, OC_CLIENT_SERVER))
210     {
211         OIC_LOG(ERROR, TAG, "OCStack init error");
212         return -1;
213     }
214
215     if (access(PRVN_DB_FILE_NAME, F_OK) != -1)
216     {
217         printf("************************************************************\n");
218         printf("************Provisioning DB file already exists.************\n");
219         printf("************************************************************\n");
220     }
221     else
222     {
223         printf("*************************************************************\n");
224         printf("************No provisioning DB file, creating new************\n");
225         printf("*************************************************************\n");
226     }
227
228     if(OC_STACK_OK != OCInitPM(PRVN_DB_FILE_NAME))
229     {
230         OIC_LOG(ERROR, TAG, "OC_PM init error");
231         return -1;
232     }
233
234     // register callback function(s) to each OxM
235     OTMCallbackData_t otmcb =
236     {
237         .loadSecretCB = LoadSecretJustWorksCallback,
238         .createSecureSessionCB = CreateSecureSessionJustWorksCallback,
239         .createSelectOxmPayloadCB = CreateJustWorksSelectOxmPayload,
240         .createOwnerTransferPayloadCB = CreateJustWorksOwnerTransferPayload
241     };
242     if(OC_STACK_OK != OCSetOwnerTransferCallbackData(OIC_JUST_WORKS, &otmcb))
243     {
244         OIC_LOG(ERROR, TAG, "OCSetOwnerTransferCallbackData error: OIC_JUST_WORKS");
245         return -1;
246     }
247     otmcb.loadSecretCB = InputPinCodeCallback;
248     otmcb.createSecureSessionCB = CreateSecureSessionRandomPinCallbak;
249     otmcb.createSelectOxmPayloadCB = CreatePinBasedSelectOxmPayload;
250     otmcb.createOwnerTransferPayloadCB = CreatePinBasedOwnerTransferPayload;
251     if(OC_STACK_OK != OCSetOwnerTransferCallbackData(OIC_RANDOM_DEVICE_PIN, &otmcb))
252     {
253         OIC_LOG(ERROR, TAG, "OCSetOwnerTransferCallbackData error: OIC_RANDOM_DEVICE_PIN");
254         return -1;
255     }
256     SetInputPinCB(inputPinCB);
257
258     return 0;
259 }
260
261 static int discoverAllDevices(void)
262 {
263     // delete un/owned device lists before updating them
264     if(g_own_list)
265     {
266         OCDeleteDiscoveredDevices(g_own_list);
267         g_own_list = NULL;
268     }
269     if(g_unown_list)
270     {
271         OCDeleteDiscoveredDevices(g_unown_list);
272         g_unown_list = NULL;
273     }
274
275     // call |OCGetDevInfoFromNetwork| API actually
276     printf("   Discovering All Un/Owned Devices on Network..\n");
277     if(OC_STACK_OK != OCGetDevInfoFromNetwork(DISCOVERY_TIMEOUT, &g_own_list, &g_unown_list))
278     {
279         OIC_LOG(ERROR, TAG, "OCGetDevInfoFromNetwork API error");
280         return -1;
281     }
282
283     // display the discovered un/owned lists
284     printf("   > Discovered Owned Devices\n");
285     g_own_cnt = printDevList(g_own_list);
286     printf("   > Discovered Unowned Devices\n");
287     g_unown_cnt = printDevList(g_unown_list);
288
289     return 0;
290 }
291
292
293 static int discoverUnownedDevices(void)
294 {
295     // delete unowned device list before updating it
296     if(g_unown_list)
297     {
298         OCDeleteDiscoveredDevices(g_unown_list);
299         g_unown_list = NULL;
300     }
301
302     // call |OCDiscoverUnownedDevices| API actually
303     printf("   Discovering Only Unowned Devices on Network..\n");
304     if(OC_STACK_OK != OCDiscoverUnownedDevices(DISCOVERY_TIMEOUT, &g_unown_list))
305     {
306         OIC_LOG(ERROR, TAG, "OCDiscoverUnownedDevices API error");
307         return -1;
308     }
309
310     // display the discovered unowned list
311     printf("   > Discovered Unowned Devices\n");
312     g_unown_cnt = printDevList(g_unown_list);
313
314     return 0;
315 }
316
317 static int discoverOwnedDevices(void)
318 {
319     // delete owned device list before updating it
320     if(g_own_list)
321     {
322         OCDeleteDiscoveredDevices(g_own_list);
323         g_own_list = NULL;
324     }
325
326     // call |OCDiscoverOwnedDevices| API actually
327     printf("   Discovering Only Owned Devices on Network..\n");
328     if(OC_STACK_OK != OCDiscoverOwnedDevices(DISCOVERY_TIMEOUT, &g_own_list))
329     {
330         OIC_LOG(ERROR, TAG, "OCDiscoverOwnedDevices API error");
331         return -1;
332     }
333
334     // display the discovered owned list
335     printf("   > Discovered Owned Devices\n");
336     g_own_cnt = printDevList(g_own_list);
337
338     return 0;
339 }
340
341 static int registerDevices(void)
342 {
343     // check |unown_list| for registering devices
344     if(!g_unown_list || 0>=g_unown_cnt)
345     {
346         printf("   > Unowned Device List, to Register Devices, is Empty\n");
347         printf("   > Please Discover Unowned Devices first, with [10|11] Menu\n");
348         return 0;  // normal case
349     }
350
351     // call |OCDoOwnershipTransfer| API actually
352     // calling this API with callback actually acts like blocking
353     // for error checking, the return value saved and printed
354     g_doneCB = false;
355     printf("   Registering All Discovered Unowned Devices..\n");
356     OCStackResult rst = OCDoOwnershipTransfer((void*) g_ctx, g_unown_list, ownershipTransferCB);
357     if(OC_STACK_OK != rst)
358     {
359         OIC_LOG_V(ERROR, TAG, "OCDoOwnershipTransfer API error: %d", rst);
360         return -1;
361     }
362     if(waitCallbackRet())  // input |g_doneCB| flag implicitly
363     {
364         OIC_LOG(ERROR, TAG, "OCProvisionCredentials callback error");
365         return -1;
366     }
367
368     // display the registered result
369     printf("   > Registered Discovered Unowned Devices\n");
370     printf("   > Please Discover Owned Devices for the Registered Result, with [10|12] Menu\n");
371
372     return 0;
373 }
374
375 static int provisionPairwise(void)
376 {
377     // check |own_list| for provisioning pairwise devices
378     if(!g_own_list || 2>g_own_cnt)
379     {
380         printf("   > Owned Device List, to Provision the Pairwise, is Empty\n");
381         printf("   > Please Register Unowned Devices first, with [20] Menu\n");
382         return 0;  // normal case
383     }
384
385     // select two devices for provisioning pairwise devices
386     int dev_num[2] = {0};
387     if(selectTwoDiffNum(&(dev_num[0]), &(dev_num[1]), g_own_cnt, "for Linking Devices"))
388     {
389         OIC_LOG(ERROR, TAG, "selectTwoDiffNum error return");
390         return -1;  // not need to 'goto' |ERROR| before allocating |acl|
391     }
392
393     // create ACL(s) for each selected device
394     OicSecAcl_t* acl[2] = {0};
395     for(int i=0; 2>i; ++i)
396     {
397         acl[i] = createAcl(dev_num[i]);
398         if(!acl[i])
399         {
400             OIC_LOG(ERROR, TAG, "createAcl error return");
401             goto PVPWS_ERROR;
402         }
403     }
404
405     // call |OCProvisionPairwiseDevices| API actually
406     // calling this API with callback actually acts like blocking
407     // for error checking, the return value saved and printed
408     g_doneCB = false;
409     printf("   Provisioning Selected Pairwise Devices..\n");
410     OCStackResult rst =
411             OCProvisionPairwiseDevices((void*) g_ctx,
412                     SYMMETRIC_PAIR_WISE_KEY, OWNER_PSK_LENGTH_128,
413                     getDevInst((const OCProvisionDev_t*) g_own_list, dev_num[0]), acl[0],
414                     getDevInst((const OCProvisionDev_t*) g_own_list, dev_num[1]), acl[1],
415                     provisionPairwiseCB);
416     if(OC_STACK_OK != rst)
417     {
418         OIC_LOG_V(ERROR, TAG, "OCProvisionPairwiseDevices API error: %d", rst);
419         goto PVPWS_ERROR;
420     }
421     if(waitCallbackRet())  // input |g_doneCB| flag implicitly
422     {
423         OIC_LOG(ERROR, TAG, "OCProvisionCredentials callback error");
424         goto PVPWS_ERROR;
425     }
426     OCDeleteACLList(acl[0]);
427     OCDeleteACLList(acl[1]);
428
429     // display the pairwise-provisioned result
430     printf("   > Provisioned Selected Pairwise Devices\n");
431     printf("   > Please Check Device's Status for the Linked Result, with [33] Menu\n");
432
433     return 0;
434
435 PVPWS_ERROR:
436     OCDeleteACLList(acl[0]);
437     OCDeleteACLList(acl[1]);
438     return -1;
439 }
440
441 static int provisionCred(void)
442 {
443     // check |own_list| for provisioning pairwise credentials
444     if(!g_own_list || 2>g_own_cnt)
445     {
446         printf("   > Owned Device List, to Provision Credentials, is Empty\n");
447         printf("   > Please Register Unowned Devices first, with [20] Menu\n");
448         return 0;  // normal case
449     }
450
451     // select two devices for provisioning pairwise credentials
452     int dev_num[2] = {0};
453     if(selectTwoDiffNum(&(dev_num[0]), &(dev_num[1]), g_own_cnt, "for Linking CRED(s)"))
454     {
455         OIC_LOG(ERROR, TAG, "selectTwoDiffNum error return");
456         return -1;
457     }
458
459     printf("   Select PSK length..\n");
460     printf("   1 - 128bit(Default)\n");
461     printf("   2 - 256bit\n");
462     int sizeOption = 0;
463
464     for(int ret=0; 1!=ret; )
465     {
466          ret = scanf("%d",&sizeOption);
467          for( ; 0x20<=getchar(); );  // for removing overflow garbages
468                                     // '0x20<=code' is character region
469     }
470     size_t size = 0;
471
472     switch(sizeOption)
473     {
474         case 1:
475         {
476             size = OWNER_PSK_LENGTH_128;
477             break;
478         }
479         case 2:
480         {
481             size = OWNER_PSK_LENGTH_256;
482             break;
483         }
484         default:
485         {
486             size = OWNER_PSK_LENGTH_128;
487             break;
488         }
489     }
490
491
492     // call |OCProvisionCredentials| API actually
493     // calling this API with callback actually acts like blocking
494     // for error checking, the return value saved and printed
495     g_doneCB = false;
496     printf("   Provisioning Selected Pairwise Credentials..\n");
497     OCStackResult rst =
498             OCProvisionCredentials((void*) g_ctx,
499                     SYMMETRIC_PAIR_WISE_KEY, size,
500                     getDevInst((const OCProvisionDev_t*) g_own_list, dev_num[0]),
501                     getDevInst((const OCProvisionDev_t*) g_own_list, dev_num[1]),
502                     provisionCredCB);
503     if(OC_STACK_OK != rst)
504     {
505         OIC_LOG_V(ERROR, TAG, "OCProvisionCredentials API error: %d", rst);
506         return -1;
507     }
508     if(waitCallbackRet())  // input |g_doneCB| flag implicitly
509     {
510         OIC_LOG(ERROR, TAG, "OCProvisionCredentials callback error");
511         return -1;
512     }
513
514     // display the CRED-provisioned result
515     printf("   > Provisioned Selected Pairwise Crendentials\n");
516     printf("   > Please Check Device's Status for the Linked Result, with [33] Menu\n");
517
518     return 0;
519 }
520
521 static int provisionAcl(void)
522 {
523     // check |own_list| for provisioning access control list
524     if(!g_own_list || 1>g_own_cnt)
525     {
526         printf("   > Owned Device List, to Provision ACL, is Empty\n");
527         printf("   > Please Register Unowned Devices first, with [20] Menu\n");
528         return 0;  // normal case
529     }
530
531     // select device for provisioning access control list
532     int dev_num = 0;
533     for( ; ; )
534     {
535         printf("   > Enter Device Number, for Provisioning ACL: ");
536         for(int ret=0; 1!=ret; )
537         {
538             ret = scanf("%d", &dev_num);
539             for( ; 0x20<=getchar(); );  // for removing overflow garbages
540                                         // '0x20<=code' is character region
541         }
542         if(0<dev_num && g_own_cnt>=dev_num)
543         {
544             break;
545         }
546         printf("     Entered Wrong Number. Please Enter Again\n");
547     }
548
549     // create ACL for selected device
550     OicSecAcl_t* acl = NULL;
551     acl = createAcl(dev_num);
552     if(!acl)
553     {
554         OIC_LOG(ERROR, TAG, "createAcl error return");
555         goto PVACL_ERROR;
556     }
557
558     // call |OCProvisionACL| API actually
559     // calling this API with callback actually acts like blocking
560     // for error checking, the return value saved and printed
561     g_doneCB = false;
562     printf("   Provisioning Selected ACL..\n");
563     OCStackResult rst =
564             OCProvisionACL((void*) g_ctx,
565                     getDevInst((const OCProvisionDev_t*) g_own_list, dev_num),
566                     acl, provisionAclCB);
567     if(OC_STACK_OK != rst)
568     {
569         OIC_LOG_V(ERROR, TAG, "OCProvisionACL API error: %d", rst);
570         goto PVACL_ERROR;
571     }
572     if(waitCallbackRet())  // input |g_doneCB| flag implicitly
573     {
574         OIC_LOG(ERROR, TAG, "OCProvisionCredentials callback error");
575         goto PVACL_ERROR;
576     }
577     OCDeleteACLList(acl);  // after here |acl| points nothing
578
579     // display the ACL-provisioned result
580     printf("   > Provisioned Selected ACL\n");
581
582     return 0;
583
584 PVACL_ERROR:
585     OCDeleteACLList(acl);  // after here |acl| points nothing
586     return -1;
587 }
588
589 static int checkLinkedStatus(void)
590 {
591     // check |own_list| for checking selected link status on PRVN DB
592     if(!g_own_list || 1>g_own_cnt)
593     {
594         printf("   > Owned Device List, to Check Linked Status on PRVN DB, is Empty\n");
595         printf("   > Please Register Unowned Devices first, with [20] Menu\n");
596         return 0;  // normal case
597     }
598
599     // select device for checking selected link status on PRVN DB
600     int dev_num = 0;
601     for( ; ; )
602     {
603         printf("   > Enter Device Number, for Checking Linked Status on PRVN DB: ");
604         for(int ret=0; 1!=ret; )
605         {
606             ret = scanf("%d", &dev_num);
607             for( ; 0x20<=getchar(); );  // for removing overflow garbages
608                                         // '0x20<=code' is character region
609         }
610         if(0<dev_num && g_own_cnt>=dev_num)
611         {
612             break;
613         }
614         printf("     Entered Wrong Number. Please Enter Again\n");
615     }
616
617     // call |OCGetLinkedStatus| API actually
618     printf("   Checking Selected Link Status on PRVN DB..\n");
619     OCUuidList_t* dvid_lst = NULL;
620     size_t dvid_cnt = 0;
621     OCProvisionDev_t* dev = getDevInst((const OCProvisionDev_t*)g_own_list, dev_num);
622     if(!dev || !dev->doxm)
623     {
624         OIC_LOG(ERROR, TAG, "checkLinkedStatus: device instance empty");
625         goto CKLST_ERROR;
626     }
627
628     if(OC_STACK_OK !=
629             OCGetLinkedStatus(
630                     &dev->doxm->deviceID,
631                     &dvid_lst, &dvid_cnt))  // allow empty list
632     {
633         OIC_LOG(ERROR, TAG, "OCGetLinkedStatus API error");
634         goto CKLST_ERROR;
635     }
636
637     // display the linked status result
638     printf("   > Checked Selected Link Status on PRVN DB\n");
639     if(!dvid_lst || !dvid_cnt)  // |size_t| is unsigned
640     {
641         printf("     Linked Device List is Empty..\n");
642         return 0;  // normal case
643     }
644     if(dvid_cnt != printUuidList((const OCUuidList_t*) dvid_lst))
645     {
646         OIC_LOG(ERROR, TAG, "printUuidList error return");
647         goto CKLST_ERROR;
648     }
649     OCDeleteUuidList(dvid_lst);
650
651     return 0;
652
653 CKLST_ERROR:
654     OCDeleteUuidList(dvid_lst);
655     return -1;
656 }
657
658 static int unlinkPairwise(void)
659 {
660     // check |own_list| for unlinking pairwise devices
661     if(!g_own_list || 2>g_own_cnt)
662     {
663         printf("   > Owned Device List, to Unlink the Pairwise, is Empty\n");
664         printf("   > Please Register Unowned Devices first, with [20] Menu\n");
665         return 0;  // normal case
666     }
667
668     // select two devices for unlinking pairwise devices
669     int dev_num[2] = {0};
670     if(selectTwoDiffNum(&(dev_num[0]), &(dev_num[1]), g_own_cnt, "for Unlinking Devices"))
671     {
672         OIC_LOG(ERROR, TAG, "selectTwoDiffNum error return");
673         return -1;
674     }
675
676     // call |OCUnlinkDevices| API actually
677     // calling this API with callback actually acts like blocking
678     // for error checking, the return value saved and printed
679     g_doneCB = false;
680     printf("   Unlinking Selected Pairwise Devices..\n");
681     OCStackResult rst =
682             OCUnlinkDevices((void*) g_ctx,
683                     getDevInst((const OCProvisionDev_t*) g_own_list, dev_num[0]),
684                     getDevInst((const OCProvisionDev_t*) g_own_list, dev_num[1]),
685                     unlinkDevicesCB);
686     if(OC_STACK_OK != rst)
687     {
688         OIC_LOG_V(ERROR, TAG, "OCUnlinkDevices API error: %d", rst);
689         return -1;
690     }
691     if(waitCallbackRet())  // input |g_doneCB| flag implicitly
692     {
693         OIC_LOG(ERROR, TAG, "OCProvisionCredentials callback error");
694         return -1;
695     }
696
697     // display the pairwise-unlinked result
698     printf("   > Unlinked Selected Pairwise Devices\n");
699     printf("   > Please Check Device's Status for the Unlinked Result, with [33] Menu\n");
700
701     return 0;
702 }
703
704 static int removeDevice(void)
705 {
706     // check |own_list| for removing device
707     if(!g_own_list || 1>g_own_cnt)
708     {
709         printf("   > Owned Device List, to Remove Device, is Empty\n");
710         printf("   > Please Register Unowned Devices first, with [20] Menu\n");
711         return 0;  // normal case
712     }
713
714     // select device for removing it
715     int dev_num = 0;
716     for( ; ; )
717     {
718         printf("   > Enter Device Number, for Removing Device: ");
719         for(int ret=0; 1!=ret; )
720         {
721             ret = scanf("%d", &dev_num);
722             for( ; 0x20<=getchar(); );  // for removing overflow garbages
723                                         // '0x20<=code' is character region
724         }
725         if(0<dev_num && g_own_cnt>=dev_num)
726         {
727             break;
728         }
729         printf("     Entered Wrong Number. Please Enter Again\n");
730     }
731
732     // call |OCRemoveDevice| API actually
733     // calling this API with callback actually acts like blocking
734     // for error checking, the return value saved and printed
735     g_doneCB = false;
736     printf("   Removing Selected Owned Device..\n");
737     OCStackResult rst =
738             OCRemoveDevice((void*) g_ctx, DISCOVERY_TIMEOUT,
739                     getDevInst((const OCProvisionDev_t*) g_own_list, dev_num), removeDeviceCB);
740     if(OC_STACK_OK != rst)
741     {
742         OIC_LOG_V(ERROR, TAG, "OCRemoveDevice API error: %d", rst);
743         return -1;
744     }
745     if(waitCallbackRet())  // input |g_doneCB| flag implicitly
746     {
747         OIC_LOG(ERROR, TAG, "OCProvisionCredentials callback error");
748         return -1;
749     }
750
751     // display the removed result
752     printf("   > Removed Selected Owned Device\n");
753     printf("   > Please Discover Owned Devices for the Registered Result, with [10|12] Menu\n");
754
755     return 0;
756 }
757
758 static OicSecAcl_t* createAcl(const int dev_num)
759 {
760     if(0>=dev_num || g_own_cnt<dev_num)
761     {
762         OIC_LOG(ERROR, TAG, "createAcl invalid parameters");
763         return NULL;  // not need to 'goto' |ERROR| before allocating |acl|
764     }
765
766     // allocate memory for |acl| struct
767     printf("   **** Create ACL for the Selected Device[%d]\n", dev_num);
768     OicSecAcl_t* acl = (OicSecAcl_t*) OICCalloc(1, sizeof(OicSecAcl_t));
769     if(!acl)
770     {
771         OIC_LOG(ERROR, TAG, "createAcl: OICCalloc error return");
772         return NULL;  // not need to 'goto' |ERROR| before allocating |acl|
773     }
774
775     // enter |subject| device number
776     int num = 0;
777     for( ; ; )
778     {
779         printf("   > [A] Enter Subject Device Number: ");
780         for(int ret=0; 1!=ret; )
781         {
782             ret = scanf("%d", &num);
783             for( ; 0x20<=getchar(); );  // for removing overflow garbages
784                                         // '0x20<=code' is character region
785         }
786         if(num && g_own_cnt>=num && dev_num!=num)
787         {
788             break;
789         }
790         printf("     Entered Wrong Number. Please Enter Again\n");
791     }
792
793     OCProvisionDev_t* dev = getDevInst((const OCProvisionDev_t*)g_own_list, num);
794     if(!dev || !dev->doxm)
795     {
796         OIC_LOG(ERROR, TAG, "createAcl: device instance empty");
797         goto CRACL_ERROR;
798     }
799     memcpy(&acl->subject, &dev->doxm->deviceID, UUID_LENGTH);
800
801     // enter number of |resources| in 'accessed' device
802     for( ; ; )
803     {
804         printf("   > [B] Enter Number of Accessed Resources (under 16): ");
805                 // '16' is |ACL_RESRC_MAX_NUM|
806         for(int ret=0; 1!=ret; )
807         {
808             ret = scanf("%zu", &acl->resourcesLen);
809             for( ; 0x20<=getchar(); );  // for removing overflow garbages
810                                         // '0x20<=code' is character region
811         }
812         if(acl->resourcesLen && ACL_RESRC_MAX_NUM>=acl->resourcesLen)
813                 // |acl->resourcesLen| is unsigned
814         {
815             break;
816         }
817         printf("     Entered Wrong Number. Please Enter under 16 Again\n");
818                 // '16' is |ACL_RESRC_MAX_NUM|
819     }
820
821     // enter actually each 'accessed' |resources| name
822     printf("         Enter Each Accessed Resource Name (each under 128 char)\n");
823             // '128' is ACL_RESRC_MAX_LEN
824     num = acl->resourcesLen;
825     acl->resources = (char**) OICCalloc(num, sizeof(char*));
826     if(!acl->resources)
827     {
828         OIC_LOG(ERROR, TAG, "createAcl: OICCalloc error return");
829         goto CRACL_ERROR;
830     }
831     char rsrc_in[ACL_RESRC_MAX_LEN+1] = {0};  // '1' for null termination
832     for(int i=0; num>i; ++i)
833     {
834         printf("         Enter Accessed Resource[%d] Name: ", i+1);
835         for(int ret=0; 1!=ret; )
836         {
837             ret = scanf("%128s", rsrc_in);  // '128' is ACL_RESRC_MAX_LEN
838             for( ; 0x20<=getchar(); );  // for removing overflow garbages
839                                         // '0x20<=code' is character region
840         }
841         size_t len = strlen(rsrc_in)+1;  // '1' for null termination
842         char* rsrc = (char*) OICCalloc(len, sizeof(char));
843         if(!rsrc)
844         {
845             OIC_LOG(ERROR, TAG, "createAcl: OICCalloc error return");
846             goto CRACL_ERROR;
847         }
848         OICStrcpy(rsrc, len, rsrc_in);
849         acl->resources[i] = rsrc;  // after here, |rsrc| points nothing
850     }
851
852     // enter |permission| for this access
853     printf("   > [C] Enter Permission for This Access\n");
854     uint16_t pmsn = PERMISSION_FULL_CONTROL;  // default full permission
855     uint16_t pmsn_msk = PERMISSION_CREATE;  // default permission mask
856     for(int i=0; ACL_PEMISN_CNT>i; ++i)
857     {
858         char ans = 0;
859         for( ; ; )
860         {
861             printf("         Enter %s Permission (y/n): ", ACL_PEMISN[i]);
862             for(int ret=0; 1!=ret; )
863             {
864                 ret = scanf("%c", &ans);
865                 for( ; 0x20<=getchar(); );  // for removing overflow garbages
866                                             // '0x20<=code' is character region
867             }
868             if('y'==ans || 'Y'==ans || 'n'==ans|| 'N'==ans)
869             {
870                 ans &= ~0x20;  // for masking lower case, 'y/n'
871                 break;
872             }
873             printf("         Entered Wrong Answer. Please Enter 'y/n' Again\n");
874         }
875         if('N' == ans)  // masked lower case, 'n'
876         {
877             pmsn -= pmsn_msk;
878         }
879         pmsn_msk <<= 1;
880     }
881     acl->permission = pmsn;
882
883     // enter |owner| device number
884     for( ; ; )
885     {
886         printf("   > [D] Enter Owner Device Number: ");
887         for(int ret=0; 1!=ret; )
888         {
889             ret = scanf("%d", &num);
890             for( ; 0x20<=getchar(); );  // for removing overflow garbages
891                                         // '0x20<=code' is character region
892         }
893         if(num && g_own_cnt>=num)
894         {
895             break;
896         }
897         printf("         Entered Wrong Number. Please Enter Again\n");
898     }
899     acl->ownersLen = 1;
900     acl->owners = (OicUuid_t*) OICCalloc(1, sizeof(OicUuid_t));
901     if(!acl->owners)
902     {
903         OIC_LOG(ERROR, TAG, "createAcl: OICCalloc error return");
904         goto CRACL_ERROR;
905     }
906
907     dev = getDevInst((const OCProvisionDev_t*)g_own_list, num);
908     if(!dev || !dev->doxm)
909     {
910         OIC_LOG(ERROR, TAG, "createAcl: device instance empty");
911         goto CRACL_ERROR;
912     }
913     memcpy(acl->owners, &dev->doxm->deviceID, UUID_LENGTH);
914     printf("\n");
915
916     return acl;
917
918 CRACL_ERROR:
919     OCDeleteACLList(acl);  // after here |acl| points nothing
920     return NULL;
921 }
922
923 static OCProvisionDev_t* getDevInst(const OCProvisionDev_t* dev_lst, const int dev_num)
924 {
925     if(!dev_lst || 0>=dev_num)
926     {
927         printf("     Device List is Empty..\n");
928         return NULL;
929     }
930
931     OCProvisionDev_t* lst = (OCProvisionDev_t*) dev_lst;
932     for(int i=0; lst; )
933     {
934         if(dev_num == ++i)
935         {
936             return lst;
937         }
938         lst = lst->next;
939     }
940
941     return NULL;  // in here |lst| is always |NULL|
942 }
943
944 static int printDevList(const OCProvisionDev_t* dev_lst)
945 {
946     if(!dev_lst)
947     {
948         printf("     Device List is Empty..\n\n");
949         return 0;
950     }
951
952     OCProvisionDev_t* lst = (OCProvisionDev_t*) dev_lst;
953     int lst_cnt = 0;
954     for( ; lst; )
955     {
956         printf("     [%d] ", ++lst_cnt);
957         printUuid((const OicUuid_t*) &lst->doxm->deviceID);
958         printf("\n");
959         lst = lst->next;
960     }
961     printf("\n");
962
963     return lst_cnt;
964 }
965
966 static size_t printUuidList(const OCUuidList_t* uid_lst)
967 {
968     if(!uid_lst)
969     {
970         printf("     Device List is Empty..\n\n");
971         return 0;
972     }
973
974     OCUuidList_t* lst = (OCUuidList_t*) uid_lst;
975     size_t lst_cnt = 0;
976     for( ; lst; )
977     {
978         printf("     [%zu] ", ++lst_cnt);
979         printUuid((const OicUuid_t*) &lst->dev);
980         printf("\n");
981         lst = lst->next;
982     }
983     printf("\n");
984
985     return lst_cnt;
986 }
987
988 static int printResultList(const OCProvisionResult_t* rslt_lst, const int rslt_cnt)
989 {
990     if(!rslt_lst || 0>=rslt_cnt)
991     {
992         printf("     Device List is Empty..\n\n");
993         return 0;
994     }
995
996     int lst_cnt = 0;
997     for( ; rslt_cnt>lst_cnt; ++lst_cnt)
998     {
999         printf("     [%d] ", lst_cnt+1);
1000         printUuid((const OicUuid_t*) &rslt_lst[lst_cnt].deviceId);
1001         printf(" - result: %d\n", rslt_lst[lst_cnt].res);
1002     }
1003     printf("\n");
1004
1005     return lst_cnt;
1006 }
1007
1008 static void printUuid(const OicUuid_t* uid)
1009 {
1010     for(int i=0; i<UUID_LENGTH; )
1011     {
1012         printf("%02X", (*uid).id[i++]);
1013         if(i==4 || i==6 || i==8 || i==10)  // canonical format for UUID has '8-4-4-4-12'
1014         {
1015             printf("-");
1016         }
1017     }
1018 }
1019
1020 static FILE* fopen_prvnMng(const char* path, const char* mode)
1021 {
1022     (void)path;  // unused |path| parameter
1023
1024     // input |g_svr_db_fname| internally by force, not using |path| parameter
1025     // because |OCPersistentStorage::open| is called |OCPersistentStorage| internally
1026     // with its own |SVR_DB_FILE_NAME|
1027     return fopen(SVR_DB_FILE_NAME, mode);
1028 }
1029
1030 static int waitCallbackRet(void)
1031 {
1032     for(int i=0; !g_doneCB && CALLBACK_TIMEOUT>i; ++i)
1033     {
1034         sleep(1);
1035         if(OC_STACK_OK != OCProcess())
1036         {
1037             OIC_LOG(ERROR, TAG, "OCStack process error");
1038             return -1;
1039         }
1040     }
1041
1042     return 0;
1043 }
1044
1045 static int selectTwoDiffNum(int* a, int* b, const int max, const char* str)
1046 {
1047     if(!a || !b || 2>=max || !str)
1048     {
1049         return -1;
1050     }
1051
1052     for( ; ; )
1053     {
1054         for(int i=0; 2>i; ++i)
1055         {
1056             int* num = 0==i?a:b;
1057             for( ; ; )
1058             {
1059                 printf("   > Enter Device[%d] Number, %s: ", i+1, str);
1060                 for(int ret=0; 1!=ret; )
1061                 {
1062                     ret = scanf("%d", num);
1063                     for( ; 0x20<=getchar(); );  // for removing overflow garbages
1064                                                 // '0x20<=code' is character region
1065                 }
1066                 if(0<*num && max>=*num)
1067                 {
1068                     break;
1069                 }
1070                 printf("     Entered Wrong Number. Please Enter Again\n");
1071             }
1072         }
1073         if(*a != *b)
1074         {
1075             printf("\n");
1076             return 0;
1077         }
1078     }
1079
1080     return -1;
1081 }
1082
1083 static void printMenu(void)
1084 {
1085     printf("************************************************************\n");
1086     printf("****** OIC Provisioning Client with using C-level API ******\n");
1087     printf("************************************************************\n\n");
1088
1089     printf("** [A] DISCOVER DEVICES ON NETWORK\n");
1090     printf("** 10. Discover All Un/Owned Devices on Network\n");
1091     printf("** 11. Discover Only Unowned Devices on Network\n");
1092     printf("** 12. Discover Only Owned Devices on Network\n\n");
1093
1094     printf("** [B] REGISTER/OWN ALL DISCOVERED UNOWNED DEVICES\n");
1095     printf("** 20. Register/Own All Discovered Unowned Devices\n\n");
1096
1097     printf("** [C] PROVISION/LINK PAIRWISE THINGS\n");
1098     printf("** 30. Provision/Link Pairwise Things\n");
1099     printf("** 31. Provision Credentials for Pairwise Things\n");
1100     printf("** 32. Provision the Selected Access Control List(ACL)\n");
1101     printf("** 33. Check Linked Status of the Selected Device on PRVN DB\n\n");
1102
1103     printf("** [D] UNLINK PAIRWISE THINGS\n");
1104     printf("** 40. Unlink Pairwise Things\n\n");
1105
1106     printf("** [E] REMOVE THE SELECTED DEVICE\n");
1107     printf("** 50. Remove the Selected Device\n\n");
1108
1109     printf("** [F] EXIT PROVISIONING CLIENT\n");
1110     printf("** 99. Exit Provisionong Client\n\n");
1111
1112     printf("************************************************************\n\n");
1113 }
1114
1115 #if 0 // Code for enabling path configuration for PDB and SVR DBf
1116 static void printUsage(void)
1117 {
1118     printf("\n");
1119     printf("OIC Provisioning Client with using C-level API\n");
1120     printf("Usage: provisioningclient [option]...\n");
1121     printf("\n");
1122     printf("  -h                           print help for this provisioning client\n");
1123     printf("  -p=[prvn_db_file_path/name]  input PRVN DB file path and name\n");
1124     printf("                               if not exists, will load default DB file\n");
1125     printf("                               (default: |oic_prvn_mng.db| on working dir)\n");
1126     printf("                               (ex. -p=oic_prvn_mng.db)\n");
1127     printf("  -s=[svr_db_file_path/name]   input SVR DB file path and name\n");
1128     printf("                               if not exists, will load default DB file\n");
1129     printf("                               (default: |oic_svr_db_client.json| on working dir)\n");
1130     printf("                               (ex. -s=oic_svr_db_client.json)\n");
1131     printf("\n");
1132 }
1133 #endif
1134
1135 // main function for provisioning client using C-level provisioning API
1136 int main()
1137 {
1138     // initialize provisioning client
1139     if(initProvisionClient())
1140     {
1141         OIC_LOG(ERROR, TAG, "ProvisionClient init error");
1142         goto PMCLT_ERROR;
1143     }
1144
1145     // main loop for provisioning manager
1146     int mn_num = 0;
1147     for( ; ; )
1148     {
1149         printf("\n");
1150         printMenu();
1151         printf(">> Enter Menu Number: ");
1152         for(int ret=0; 1!=ret; )
1153         {
1154             ret = scanf("%d", &mn_num);
1155             for( ; 0x20<=getchar(); );  // for removing overflow garbages
1156                                         // '0x20<=code' is character region
1157         }
1158         printf("\n");
1159         switch(mn_num)
1160         {
1161         case _10_DISCOV_ALL_DEVS_:
1162             if(discoverAllDevices())
1163             {
1164                 OIC_LOG(ERROR, TAG, "_10_DISCOV_ALL_DEVS_: error");
1165             }
1166             break;
1167         case _11_DISCOV_UNOWN_DEVS_:
1168             if(discoverUnownedDevices())
1169             {
1170                 OIC_LOG(ERROR, TAG, "_11_DISCOV_UNOWN_DEVS_: error");
1171             }
1172             break;
1173         case _12_DISCOV_OWN_DEVS_:
1174             if(discoverOwnedDevices())
1175             {
1176                 OIC_LOG(ERROR, TAG, "_12_DISCOV_OWN_DEVS_: error");
1177             }
1178             break;
1179         case _20_REGIST_DEVS_:
1180             if(registerDevices())
1181             {
1182                 OIC_LOG(ERROR, TAG, "_20_REGIST_DEVS_: error");
1183             }
1184             break;
1185         case _30_PROVIS_PAIR_DEVS_:
1186             if(provisionPairwise())
1187             {
1188                 OIC_LOG(ERROR, TAG, "_30_PROVIS_PAIR_DEVS_: error");
1189             }
1190             break;
1191         case _31_PROVIS_CRED_:
1192             if(provisionCred())
1193             {
1194                 OIC_LOG(ERROR, TAG, "_31_PROVIS_CRED_: error");
1195             }
1196             break;
1197         case _32_PROVIS_ACL_:
1198             if(provisionAcl())
1199             {
1200                 OIC_LOG(ERROR, TAG, "_32_PROVIS_ACL_: error");
1201             }
1202             break;
1203         case _33_CHECK_LINK_STATUS_:
1204             if(checkLinkedStatus())
1205             {
1206                 OIC_LOG(ERROR, TAG, "_33_CHECK_LINK_STATUS_: error");
1207             }
1208             break;
1209         case _40_UNLINK_PAIR_DEVS_:
1210             if(unlinkPairwise())
1211             {
1212                 OIC_LOG(ERROR, TAG, "_40_UNLINK_PAIR_DEVS_: error");
1213             }
1214             break;
1215         case _50_REMOVE_SELEC_DEV_:
1216             if(removeDevice())
1217             {
1218                 OIC_LOG(ERROR, TAG, "_50_REMOVE_SELEC_DEV_: error");
1219             }
1220             break;
1221         case _99_EXIT_PRVN_CLT_:
1222             goto PMCLT_ERROR;
1223         default:
1224             printf(">> Entered Wrong Number. Please Enter Again\n\n");
1225             break;
1226         }
1227     }
1228
1229 PMCLT_ERROR:
1230     if(OC_STACK_OK != OCStop())
1231     {
1232         OIC_LOG(ERROR, TAG, "OCStack stop error");
1233     }
1234     OCDeleteDiscoveredDevices(g_own_list);  // after here |g_own_list| points nothing
1235     OCDeleteDiscoveredDevices(g_unown_list);  // after here |g_unown_list| points nothing
1236
1237     if(g_svr_fname)
1238     {
1239         OICFree(g_svr_fname);  // after here |g_svr_fname| points nothing
1240     }
1241     if(g_prvn_fname)
1242     {
1243         OICFree(g_prvn_fname);  // after here |g_prvn_fname| points nothing
1244     }
1245     return 0;  // always return normal case
1246 }
1247
1248 #ifdef __cplusplus
1249 }
1250 #endif //__cplusplus