replace : iotivity -> iotivity-sec
[platform/upstream/iotivity.git] / resource / csdk / security / tool / svrdbeditor_src / svrdbeditoracl.c
1 /* *****************************************************************
2  *
3  * Copyright 2017 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 <stdbool.h>
22
23 #include "utlist.h"
24 #include "octypes.h"
25 #include "oic_malloc.h"
26
27 #include "psinterface.h"
28
29 #include "srmresourcestrings.h"
30 #include "security_internals.h"
31 #include "aclresource.h"
32
33 #include "svrdbeditoracl.h"
34
35 #define ACL_PEMISN_CNT (5)
36 #define ACE_MAX_ENTITY (256)
37
38 static OicSecAcl_t *g_acl = NULL;
39
40 typedef enum AclModifyType
41 {
42     ACL_MODIFY_ACE = 1,
43     ACL_EDIT_ROWNERID = 2
44 } AclModifyType_t;
45 typedef enum AceModifyType
46 {
47     ACE_EDIT_SUBJECT = 1,
48     ACE_ADD_RESOURCE,
49     ACE_REMOVE_RESOURCE,
50     ACE_EDIT_RESOURCE,
51     ACE_EDIT_PERMISSION = 5
52 } AceModifyType_t;
53
54 void DeInitACL(void)
55 {
56     if (g_acl)
57     {
58         DeleteACLList(g_acl);
59         g_acl = NULL;
60     }
61 }
62
63 void RefreshACL(void)
64 {
65     OicSecAcl_t *tmpACL = NULL;
66     uint8_t *secPayload = NULL;
67     size_t payloadSize = 0;
68     OCStackResult ocResult = OC_STACK_ERROR;
69     ocResult = GetSecureVirtualDatabaseFromPS(OIC_JSON_ACL_NAME, &secPayload, &payloadSize);
70     if (OC_STACK_OK != ocResult)
71     {
72         PRINT_WARN("Failed GetSecureVirtualDatabaseFromPS");
73         return;
74     }
75
76     tmpACL = CBORPayloadToAcl(secPayload, payloadSize);
77     if (NULL == tmpACL)
78     {
79         PRINT_ERR("Failed CBORPayloadToAcl");
80         OICFree(secPayload);
81         return;
82     }
83     OICFree(secPayload);
84
85     if (g_acl)
86     {
87         DeInitACL();
88     }
89     g_acl = tmpACL;
90 }
91
92 static void UpdateACL(void)
93 {
94     OCStackResult aclResult = OC_STACK_ERROR;
95     uint8_t *aclPayload = NULL;
96     size_t aclPayloadSize = 0;
97
98     aclResult = AclToCBORPayload(g_acl, &aclPayload, &aclPayloadSize);
99     if (OC_STACK_OK != aclResult)
100     {
101         PRINT_ERR("AclToCBORPayload error : %d" , aclResult);
102         return;
103     }
104     aclResult = UpdateSecureResourceInPS(OIC_JSON_ACL_NAME, aclPayload, aclPayloadSize);
105     if (OC_STACK_OK != aclResult)
106     {
107         PRINT_ERR("UpdateSecureResourceInPS error : %d" , aclResult);
108         OICFree(aclPayload);
109         return;
110     }
111     OICFree(aclPayload);
112 }
113
114 static void FreeACE(OicSecAce_t *ace)
115 {
116     if (NULL == ace)
117     {
118         PRINT_ERR("Invalid parameter");
119         return;
120     }
121
122     //Clean Resources
123     OicSecRsrc_t *rsrc = NULL;
124     OicSecRsrc_t *tmpRsrc = NULL;
125     LL_FOREACH_SAFE(ace->resources, rsrc, tmpRsrc)
126     {
127         LL_DELETE(ace->resources, rsrc);
128         FreeRsrc(rsrc);
129     }
130
131     OicSecValidity_t *validity = NULL;
132     OicSecValidity_t *tmpValidity = NULL;
133     LL_FOREACH_SAFE(ace->validities, validity, tmpValidity)
134     {
135         LL_DELETE(ace->validities, validity);
136
137         //Clean period
138         OICFree(validity->period);
139
140         //Clean recurrence
141         for (size_t i = 0; i < validity->recurrenceLen; i++)
142         {
143             OICFree(validity->recurrences[i]);
144         }
145         OICFree(validity->recurrences);
146         OICFree(validity);
147         validity = NULL;
148     }
149
150 #ifdef MULTIPLE_OWNER
151     OICFree(ace->eownerID);
152 #endif
153     OICFree(ace);
154 }
155
156 static void PrintValidity(const OicSecValidity_t *validities)
157 {
158     const OicSecValidity_t *validity = NULL;
159     const OicSecValidity_t *tempValidity = NULL;
160     size_t validityCnt = 0;
161
162     LL_FOREACH_SAFE(validities, validity, tempValidity)
163     {
164         PRINT_DATA("Validity #%zu:\n", validityCnt + 1);
165         PRINT_DATA("%10s : %s\n", OIC_JSON_PERIOD_NAME, validity->period);
166         PRINT_DATA("%10s : ", OIC_JSON_RESOURCES_NAME);
167         PrintStringArray((const char **)validity->recurrences, validity->recurrenceLen);
168         validityCnt++;
169     }
170 }
171
172 static void PrintPermission(uint16_t permission)
173 {
174     PRINT_DATA("%d (", permission);
175
176     if (0 == permission)
177     {
178         PRINT_DATA(" NO PERMISSION");
179     }
180     else
181     {
182         if (permission & PERMISSION_CREATE)
183         {
184             PRINT_DATA(" CREATE ");
185         }
186         if (permission & PERMISSION_READ)
187         {
188             PRINT_DATA(" READ ");
189         }
190         if (permission & PERMISSION_WRITE)
191         {
192             PRINT_DATA(" WRITE ");
193         }
194         if (permission & PERMISSION_DELETE)
195         {
196             PRINT_DATA(" DELETE ");
197         }
198         if (permission & PERMISSION_NOTIFY)
199         {
200             PRINT_DATA(" NOTIFY ");
201         }
202     }
203
204     PRINT_DATA(") \n");
205 }
206
207 static size_t PrintResourceList(const OicSecRsrc_t *rsrcList)
208 {
209     const OicSecRsrc_t *rsrc = NULL;
210     const OicSecRsrc_t *tempRsrc = NULL;
211     size_t rsrcCnt = 0;
212
213     LL_FOREACH_SAFE(rsrcList, rsrc, tempRsrc)
214     {
215         PRINT_DATA("Resource #%zu:\n", rsrcCnt + 1);
216         PRINT_DATA("%10s : %s\n", OIC_JSON_HREF_NAME, rsrc->href);
217         PRINT_DATA("%10s : %s\n", OIC_JSON_REL_NAME, rsrc->rel);
218         PRINT_DATA("%10s : ", OIC_JSON_RT_NAME);
219         PrintStringArray((const char **)rsrc->types, rsrc->typeLen);
220         PRINT_DATA("%10s : ", OIC_JSON_IF_NAME);
221         PrintStringArray((const char **)rsrc->interfaces, rsrc->interfaceLen);
222         rsrcCnt++;
223     }
224     return rsrcCnt;
225 }
226
227
228 static int PrintAce(const OicSecAce_t *ace)
229 {
230     PRINT_PROG("%15s : ", OIC_JSON_SUBJECT_NAME);
231     if (memcmp(&(ace->subjectuuid), &WILDCARD_SUBJECT_ID, sizeof(OicUuid_t)) == 0)
232     {
233         PrintString((char *)WILDCARD_SUBJECT_ID.id);
234     }
235     else
236     {
237         PrintUuid(&(ace->subjectuuid));
238     }
239
240 #ifdef MULTIPLE_OWNER
241     if (ace->eownerID)
242     {
243         PRINT_PROG("%15s : ", OIC_JSON_EOWNERID_NAME);
244         PrintUuid(&(ace->subjectuuid));
245     }
246 #endif
247
248     //permission
249     PRINT_PROG("%15s : ", OIC_JSON_PERMISSION_NAME);
250     PrintPermission(ace->permission);
251
252     //resource list
253     PRINT_PROG("%15s : \n", OIC_JSON_RESOURCES_NAME);
254     PrintResourceList(ace->resources);
255
256     //Validity
257     PrintValidity(ace->validities);
258
259     return 0;
260 }
261
262 size_t PrintAcl(void)
263 {
264     OicSecAce_t *ace = NULL;
265     OicSecAce_t *tempAce = NULL;
266     bool isEmptyList = true;
267     size_t aceCnt = 0;
268
269     PRINT_INFO("\n\n********************* [%-20s] *********************",
270                "ACL Resource");
271     if (g_acl)
272     {
273         LL_FOREACH_SAFE(g_acl->aces, ace, tempAce)
274         {
275             PRINT_INFO("[ACE #%zu]", ++aceCnt);
276             if (0 != PrintAce(ace))
277             {
278                 return aceCnt;
279             }
280             PRINT_PROG("------------------------------------------------------------------\n");
281             isEmptyList = false;
282         }
283
284         if (isEmptyList)
285         {
286             PRINT_PROG("ACE is empty.\n");
287             PRINT_PROG("------------------------------------------------------------------\n");
288         }
289         PRINT_PROG("%15s : ", OIC_JSON_ROWNERID_NAME);
290         PrintUuid(&(g_acl->rownerID));
291     }
292     else
293     {
294         PRINT_PROG("ACL is empty.\n");
295     }
296
297     PRINT_INFO("********************* [%-20s] *********************",
298                "ACL Resource");
299
300     return aceCnt;
301 }
302
303 static int InputSubjectUuid(OicSecAce_t *ace)
304 {
305     int ret = 0;
306
307     PRINT_DATA("\tInput the Subject UUID for this access (e.g. 61646D69-6E44-6576-6963-655575696430) : ");
308     ret = InputUuid(&ace->subjectuuid);
309     if (0 != ret)
310     {
311         PRINT_ERR("Failed InputUuid");
312         return ret;
313     }
314     return ret;
315 }
316
317 static int InputResources(OicSecRsrc_t *resources)
318 {
319     size_t i = 0;
320     char *href = NULL;
321     char **types = NULL;
322     size_t typeLen = 0;
323     char **interfaces = NULL;
324     size_t interfaceLen = 0;
325
326     if (NULL == resources)
327     {
328         PRINT_ERR("Invalid parameter");
329         return -1;
330     }
331     // input href
332     href = InputString("\tInput the resource URI : ");
333     if (NULL == href)
334     {
335         PRINT_ERR("Failed InputString");
336         return -1;
337     }
338
339     // input types
340     PRINT_PROG("\tInput the number of resource type for %s (MAX : %d): ", href,
341                SVR_MAX_ENTITY);
342     typeLen = InputNumber("");
343     if (0 == typeLen || SVR_MAX_ENTITY < typeLen)
344     {
345         PRINT_ERR("Invalid number");
346         OICFree(href);
347         return -1;
348     }
349     types = (char **)OICCalloc(typeLen, sizeof(char *));
350     if (NULL == types)
351     {
352         PRINT_ERR("Failed to allocate memory");
353         OICFree(href);
354         return -1;
355     }
356
357     for (i = 0; i < typeLen; i++)
358     {
359         PRINT_PROG("\tInput the resource type name #%zu : ", i + 1);
360         types[i] = InputString("");
361         if (NULL == types[i] )
362         {
363             PRINT_ERR("Failed InputString");
364             OICFree(href);
365             for (size_t j = 0; j < i; j++)
366             {
367                 OICFree(types[j]);
368             }
369             OICFree(types);
370             return -1;
371         }
372     }
373     // input interfaces
374     PRINT_PROG("\tInput the number of interface for %s (MAX : %d): ", href, SVR_MAX_ENTITY);
375     interfaceLen = InputNumber("");
376     if (0 == interfaceLen || SVR_MAX_ENTITY < interfaceLen)
377     {
378         PRINT_ERR("Invalid number");
379         OICFree(href);
380         for (size_t j = 0; j < typeLen; j++)
381         {
382             OICFree(types[j]);
383         }
384         OICFree(types);
385         return -1;
386     }
387     interfaces = (char **)OICCalloc(interfaceLen, sizeof(char *));
388     if (NULL == interfaces)
389     {
390         PRINT_ERR("Failed to allocate memory");
391         OICFree(href);
392         for (size_t j = 0; j < typeLen; j++)
393         {
394             OICFree(types[j]);
395         }
396         OICFree(types);
397         return -1;
398
399     }
400
401     for (i = 0; i < interfaceLen; i++)
402     {
403         PRINT_PROG("\tInput the interface name #%zu : ", i + 1);
404         interfaces[i] = InputString("");
405         if (NULL == interfaces[i] )
406         {
407             PRINT_ERR("Failed InputString");
408             OICFree(href);
409             for (size_t j = 0; j < typeLen; j++)
410             {
411                 OICFree(types[j]);
412             }
413             OICFree(types);
414
415             for (size_t j = 0; j < i; j++)
416             {
417                 OICFree(interfaces[j]);
418             }
419             OICFree(interfaces);
420             return -1;
421         }
422     }
423
424     // free before assign
425     OICFree(resources->href);
426     if (0 < resources->typeLen && resources->types)
427     {
428         for (i = 0; i < resources->typeLen; i++)
429         {
430             OICFree(resources->types[i]);
431         }
432         OICFree(resources->types);
433     }
434     if (0 < resources->interfaceLen && resources->interfaces)
435     {
436         for (i = 0; i < resources->interfaceLen; i++)
437         {
438             OICFree(resources->interfaces[i]);
439         }
440         OICFree(resources->interfaces);
441     }
442
443     // assign to real
444     resources->href = href;
445     resources->typeLen = typeLen;
446     resources->types = types;
447     resources->interfaceLen = interfaceLen;
448     resources->interfaces = interfaces;
449     return 0;
450 }
451
452 static uint16_t InputAccessPermission(void)
453 {
454     uint16_t pmsn = PERMISSION_FULL_CONTROL;  // default full permission
455     uint16_t pmsn_msk = PERMISSION_CREATE;  // default permission mask
456     const char *ACL_PEMISN[ACL_PEMISN_CNT] = {"CREATE", "READ", "WRITE", "DELETE", "NOTIFY"};
457
458     for (int i = 0; i < ACL_PEMISN_CNT; i++)
459     {
460         char ans = 0;
461         for ( ; ; )
462         {
463             PRINT_NORMAL("\tEnter %s Permission (y/n): ", ACL_PEMISN[i]);
464             for (int ret = 0; 1 != ret; )
465             {
466                 ret = scanf("%c", &ans);
467                 for ( ; 0x20 <= getchar(); ); // for removing overflow garbages
468                 // '0x20<=code' is character region
469             }
470             if ('y' == ans || 'Y' == ans || 'n' == ans || 'N' == ans)
471             {
472                 ans &= ~0x20;  // for masking lower case, 'y/n'
473                 break;
474             }
475             PRINT_NORMAL("\tEntered Wrong Answer. Please Enter 'y/n' Again\n");
476         }
477         if ('N' == ans)  // masked lower case, 'n'
478         {
479             pmsn -= pmsn_msk;
480         }
481         pmsn_msk <<= 1;
482     }
483     return pmsn;
484 }
485
486 int InputAceData(OicSecAce_t *ace)
487 {
488     int ret = 0;
489     size_t numOfRsrc = 0;
490
491     PRINT_PROG("\n\nPlease input the each entity of new ACE.\n");
492
493     ret = InputSubjectUuid(ace);
494     if (0 != ret)
495     {
496         PRINT_ERR("Failed InputSubjectUuid");
497         return ret;
498     }
499     PRINT_PROG("\tInput the number of resource for this access : ");
500     numOfRsrc = InputNumber("");
501     if (SVR_MAX_ENTITY < numOfRsrc)
502     {
503         PRINT_ERR("Invalid number");
504         return -1;
505     }
506
507     for (size_t i = 0; i < numOfRsrc; i++)
508     {
509         PRINT_PROG("Please input the resource information for resource #%zu\n", i + 1);
510         OicSecRsrc_t *rsrc = (OicSecRsrc_t *)OICCalloc(1, sizeof(OicSecRsrc_t));
511         if (NULL == rsrc)
512         {
513             PRINT_ERR("Failed to allocate memory");
514             return -1;
515         }
516
517         ret = InputResources(rsrc);
518         if (0 != ret)
519         {
520             PRINT_ERR("Failed InputResources");
521             OICFree(rsrc);
522             return ret;
523         }
524         LL_APPEND(ace->resources, rsrc);
525     }
526
527     PRINT_PROG("\tSelect permission for this access.\n");
528     ace->permission = InputAccessPermission();
529
530 #ifdef MULTIPLE_OWNER
531     // TODO: Input eowner
532 #endif
533
534     // TODO: Input the validity (T.B.D)
535
536     return 0;
537 }
538
539 static int ModifyAce(OicSecAce_t *ace)
540 {
541     int ret = 0;
542     int modifyMenu = 0;
543
544     size_t sizeOfRsrc = 0;
545     size_t curIdx = 0;
546     size_t rsrcIdx = 0;
547     OicSecRsrc_t *rsrc = NULL;
548     OicSecRsrc_t *tmpRsrc = NULL;
549
550     PRINT_PROG("\n\nPlease input the attribute you want to modify\n");
551     PRINT_DATA("\t%2d. Edit subject\n", ACE_EDIT_SUBJECT);
552     PRINT_DATA("\t%2d. Add resources \n", ACE_ADD_RESOURCE);
553     PRINT_DATA("\t%2d. Remove resources \n", ACE_REMOVE_RESOURCE);
554     PRINT_DATA("\t%2d. Edit resources \n", ACE_EDIT_RESOURCE);
555     PRINT_DATA("\t%2d. Edit permission\n", ACE_EDIT_PERMISSION);
556     PRINT_DATA("\t%2d. Back to the previous\n", BACK);
557     modifyMenu = InputNumber("Select the menu : ");
558     switch (modifyMenu)
559     {
560         case ACE_EDIT_SUBJECT:
561             ret = InputSubjectUuid(ace);
562             if (0 != ret)
563             {
564                 PRINT_ERR("InputSubjectType error");
565                 return ret;
566             }
567             break;
568         case ACE_ADD_RESOURCE :
569             PRINT_PROG("Please input the resource information for resource to add\n");
570             rsrc = (OicSecRsrc_t *)OICCalloc(1, sizeof(OicSecRsrc_t));
571             if (NULL == rsrc)
572             {
573                 PRINT_ERR("Failed to allocate memory");
574                 return -1;
575             }
576
577             ret = InputResources(rsrc);
578             if (0 != ret)
579             {
580                 PRINT_ERR("InputResources error");
581                 OICFree(rsrc);
582                 return ret;
583             }
584             LL_APPEND(ace->resources, rsrc);
585             break;
586         case ACE_REMOVE_RESOURCE:
587             sizeOfRsrc = PrintResourceList(ace->resources);
588             rsrcIdx = InputNumber("\tInput the number of resource to remove : ");
589             if (0 == rsrcIdx || sizeOfRsrc < rsrcIdx)
590             {
591                 PRINT_ERR("Invalid number");
592                 return -1;
593             }
594             LL_FOREACH_SAFE(ace->resources, rsrc, tmpRsrc)
595             {
596                 if (rsrcIdx == ++curIdx)
597                 {
598                     LL_DELETE(ace->resources, rsrc);
599                     FreeRsrc(rsrc);
600                     break;
601                 }
602             }
603             break;
604         case ACE_EDIT_RESOURCE:
605             sizeOfRsrc = PrintResourceList(ace->resources);
606             PRINT_PROG("\tInput the number of resource to edit : ");
607             rsrcIdx = InputNumber("");
608             if (0 == rsrcIdx || sizeOfRsrc < rsrcIdx)
609             {
610                 PRINT_ERR("Invalid number");
611                 return -1;
612             }
613             LL_FOREACH_SAFE(ace->resources, rsrc, tmpRsrc)
614             {
615                 if (rsrcIdx == ++curIdx)
616                 {
617                     PRINT_PROG("Please input the resource information for resource #%zu\n", rsrcIdx );
618                     ret = InputResources(rsrc);
619                     if (0 != ret)
620                     {
621                         PRINT_ERR("InputResources error");
622                         return ret;
623                     }
624                     break;
625                 }
626             }
627             break;
628         case ACE_EDIT_PERMISSION:
629             PRINT_PROG("\tSelect permission for this access.\n");
630             ace->permission = InputAccessPermission();
631             break;
632         case BACK:
633             PRINT_INFO("Back to the previous menu.");
634             ret = -1;
635             break;
636         default:
637             PRINT_ERR("Wrong type Number");
638             ret = -1;
639             break;
640     }
641     return ret;
642 }
643
644 static int ModifyAcl(void)
645 {
646     int ret = 0;
647     int modifyMenu = 0;
648     OicSecAce_t *ace = NULL;
649     OicSecAce_t *tempAce = NULL;
650     size_t aclIdx = 0;
651     size_t curIdx = 0;
652     size_t numOfAce = 0;
653
654     PRINT_PROG("\n\nPlease select the menu you want to modify\n");
655     PRINT_DATA("\t%2d. Modify ACE\n", ACL_MODIFY_ACE);
656     PRINT_DATA("\t%2d. Edit rownerid\n", ACL_EDIT_ROWNERID);
657     modifyMenu = InputNumber("Select the menu : ");
658     switch (modifyMenu)
659     {
660         case ACL_MODIFY_ACE:
661             numOfAce = PrintAcl();
662             if (0 == numOfAce)
663             {
664                 PRINT_ERR("empty ace");
665                 return -1;
666             }
667             aclIdx = InputNumber("\tPlease input the number of ACE : ");
668             if (0 == aclIdx || numOfAce < aclIdx)
669             {
670                 PRINT_ERR("Wrong number of ACE.");
671                 return -1;
672             }
673
674             //Modify the ACE
675             LL_FOREACH_SAFE(g_acl->aces, ace, tempAce)
676             {
677                 if (ace)
678                 {
679                     //If found target ACE, modify it.
680                     if (aclIdx == ++curIdx)
681                     {
682                         if (0 != ModifyAce(ace))
683                         {
684                             PRINT_ERR("Failed to Moidfy ACE");
685                             return -1;
686                         }
687                         PRINT_INFO("\n\n[ACE #%zu] Modified", aclIdx);
688                         PrintAce(ace);
689                         break;
690                     }
691                 }
692             }
693             break;
694         case ACL_EDIT_ROWNERID:
695             PRINT_PROG(
696                 "\tInput the ROWNER UUID for this access (e.g. 61646D69-6E44-6576-6963-655575696430) : ");
697             ret = InputUuid(&(g_acl->rownerID));
698             if (0 != ret)
699             {
700                 PRINT_ERR("InputUuid error");
701                 return -1;
702             }
703             break;
704         default:
705             PRINT_ERR("Wrong type Number");
706             ret = -1;
707             break;
708     }
709     return ret;
710 }
711
712 void HandleAclOperation(const SubOperationType_t cmd)
713 {
714     size_t aclIdx = 0;
715
716     if (NULL == g_acl)
717     {
718         g_acl = (OicSecAcl_t *) OICCalloc(1, sizeof(OicSecAcl_t));
719         if (NULL == g_acl)
720         {
721             PRINT_ERR("Failed to allocate memory");
722             return;
723         }
724     }
725     if (SVR_EDIT_IDX_SIZE <= cmd)
726     {
727         PRINT_ERR("Invalid menu for ACL");
728         return;
729     }
730     switch (cmd)
731     {
732         case SVR_PRINT:
733             PrintAcl();
734             break;
735         case SVR_ADD:
736             {
737                 OicSecAce_t *ace = (OicSecAce_t *)OICCalloc(1, sizeof(OicSecAce_t));
738
739                 if (NULL == ace)
740                 {
741                     PRINT_ERR("Failed to allocate memory");
742                     return;
743                 }
744
745                 if (0 != InputAceData(ace))
746                 {
747                     PRINT_ERR("Failed to input ACE");
748                     FreeACE(ace);
749                     return;
750                 }
751
752                 //Add ACE
753                 LL_APPEND(g_acl->aces, ace);
754                 UpdateACL();
755                 break;
756             }
757         case SVR_REMOVE:
758             {
759                 OicSecAce_t *ace = NULL;
760                 OicSecAce_t *tempAce = NULL;
761                 size_t curIdx = 0;
762                 size_t numOfAce = 0;
763
764                 numOfAce = PrintAcl();
765                 if (0 == numOfAce)
766                 {
767                     PRINT_ERR("empty ace");
768                     return;
769                 }
770
771                 aclIdx = InputNumber("\tPlease input the number of ACE : ");
772
773                 if (0 == aclIdx || aclIdx > numOfAce)
774                 {
775                     PRINT_ERR("Wrong number of ACE.");
776                     return;
777                 }
778
779                 //Revmoe the ACE
780                 LL_FOREACH_SAFE(g_acl->aces, ace, tempAce)
781                 {
782                     if (ace)
783                     {
784                         //If found target ACE, delete it.
785                         if (aclIdx == ++curIdx)
786                         {
787                             LL_DELETE(g_acl->aces, ace);
788                             FreeACE(ace);
789                             UpdateACL();
790                             break;
791                         }
792                     }
793                 }
794                 break;
795             }
796         case SVR_MODIFY:
797             if (NULL == g_acl)
798             {
799                 PRINT_ERR("empty acl");
800                 return;
801             }
802             if (0 != ModifyAcl())
803             {
804                 PRINT_ERR("Fail ModifyAcl");
805                 return;
806             }
807             UpdateACL();
808             break;
809         default:
810             break;
811     }
812 }