From patchwork Tue Nov 22 19:18:15 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Carter X-Patchwork-Id: 9441969 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 34F6760235 for ; Tue, 22 Nov 2016 19:21:44 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 18F25284C0 for ; Tue, 22 Nov 2016 19:21:44 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0B1CA285C7; Tue, 22 Nov 2016 19:21:44 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from emsm-gh1-uea11.nsa.gov (smtp.nsa.gov [8.44.101.9]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2D2E5284C0 for ; Tue, 22 Nov 2016 19:21:39 +0000 (UTC) X-IronPort-AV: E=Sophos;i="5.31,682,1473120000"; d="scan'208";a="994571" IronPort-PHdr: =?us-ascii?q?9a23=3Apfs1/hYR+4F/Ah8sHYCD0SH/LSx+4OfEezUN459i?= =?us-ascii?q?sYplN5qZoc+8Zh7h7PlgxGXEQZ/co6odzbGH6Oa6BCdZu87JmUtBWaQEbwUCh8?= =?us-ascii?q?QSkl5oK+++Imq/EsTXaTcnFt9JTl5v8iLzG0FUHMHjew+a+SXqvnYdFRrlKAV6?= =?us-ascii?q?OPn+FJLMgMSrzeCy/IDYbxlViDanb75/KBu7oR/PusQWjoduN7g9xgfUqXZUZu?= =?us-ascii?q?pawn9lK0iOlBjm/Mew+5Bj8yVUu/0/8sNLTLv3caclQ7FGFToqK2866tHluhnF?= =?us-ascii?q?VguP+2ATUn4KnRpSAgjK9w/1U5HsuSbnrOV92S2aPcrrTbAoXDmp8qlmRAP0hC?= =?us-ascii?q?oBKjU19mbZhdJtg6JAuR6uuRp/yJPQbI2LNPdyYqbRcNUHTmRDQ8lRTTRMDIOi?= =?us-ascii?q?YYUSAeQPPuFWoIvzp1sWrxayGAehC+zzxTFHmHD2xrY30/gjHAzcwAAtBc4CvG?= =?us-ascii?q?rSod7oNKkSS+e1zKzQwDvHdfxW3Cny6JPVeR0/u/6MR65wftTLyUIyEA7FjFuR?= =?us-ascii?q?ppD/MDOPyuQBrXOW7/ZgVO2zi24nrBt9oj60xsg2kIXJiYUVyk7d+Ch/3Y07K9?= =?us-ascii?q?q4SEthbt6lFptdrySaOJFuQs84QmFoviA3waAFt56jZCUG1ZsqyhHFZ/GHboSE?= =?us-ascii?q?+AzvWemPLTtimX5ofq+0iQyo/ki60OL8U9G50FNNriVYjNbBrmsN1xnP6sifTf?= =?us-ascii?q?t941uh1S6P1w/N7uFEJlg5lbbBJJ47w74wi4ETvV7fHi72hEr2jKiWel8i+ue0?= =?us-ascii?q?8OTofq/qppqdN49wkg3+M6IuldKjAekgLwQDUGeW9f682bH+50H1XrpHguMsnq?= =?us-ascii?q?XEqJzaIN4Upq+9Aw9byIYj7BO/Ai+90NsGmXkHLVRFeA+IjoTwIF7OJ+34DfGj?= =?us-ascii?q?jFuyizdm3OzGP739DZXNKXjPirHhfa1n5EJGxwozys5f64pOCr4dOPLzRlPxtN?= =?us-ascii?q?vAAxAiKAO4xOLnCNRm1oMCQmKDGLSZP73OvlOS/eIgPe2MZI4TuDbgJPko/OLh?= =?us-ascii?q?jH8jmV8AZqmlx5UWZ2qkHvR9JEWZZ2DggtAbEWcFpgA+VvDliEWeUT5PYHa/R7?= =?us-ascii?q?wz5ikhB4K8DIfDXZuggKSb0yehH51WfXhGClSWHnj0aYqIQfAMaDidIsV5iDwL?= =?us-ascii?q?SaChS5M91RGprAL7xbtnLu7R+iIGr5Luz9Z16PPOmhE17zx7Fdyd03uKT2F2gG?= =?us-ascii?q?wHWyM20Lp4oUxnxVeJybJ4jOBAFdxP+/NJVR83NZDGz+NgDdD9RgPBfsySRVaj?= =?us-ascii?q?WtWmACg9Tsk/wt8VeUp9HM+ijh/b1SqwH7AVj6CLBIAz8q/E3Hj+PcV9y3Hb1K?= =?us-ascii?q?Q6jFkpWMhPNWq7hqJl8AjTHYHJmV2Dl6m2baQcwDLN9GCbwGWUoU5YSg9wXrvf?= =?us-ascii?q?XX0EfETZsdH56lnFT7+0BrQtKhFBxtKaKqtWdt3pik1LS+v5N9TafW2xgHuwBB?= =?us-ascii?q?aPxr6Xd4rlZ2Qd0zvbCEgYkgAc52yKNQ4gCSe9u2jeFiBhFUrzY0Pw9ulzsHO7?= =?us-ascii?q?QVEwzwGOaE1szL61+gMJhfybTvMcxKgIuCA7qzV7BFy9xc7ZC8Kcpwp9e6VRec?= =?us-ascii?q?g94Fld1WLerAx9IoetL7tkhl4ZfQV3ulnh1xNtBoVGj8cqsGsgzBBuJqKAzFNB?= =?us-ascii?q?azSY0Ij+O7LNLmny4A6ga7TN2lzFztaZ5L0P5+8lq1Xmpg2pEVAi83p/2dlPz3?= =?us-ascii?q?Sc/onKDBYVUZ/pTkY46gV1p7DAbSk5/I7byXpsMayovTDYwNIpGPEpyhC+cNdD?= =?us-ascii?q?KKmEDhP9E9UGB8iyL+wng16pbhMAPOBW6qE0JNireOGY166xO+ZshjWmjX5I4I?= =?us-ascii?q?plyEKD6zJ8SvLU35YC2/yXwxGIVyvmg1i/vMD2lptJai0SHmWl0yjkGJBeZrdo?= =?us-ascii?q?cYYNF2iuP9W9xs9iiJ71R35Y6FmjCksY2M+oZRWSc1v93RdK2UsLoXynni24zz?= =?us-ascii?q?NvnjEtr6qf2jbBw/7ldBYdPW5LXmZih0/2IYeol9AaQFSobw8xmRuh5Eb63LRb?= =?us-ascii?q?qL1kL2bNRUdIfi72L3xtU6arrbqCe89P6JUpsSpLS+Swe1aaRaDhoxECySPsA3?= =?us-ascii?q?NexCwndzGtopj5hRt6iGaZLHlttnrWZcZwxBnE6dzHWP5ewiEGSDN/iTnNCVi2?= =?us-ascii?q?J8Op8smMl5ffruC+UHqsVoVJfin2yYOMrjG06XdxDh24m/CzhtrnEQ4h3C/+y9?= =?us-ascii?q?VqUyLIowrmbontyau6LfptflN0C1/k98p6BoZ+n5M1hJEUwHQVmJOV8GEZkWjt?= =?us-ascii?q?NdVb3bzxbGAXST4N3dHV/BDv2Fd/IXKR24L5SnKdz9NiZ9akZGMWwTkw78NUB6?= =?us-ascii?q?eS97xEmzV6okaioQLWe/h9kS8XyeEy534Cn+EJpA0twz2FAr8IAElYOTLjlwyS?= =?us-ascii?q?4NC4sKVYenyvfKOt1Eplg9+hFqqCrhtHWHb+Z5ciBzN/4dtxMFLLyn3z5Z/rdM?= =?us-ascii?q?PWbd0Nqh2eiw3AgPRNKJItivoKgjJqOXz7vXI40OM7kxpu0oy6vISdLWVi4r65?= =?us-ascii?q?CAZCNjLpf8MT5i3tjaFGk8aOxY+vA5FhFy4XU5vpUfKpECsetfr9OAaICjE8rW?= =?us-ascii?q?2bGbXHFw+F9Ehmt27PE4ysN3yPJ3kYzdFiSweGKUxahwAUUjs6kYAlFgC2xMzh?= =?us-ascii?q?d0J56S4L6l7+tBRM1vpiNwPjXWfHuAeodjA0RYCRLBVM6AFC+0DVMcmF4+J9AS?= =?us-ascii?q?5X45qhrBaXJWyDfQRICmMJVVKYCFD/JLWu4sPA8+eADOqkM/TOeamOqfBZV/qQ?= =?us-ascii?q?ypKv0pdp/yyMN8WXInliCOY22kxdUnBlAMTWhy8ASzQJmC7Xac6Uugu88DVtrs?= =?us-ascii?q?+j6PTrRB7v5YyXBrRPN9Vg4Qu7jrqFN+GKnip5LixY1pwUz3/S1LcfxEISiz1p?= =?us-ascii?q?dzS1C7QPqDPCQbnfmq9SAB8XcSVzO9VU76gkxAlCJdbbis/p1r5/lvM1EU1JVF?= =?us-ascii?q?L7lsGsf8MKJ2a9NVPcCUmRKLuGICfHw8btYaOzUbdQlvlbtwWsuTaHFE/uJjKD?= =?us-ascii?q?lyPzWBC3KeFBly+bPB1EuIGmbhZtB2njTNT8ZR29LNB3jCc5wbkuinPNL24cPi?= =?us-ascii?q?B2c1lRob2I8SNYnvJ/FnRc4Xp+M+aLgSmZ7/PCJZYIqvZrGT57l+FH4HQg0bRZ?= =?us-ascii?q?9iVEROFzmCTItN5iuk2mku6MyjtnVxpCsDBLi5yXvU96I6XW6oFAWWrY/BIK9W?= =?us-ascii?q?ifEBUKp9RiCt3poK1f18bAm7nyKDhY9dLY58wcB9LbKMifKnouLQLpGCLIDAsC?= =?us-ascii?q?VTOkL27fiFZDkP6M7XCVqYA6pYbqmJoLULBbVVg1GegdCkVqBtACJ413Xjw8m7?= =?us-ascii?q?6BkMEI/Wa+rAXWRMhCopDHUfeSDe/1KDaejLhLeR0IzqjiLYQUKIL72FdvZUV9?= =?us-ascii?q?nITPB0XfR8tNojF7Yg8yvkpN7GB0Tncv1EL9dgOt/HgTGOa0nh4qigt+ZuEt+y?= =?us-ascii?q?3341osI1rKpTcwkFMvltn/hjCRajHxJr+qXY5KEyr0q1QxMpTjTgZzcwK9h0hk?= =?us-ascii?q?OSzHR7JWlLtgaXpkiAnHuZtMGP5QV6tEbwEMxfuPffUnzUxcqjm7xU9A/ebFE4?= =?us-ascii?q?VtlBA0fpG2tXJPxwJjYcUuKqzRPqpG019QhqyWvi+yyO8wwBUSJ0AT/2OOYCQI?= =?us-ascii?q?olAHNqE6Jyq0+exh8RGNlCFdeGgNSvUqueln+VknO+SayCLh3aVDJV6tOOyCNa?= =?us-ascii?q?OZunTAlM6STlM2yEwIi1FP/aJq3sc7b0qUS0cvwaOfFxQTK8XNNBpVYNBU9HjP?= =?us-ascii?q?eiaOqv7AzohpMIW4DOzoSvWOtKkMiEK+AAkpB5gM7tgGHpS01EHYKt3nI6ADyR?= =?us-ascii?q?Qs4wTmP1qFDPJUeB6RlzcHuc6/xodt3YZBPjEdHXl9MSKv67bMuAAqhPuDXNEr?= =?us-ascii?q?YnYVRYYLKnU2WMimlCFDpHRAECO70uQHxwie9zX8vDjfDCHgb9p/Y/eZfQ5jB8?= =?us-ascii?q?2z+TU49ai2lUPb/47AJ27kL9Riu97O6eQcp5qdDfNbU6V9uV/Gm4ZEX3yqT3LP?= =?us-ascii?q?EdmtKpjzcYktbcb7CnCmUly/kD81QMDxPM6xIaSShwHnW5pUupGB3D8/Lc+9Ci?= =?us-ascii?q?0eGxBoquEf5aJ8YAoDY4Y7YR/orAkxKq2/IQeC3dq1WWqtLyVZT+VHx+Wge7NX?= =?us-ascii?q?1zYsbvO9yHY4QZE61fO48UgRRJwRjxHewviiZ49CUSjzBHNdegPPpTYnmGh7LO?= =?us-ascii?q?oyxPkwwA/Qu1kGLz+LbPBpaHBDv9wkH1ySJXR2BXYmSFCEiIrC4gis37cU/yRH?= =?us-ascii?q?hNtbyuxFv2L4vpPGbjKsRbanqZPLvCo8ddImubF+MZT/Isuas5PThifQQ4fWsg?= =?us-ascii?q?CeSiG1CuRalcZKICJDWvZIg2EkNdYBuYpb5ko7Tt0+KKBXCKkwurCqbiJpDTQU?= =?us-ascii?q?zS8YS4yA3DsCguOn27XCjxmebY4sPQADvphZntQdVCt2bT8Eq6+4S4XajWmERX?= =?us-ascii?q?YXIA0L9wRD+BoAlpNsfuDi+IfHUJ1MxCRKrP9vTiTLEZ1o91/6Sm6Im1j4VOuu?= =?us-ascii?q?nPCp3Q5Iy/LsyNYbUgZlCUdB3+ZWilcoKLZvJqkKpIHKqDiIeljhsWLx0uupPk?= =?us-ascii?q?dRxtPQd135CorFum78UiwT+X0UWY9PxmvQFY4XkwZjbqYkuklMKpi8ekni/zwk?= =?us-ascii?q?25hpH76gWMGr3VkltmwJRyKrE9pHEOxmsU7XVyd+Y5+3sprpIZNSTXFM+JeFsV?= =?us-ascii?q?dWjF1tMzKlyZpbM8xM7CQAUyRPoTWcuduySddM2cxtAp8NPNhwpWnyFLlDOJiL?= =?us-ascii?q?rH08oqbvxWPB+zAgrFe6wy2+G7e/T+Jd5WIeAAsoJ2OaqkkhFOYs92DS8lfWsl?= =?us-ascii?q?9q4+hbHL+PjV5qoDZ8GJBOCSxF1Xe/L1R8VHNGqflVKLzJc8xARPk/fQWgOwYj?= =?us-ascii?q?Ff4gxUCJ/lp5nXb4YyxzqgtV4DrRXw8qWikJmr3tgyERqtm7OT8GTJJFdSkhby?= =?us-ascii?q?DAKw+AhSBboBNfZFpwV5AfHNlF56kR3ZFI8craVUasNSYFUQRiNg0iy/pQj0pD?= =?us-ascii?q?v1iDdC/AEwWobe7PvQNzfciPts6lNvP5/B1Iion/quA3670DR2G6mQ2qWd3er4?= =?us-ascii?q?j8ucOEtkSQbqf1KOy8bmHfQzfSlxywgq0kD5bS9SjJLAVbM4V6yWYjYZX5C27L?= =?us-ascii?q?OgpJKrkGKEVFTqB1d89GovxEaMB5YqoJ/7FiBg6fTBP1BIOvtOVGLkrURTnGNC?= =?us-ascii?q?qB/PCwrZ7R4LDAR+XtfdCDx3HCQ61rJJh68iX7F63s0YBA5kr8wu1t+V9iSVja?= =?us-ascii?q?LyCBq8zsJhkV68a/dkvtpIEpECjSAJd3jnri2F9MeNYQQyK37psU0pVZ52jsSe?= =?us-ascii?q?hgyEj8rPVS96V46Ykw+71p0dy0JbvIJvtHrU9qGQOUBgJ39pU3HGdwWWZRYvML?= =?us-ascii?q?KPjLeaQVl8fuq/r4F6YP8h2a5/RZacfbJ0HGgsS/FiucRgJakwgcsjMaMw+c1+?= =?us-ascii?q?Kfm6BuV8alpO/52kYz7FiiNBIGy6pt5Yic8KqSuODXdwfRzaQDWqXyQ8P8tLAs?= =?us-ascii?q?u0eM6v04iL4BYHZ6bhahEOcDSs4d3XvvwroyzS0yCc/DGazv+OJbXXIjgj3gg4?= =?us-ascii?q?x9H0kRGv4MH7qE555enmAjm+zdLNIWbLtPmmOSFR6gDr8CyGKk6yqNL2ljmRHC?= =?us-ascii?q?yRbwQXm87FXuty93XTPMz8v/kkpSTrS3B11dXyynOU9itzOAIRTnucHruasv6k?= =?us-ascii?q?E2KWvkuMiLlGS/JLNdB9f/K8CEISkouFIXi4U8RtOy2YAaHdq9JMke8HRlY/TD?= =?us-ascii?q?9WykiC5BrL1Bh4bE5cGV4PrXF2G6j6KGs7WN2CxYyn8gsFE57tCtLfDO59uPQ/?= =?us-ascii?q?iy1mYRSSl/uxHbUB6utrzbtU0UNlCX0EfWgowFIMtV3X4i1kHp/OIjWs489B1C?= =?us-ascii?q?FobcYPMPvTXzODzywVaDbNI4SDKT0z5WHl3vF1l3BrQ82Wz3vMLTlnfQ4EckRo?= =?us-ascii?q?9ueEz7nRZ3FZk3KVox6FgLxSoOCQwNaQueDLyoHknlI5ULWlUEaRSdxre6Yr03?= =?us-ascii?q?3Upxwryx+ODTcfZwB60XNvZSlgSOhkRUGooKsa0CR7JxY1pd9KrJqQjnDIjoQf?= =?us-ascii?q?zmmGE/NfKrRcBa6tgZuGE+4ga+XRWg7ZZD77AHiJ+Wcq5EZZnMvM9i4Edh+TEA?= =?us-ascii?q?aDZBgB5hgBOlSeocvvzs4sDHsJq07eajTL0tSP8J9xcuCGRxkYDwjUs4od7Nye?= =?us-ascii?q?dTUILVhprk8AxXJX6Fppra2QFmKeUSM4KrYKpg93IfKigcJnIOOMGba/wi7C5t?= =?us-ascii?q?LjrT/V1CAsUDZd8COsrChxxUgFXzWL5P7srbBkOYC4BresAp7mv40io6/ocnX+?= =?us-ascii?q?b79jC2OY7Q4E1XM/NEliVsm8rIpPIJzvrKFCgX/X6ZZgBuzSOD0JmMBez//eeN?= =?us-ascii?q?yNHIT1MJBDM2U4NGKTWe/gyoW/S6m4/0UgOO7c/zmogxeFiXRnyrk6QPqrxMHv?= =?us-ascii?q?JYiiXnwjheEZj4h+qPvNqw9GRXtlNGEIFp7R3GAalfJYt0ORD5lsmtW0h9CTDy?= =?us-ascii?q?eNnOeRoypOWWxukN4+JkN0v9f4MbIQwLy6j86XVLSgtiUrn2vkyWXegJfttpVO?= =?us-ascii?q?vErmxJ6YJnM6IPIEKdq4LurjhSrlA5HhQkZ6IxrjxVd0nOgBdaW73ut74alwsQ?= =?us-ascii?q?S9h5tlFQGWioImIx+yLHVbhJjKmWEPEV/S+cTrYQXEV0MiNzWBe12JRye7S3nf?= =?us-ascii?q?BIqH5GnjhnrPgszTNmWAO2uTfwqKIVxTIg5La4uS0OuXNbSOWejyDICVJEwPQR?= =?us-ascii?q?k6gcD3fi6VqhYHgMd4by5KdoJd7g9IY7+Xg/ZwssfzEeV+S6Fy7wl7+IApCIsN?= =?us-ascii?q?9Egh6NudnBbbi3LScILbQx0xPjR3960gjFhxZl624LTzqv7dM+I4W9I8klzDKy?= =?us-ascii?q?GWfHbFYM/r9JsMzpuF4EUOQ2ckhhzHx+3MaIQCMNRcrPG3s6jwU/ZmVEdYhM6R?= =?us-ascii?q?kEGKUyhTaIpKZG9BkOYDjICoSl5pXQncDQ1Hk/StdqxmTWqreZiZMq1H1lhs57?= =?us-ascii?q?7y+PuHQUbOzYUM5sD2Pt1ode1+zxffGtvf0GSId8zrSuTuMCONG5+WSqwJVqRl?= =?us-ascii?q?OlxrMGElq4Lu8M3LHbXjyhSW2FROuLcm+Mny0jPk71/xmoIUU9aN1WoE8lLuvC?= =?us-ascii?q?mplcmhXjUbxqSCWQq1vbwXctMOwAcQI5ppundxYMTOEPe+iWPfIuz+EmCFsQc3?= =?us-ascii?q?/JGjN7C+CysV6qkol0JXFg4UHhbOT29QDmNtqSFQUeHY7csJFx5eSwRnidNn94?= =?us-ascii?q?0B1yIE50+v/dF1Qxtu5ca5GRndzRh9Rnz+EIbPJtMSwhut4JhI1v846U0N2FcR?= =?us-ascii?q?vJ1Jb9OcnVouSEA/3Y10kqZmBaUr8CbAPp5oU1It05VKPXHbdDuxQTG7Q6SoQ7?= =?us-ascii?q?N2jt7KF0MB9zcgnJabSxg8nqpeGLZpxPqn/U9F0wLyDcuxsdxfyyVwB7aY6lh2?= =?us-ascii?q?nqKpAqWj1Bt8FtCgdhHIZXAMwPsQynA4KPlaGgj9+x/F96u/MUsaXuF//GztO5?= =?us-ascii?q?359+X5JC/0yEIC7RBLV3gkRilumyjOnP0p3wCcP6Z9wJT+l6Qm/Aar/DAIq/MD?= =?us-ascii?q?aONdzmd05B6b6c36pzUg+NayDhQ6qGqCqkOe1q4EUj0Ix4ffbcwyI24rHe2dvy?= =?us-ascii?q?e3tbqTm5oX6OLptf40TABfbCUBJMVfqF7GFlELUQbYvw6ugDKsQiwNyG7Alo8D?= =?us-ascii?q?RC0deKI7S7rkDSxE13b5TbI1X12ywhQ4kFPAy/MVcwgW/esnndBXVcLs65Kchi?= =?us-ascii?q?mdqVCh3t51JtmWE2fWNBG3DnRdGWOWQB3MK+fgKK/hpRD9kfh+63ZVI4tqqqRO?= =?us-ascii?q?lzJJpFneSqtLMakddmLC3BS9RaPyHOI79sIDVRFv/AqUMrYhEaqbg1XJk6ZZyV?= =?us-ascii?q?L0MaP0eM0yTyzRHN0UfsbdyjyL6JIDoK8nVA17/F1TlMpxKlufuCg8zjSbbZY4?= =?us-ascii?q?vsUP7ULiUlSimQRS4uHkax5Vekp/0EseKdIWgFvl8UYiOSCAgUpq10s9jQD2nT?= =?us-ascii?q?lvNnfJ0LgvCaRi/xRDd/lKooCSZBrVqMTOYbFQnKc3/hh3JRuA64Kf9P+nLqdK?= =?us-ascii?q?aVxrdTW+wKAotMdeCZQ9TYefBCPTsokCsWOPqkdd3Gs7k5yk7ITXceE6TQ+12R?= =?us-ascii?q?VlWZQuadxz31WYUYpJY0ui4y9dLLny93Dr7EP7CBqD6y6oS4ljqXufXCVmkxZE?= =?us-ascii?q?w4mOACAGyGwBlaMmEECsoVtVrrQqGaYkZDynMphfhp2x8WdwR5Smdu3WFOnPah?= =?us-ascii?q?Bs1ZTkYZg32sQP0BbFB3Cigw/UiM4gDpbtwAo93TR3FA+bsWU4YdKucn6JXPMq?= =?us-ascii?q?sK3PkpxC5moDA9syiFFFNdgAeF/LbREa9/3bBC+3c3/+t3XkCORDPfdHLLyoy4?= =?us-ascii?q?BMJT3S1uu2zr19LIvuBxM7tXv4N5AFAMASJyPd3d+C5OXnz62Au1pRa0ACqRLC?= =?us-ascii?q?gf4DkVOSxWPtpymvR2tBfOa8bp9VKbt6VnrlCiTwmMFOmawptOX+Pg0AijIQJC?= =?us-ascii?q?aymmDdgiqOlGncwOO4s7dIO+BBbHNQG4AQWG7XNfvCP2q6imWJMZil4Vlb8hfY?= =?us-ascii?q?u0B4Q=3D?= X-IPAS-Result: =?us-ascii?q?A2F7DwCamTRY/wHyM5BdGwEBAQMBAQEJAQEBFgEBAQMBAQE?= =?us-ascii?q?JAQEBgw0BAQEBAR9YcRCmWwGKTYogIAOBeFOFUlMBAQEBAQEBAQIBAl8FI0ISA?= =?us-ascii?q?YFoAQMDAgIBAQaBAls8AgQBAhcBDBMUIA4DCQEBFykICAMBLRURDgsFGASITLI?= =?us-ascii?q?OPSoCi1aPMwoHAYVfHgWBJQGHKgeGFXxFih8ChkeGHYQZAoIGOIdchhCRclVeF?= =?us-ascii?q?QI7L4I0AQEBRByBe1SEcl0CDRcEA4IQAQEB?= Received: from unknown (HELO tarius.tycho.ncsc.mil) ([144.51.242.1]) by emsm-gh1-uea11.nsa.gov with ESMTP; 22 Nov 2016 19:21:30 +0000 Received: from prometheus.infosec.tycho.ncsc.mil (prometheus [192.168.25.40]) by tarius.tycho.ncsc.mil (8.14.4/8.14.4) with ESMTP id uAMJLQwf009784; Tue, 22 Nov 2016 14:21:28 -0500 Received: from tarius.tycho.ncsc.mil (tarius.infosec.tycho.ncsc.mil [144.51.242.1]) by prometheus.infosec.tycho.ncsc.mil (8.15.2/8.15.2) with ESMTP id uAMJIcXZ031402 for ; Tue, 22 Nov 2016 14:18:38 -0500 Received: from moss-lions.infosec.tycho.ncsc.mil (moss-lions [192.168.25.4]) by tarius.tycho.ncsc.mil (8.14.4/8.14.4) with ESMTP id uAMJIcuj008417 for ; Tue, 22 Nov 2016 14:18:38 -0500 From: James Carter To: selinux@tycho.nsa.gov Subject: [PATCH 1/2 v2] libsepol/cil: Add ability to write policy.conf file from CIL AST Date: Tue, 22 Nov 2016 14:18:15 -0500 Message-Id: <1479842296-21906-2-git-send-email-jwcart2@tycho.nsa.gov> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1479842296-21906-1-git-send-email-jwcart2@tycho.nsa.gov> References: <1479842296-21906-1-git-send-email-jwcart2@tycho.nsa.gov> X-BeenThere: selinux@tycho.nsa.gov X-Mailman-Version: 2.1.20 Precedence: list List-Id: "Security-Enhanced Linux \(SELinux\) mailing list" List-Post: List-Help: MIME-Version: 1.0 Errors-To: selinux-bounces@tycho.nsa.gov Sender: "Selinux" X-Virus-Scanned: ClamAV using ClamSMTP The ability to create a policy.conf file from the CIL AST has been a desire from the beginning to assist in debugging and for general flexibility. Some work towards this end was started early in CIL's history, but cil_policy.c has not been remotely functional in a long time. Until now. The function cil_write_policy_conf() will write a policy.conf file from a CIL AST after cil_build_ast(), cil_resolve_ast(), cil_fqn_qualify(), and cil_post_process() have been called. Signed-off-by: James Carter --- libsepol/cil/include/cil/cil.h | 1 + libsepol/cil/src/cil.c | 6 + libsepol/cil/src/cil_policy.c | 2714 ++++++++++++++++++++++++---------------- libsepol/cil/src/cil_policy.h | 12 +- libsepol/src/libsepol.map.in | 1 + 5 files changed, 1629 insertions(+), 1105 deletions(-) diff --git a/libsepol/cil/include/cil/cil.h b/libsepol/cil/include/cil/cil.h index e4b10c5..c4a6fb9 100644 --- a/libsepol/cil/include/cil/cil.h +++ b/libsepol/cil/include/cil/cil.h @@ -52,6 +52,7 @@ extern int cil_set_handle_unknown(cil_db_t *db, int handle_unknown); extern void cil_set_mls(cil_db_t *db, int mls); extern void cil_set_target_platform(cil_db_t *db, int target_platform); extern void cil_set_policy_version(cil_db_t *db, int policy_version); +extern void cil_write_policy_conf(FILE *out, struct cil_db *db); enum cil_log_level { CIL_ERR = 1, diff --git a/libsepol/cil/src/cil.c b/libsepol/cil/src/cil.c index 9b18773..15833c13 100644 --- a/libsepol/cil/src/cil.c +++ b/libsepol/cil/src/cil.c @@ -461,6 +461,12 @@ exit: return rc; } +void cil_write_policy_conf(FILE *out, struct cil_db *db) +{ + cil_log(CIL_INFO, "Writing policy.conf file\n"); + cil_gen_policy(out, db); +} + void cil_destroy_data(void **data, enum cil_flavor flavor) { if (*data == NULL) { diff --git a/libsepol/cil/src/cil_policy.c b/libsepol/cil/src/cil_policy.c index 382129b..26c0d14 100644 --- a/libsepol/cil/src/cil_policy.c +++ b/libsepol/cil/src/cil_policy.c @@ -1,16 +1,16 @@ /* * Copyright 2011 Tresys Technology, LLC. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO @@ -21,7 +21,7 @@ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those * of the authors and should not be interpreted as representing official policies, * either expressed or implied, of Tresys Technology, LLC. @@ -39,1388 +39,1914 @@ #include "cil_internal.h" #include "cil_flavor.h" -#include "cil_log.h" +#include "cil_find.h" #include "cil_mem.h" #include "cil_tree.h" #include "cil_list.h" -#include "cil_policy.h" #include "cil_symtab.h" -#include "cil_strpool.h" - -#define SEPOL_DONE 555 - -#define CLASS_DECL 0 -#define ISIDS 1 -#define COMMONS 2 -#define CLASSES 3 -#define INTERFACES 4 -#define SENS 5 -#define CATS 6 -#define LEVELS 7 -#define CONSTRAINS 8 -#define TYPEATTRTYPES 9 -#define ALIASES 10 -#define ALLOWS 11 -#define CONDS 12 -#define USERROLES 13 -#define SIDS 14 -#define NETIFCONS 15 - -#define BUFFER 1024 -#define NUM_POLICY_FILES 16 - -struct cil_args_genpolicy { - struct cil_list *users; - struct cil_list *sens; - struct cil_list *cats; - FILE **file_arr; -}; - -struct cil_args_booleanif { - FILE **file_arr; - uint32_t *file_index; -}; -int cil_expr_to_policy(FILE **file_arr, uint32_t file_index, struct cil_list *expr); +enum cil_statement_list { + CIL_LIST_COMMON = 1, + CIL_LIST_DEFAULT_USER, + CIL_LIST_DEFAULT_ROLE, + CIL_LIST_DEFAULT_TYPE, + CIL_LIST_DEFAULT_RANGE, + CIL_LIST_SENSALIAS, + CIL_LIST_CATALIAS, + CIL_LIST_MLSCONSTRAIN, + CIL_LIST_MLSVALIDATETRANS, + CIL_LIST_POLICYCAP, + CIL_LIST_TYPEATTRIBUTE, + CIL_LIST_ROLEATTRIBUTE, + CIL_LIST_BOOL, + CIL_LIST_TYPE, + CIL_LIST_TYPEALIAS, + CIL_LIST_ROLE, + CIL_LIST_ROLEALLOW, + CIL_LIST_ROLETRANSITION, + CIL_LIST_USER, + CIL_LIST_CONSTRAINT, + CIL_LIST_VALIDATETRANS, + CIL_LIST_NUM_LISTS +}; -int cil_combine_policy(FILE **file_arr, FILE *policy_file) +static int __cil_gather_statements_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args) { - char temp[BUFFER]; - int i, rc, rc_read, rc_write; + struct cil_list **lists; + int kind = 0; - for(i=0; i rc_write) { - rc = fwrite(temp+rc_write, 1, rc_read-rc_write, policy_file); - rc_write += rc; - if (rc == 0 && ferror(file_arr[i])) { - cil_log(CIL_ERR, "Error writing to policy.conf\n"); - return SEPOL_ERR; - } - } + lists = (struct cil_list **)extra_args; + + switch (node->flavor) { + case CIL_BLOCK: { + struct cil_block *blk = node->data; + if (blk->is_abstract == CIL_TRUE) { + *finished = CIL_TREE_SKIP_HEAD; + } + break; + } + case CIL_MACRO: + *finished = CIL_TREE_SKIP_HEAD; + break; + case CIL_BOOLEANIF: + *finished = CIL_TREE_SKIP_HEAD; + break; + case CIL_COMMON: + kind = CIL_LIST_COMMON; + break; + case CIL_DEFAULTUSER: + kind = CIL_LIST_DEFAULT_USER; + break; + case CIL_DEFAULTROLE: + kind = CIL_LIST_DEFAULT_ROLE; + break; + case CIL_DEFAULTTYPE: + kind = CIL_LIST_DEFAULT_TYPE; + break; + case CIL_DEFAULTRANGE: + kind = CIL_LIST_DEFAULT_RANGE; + break; + case CIL_SENSALIAS: + kind = CIL_LIST_SENSALIAS; + break; + case CIL_CATALIAS: + kind = CIL_LIST_CATALIAS; + break; + case CIL_MLSCONSTRAIN: + kind = CIL_LIST_MLSCONSTRAIN; + break; + case CIL_MLSVALIDATETRANS: + kind = CIL_LIST_MLSVALIDATETRANS; + break; + case CIL_POLICYCAP: + kind = CIL_LIST_POLICYCAP; + break; + case CIL_TYPEATTRIBUTE: { + struct cil_typeattribute *attr = node->data; + if (strcmp(attr->datum.fqn, "cil_gen_require") != 0) { + kind = CIL_LIST_TYPEATTRIBUTE; + } + break; + } + case CIL_ROLEATTRIBUTE: { + struct cil_roleattribute *attr = node->data; + if (strcmp(attr->datum.fqn, "cil_gen_require") != 0) { + kind = CIL_LIST_ROLEATTRIBUTE; + } + break; + } + case CIL_BOOL: + kind = CIL_LIST_BOOL; + break; + case CIL_TYPE: + kind = CIL_LIST_TYPE; + break; + case CIL_TYPEALIAS: + kind = CIL_LIST_TYPEALIAS; + break; + case CIL_ROLE: { + struct cil_role *role = node->data; + if (strcmp(role->datum.fqn, "object_r") != 0) { + kind = CIL_LIST_ROLE; } + break; + } + case CIL_ROLEALLOW: + kind = CIL_LIST_ROLEALLOW; + break; + case CIL_ROLETRANSITION: + kind = CIL_LIST_ROLETRANSITION; + break; + case CIL_USER: + kind = CIL_LIST_USER; + break; + case CIL_CONSTRAIN: + kind = CIL_LIST_CONSTRAINT; + break; + case CIL_VALIDATETRANS: + kind = CIL_LIST_VALIDATETRANS; + break; + default: + break; + } + + if (kind > 0) { + cil_list_append(lists[kind], node->flavor, node->data); } return SEPOL_OK; } -int cil_portcon_to_policy(FILE **file_arr, struct cil_sort *sort) +static void cil_gather_statements(struct cil_tree_node *start, struct cil_list *lists[]) { - uint32_t i = 0; + cil_tree_walk(start, __cil_gather_statements_helper, NULL, NULL, lists); +} - for (i=0; icount; i++) { - struct cil_portcon *portcon = (struct cil_portcon*)sort->array[i]; - fprintf(file_arr[NETIFCONS], "portcon "); - if (portcon->proto == CIL_PROTOCOL_UDP) { - fprintf(file_arr[NETIFCONS], "udp "); - } else if (portcon->proto == CIL_PROTOCOL_TCP) { - fprintf(file_arr[NETIFCONS], "tcp "); - } else if (portcon->proto == CIL_PROTOCOL_DCCP) { - fprintf(file_arr[NETIFCONS], "dccp "); - } - fprintf(file_arr[NETIFCONS], "%d ", portcon->port_low); - fprintf(file_arr[NETIFCONS], "%d ", portcon->port_high); - cil_context_to_policy(file_arr, NETIFCONS, portcon->context); - fprintf(file_arr[NETIFCONS], ";\n"); - } +static void cil_simple_rules_to_policy(FILE *out, struct cil_list *rules, char *kind) +{ + struct cil_list_item *i1; - return SEPOL_OK; + cil_list_for_each(i1, rules) { + fprintf(out, "%s %s;\n", kind, DATUM(i1->data)->fqn); + } } -int cil_genfscon_to_policy(FILE **file_arr, struct cil_sort *sort) +static void cil_cats_to_policy(FILE *out, struct cil_cats *cats) { - uint32_t i = 0; - - for (i=0; icount; i++) { - struct cil_genfscon *genfscon = (struct cil_genfscon*)sort->array[i]; - fprintf(file_arr[NETIFCONS], "genfscon %s ", genfscon->fs_str); - fprintf(file_arr[NETIFCONS], "%s ", genfscon->path_str); - cil_context_to_policy(file_arr, NETIFCONS, genfscon->context); - fprintf(file_arr[NETIFCONS], ";\n"); + char *lead = ""; + struct cil_cat *first = NULL, *last = NULL, *cat; + struct cil_list_item *i1; + + cil_list_for_each(i1, cats->datum_expr) { + cat = i1->data; + if (first == NULL) { + first = cat; + } else if (last == NULL) { + if (cat->value == first->value + 1) { + last = cat; + } else { + fprintf(out, "%s%s", lead, DATUM(first)->fqn); + lead = ","; + first = cat; + } + } else if (cat->value == last->value + 1) { + last = cat; + } else { + fprintf(out, "%s%s", lead, DATUM(first)->fqn); + lead = ","; + if (last->value >= first->value + 1) { + fprintf(out, "."); + } else { + fprintf(out, ","); + } + fprintf(out, "%s", DATUM(last)->fqn); + first = cat; + last = NULL; + } + } + if (first) { + fprintf(out, "%s%s", lead, DATUM(first)->fqn); + if (last != NULL) { + if (last->value >= first->value + 1) { + fprintf(out, "."); + } else { + fprintf(out, ","); + } + fprintf(out, "%s", DATUM(last)->fqn); + } } +} - return SEPOL_OK; +static void cil_level_to_policy(FILE *out, struct cil_level *level) +{ + fprintf(out, "%s", DATUM(level->sens)->fqn); + if (level->cats != NULL) { + fprintf(out, ":"); + cil_cats_to_policy(out, level->cats); + } } -int cil_netifcon_to_policy(FILE **file_arr, struct cil_sort *sort) +static int cil_levels_simple_and_equal(struct cil_level *l1, struct cil_level *l2) { - uint32_t i = 0; + /* Mostly just want to detect s0 - s0 ranges */ + if (l1 == l2) + return CIL_TRUE; - for (i=0; icount; i++) { - struct cil_netifcon *netifcon = (struct cil_netifcon*)sort->array[i]; - fprintf(file_arr[NETIFCONS], "netifcon %s ", netifcon->interface_str); - cil_context_to_policy(file_arr, NETIFCONS, netifcon->if_context); - fprintf(file_arr[NETIFCONS], " "); - cil_context_to_policy(file_arr, NETIFCONS, netifcon->packet_context); - fprintf(file_arr[NETIFCONS], ";\n"); - } + if (l1->sens == l2->sens && (l1->cats == NULL && l2->cats == NULL)) + return CIL_TRUE; - return SEPOL_OK; + return CIL_FALSE; } -int cil_nodecon_to_policy(FILE **file_arr, struct cil_sort *sort) +static void cil_levelrange_to_policy(FILE *out, struct cil_levelrange *lvlrange) { - uint32_t i = 0; - int rc = SEPOL_ERR; + cil_level_to_policy(out, lvlrange->low); + if (cil_levels_simple_and_equal(lvlrange->low, lvlrange->high) == CIL_FALSE) { + fprintf(out, " - "); + cil_level_to_policy(out, lvlrange->high); + } +} - for (i=0; icount; i++) { - struct cil_nodecon *nodecon = (struct cil_nodecon*)sort->array[i]; - char *buf = NULL; - errno = 0; - if (nodecon->addr->family == AF_INET) { - buf = cil_malloc(INET_ADDRSTRLEN); - inet_ntop(nodecon->addr->family, &nodecon->addr->ip.v4, buf, INET_ADDRSTRLEN); - } else if (nodecon->addr->family == AF_INET6) { - buf = cil_malloc(INET6_ADDRSTRLEN); - inet_ntop(nodecon->addr->family, &nodecon->addr->ip.v6, buf, INET6_ADDRSTRLEN); - } +static void cil_context_to_policy(FILE *out, struct cil_context *context, int mls) +{ + fprintf(out, "%s:", DATUM(context->user)->fqn); + fprintf(out, "%s:", DATUM(context->role)->fqn); + fprintf(out, "%s", DATUM(context->type)->fqn); + if (mls) { + fprintf(out, ":"); + cil_levelrange_to_policy(out, context->range); + } +} - if (errno != 0) { - cil_log(CIL_INFO, "Failed to convert ip address to string\n"); - rc = SEPOL_ERR; - goto exit; +static void cil_cond_expr_to_policy(FILE *out, struct cil_list *expr, int first) +{ + struct cil_list_item *i1 = expr->head; + + if (i1->flavor == CIL_OP) { + enum cil_flavor op = (enum cil_flavor)i1->data; + fprintf(out, "("); + switch (op) { + case CIL_NOT: + fprintf(out, "! "); + cil_cond_expr_to_policy(out, i1->next->data, CIL_FALSE); + break; + case CIL_OR: + cil_cond_expr_to_policy(out, i1->next->data, CIL_FALSE); + fprintf(out, " || "); + cil_cond_expr_to_policy(out, i1->next->next->data, CIL_FALSE); + break; + case CIL_AND: + cil_cond_expr_to_policy(out, i1->next->data, CIL_FALSE); + fprintf(out, " && "); + cil_cond_expr_to_policy(out, i1->next->next->data, CIL_FALSE); + break; + case CIL_XOR: + cil_cond_expr_to_policy(out, i1->next->data, CIL_FALSE); + fprintf(out, " ^ "); + cil_cond_expr_to_policy(out, i1->next->next->data, CIL_FALSE); + break; + case CIL_EQ: + cil_cond_expr_to_policy(out, i1->next->data, CIL_FALSE); + fprintf(out, " == "); + cil_cond_expr_to_policy(out, i1->next->next->data, CIL_FALSE); + break; + case CIL_NEQ: + cil_cond_expr_to_policy(out, i1->next->data, CIL_FALSE); + fprintf(out, " != "); + cil_cond_expr_to_policy(out, i1->next->next->data, CIL_FALSE); + break; + default: + fprintf(out, "???"); + break; } - - fprintf(file_arr[NETIFCONS], "nodecon %s ", buf); - free(buf); - - if (nodecon->mask->family == AF_INET) { - buf = cil_malloc(INET_ADDRSTRLEN); - inet_ntop(nodecon->mask->family, &nodecon->mask->ip.v4, buf, INET_ADDRSTRLEN); - } else if (nodecon->mask->family == AF_INET6) { - buf = cil_malloc(INET6_ADDRSTRLEN); - inet_ntop(nodecon->mask->family, &nodecon->mask->ip.v6, buf, INET6_ADDRSTRLEN); + fprintf(out, ")"); + } else if (i1->flavor == CIL_DATUM) { + if (first == CIL_TRUE) { + fprintf(out, "("); } - - if (errno != 0) { - cil_log(CIL_INFO, "Failed to convert mask to string\n"); - rc = SEPOL_ERR; - goto exit; + fprintf(out, "%s", DATUM(i1->data)->fqn); + if (first == CIL_TRUE) { + fprintf(out, ")"); } + } else if (i1->flavor == CIL_LIST) { + cil_cond_expr_to_policy(out, i1->data, CIL_FALSE); + } else { + fprintf(out, "???"); + } +} - fprintf(file_arr[NETIFCONS], "%s ", buf); - free(buf); +static size_t __cil_userattribute_len(struct cil_db *db, struct cil_userattribute *attr) +{ + ebitmap_node_t *unode; + unsigned int i; + size_t len = 0; - cil_context_to_policy(file_arr, NETIFCONS, nodecon->context); - fprintf(file_arr[NETIFCONS], ";\n"); + ebitmap_for_each_bit(attr->users, unode, i) { + if (!ebitmap_get_bit(attr->users, i)) + continue; + len += strlen(DATUM(db->val_to_user[i])->fqn); + len++; } - return SEPOL_OK; - -exit: - return rc; + return len; } +static size_t __cil_cons_leaf_operand_len(struct cil_db *db, struct cil_list_item *operand) +{ + struct cil_list_item *i1; + enum cil_flavor flavor = operand->flavor; + size_t len = 0; + + if (flavor == CIL_CONS_OPERAND) { + len = 2; + } else if (flavor == CIL_DATUM) { + struct cil_tree_node *node = NODE(operand->data); + if (node->flavor == CIL_USERATTRIBUTE) { + len = __cil_userattribute_len(db, operand->data); + len++; /* "{" */ + } else { + len = strlen(DATUM(operand->data)->fqn); + } + } else if (flavor == CIL_LIST) { + len = 1; /* "{" */ + cil_list_for_each(i1, (struct cil_list *)operand->data) { + struct cil_tree_node *node = NODE(operand->data); + if (node->flavor == CIL_USERATTRIBUTE) { + len = __cil_userattribute_len(db, operand->data); + } else { + len += strlen(DATUM(operand->data)->fqn); + len++; /* " " or "}" */ + } + } + } + + return len; +} -int cil_pirqcon_to_policy(FILE **file_arr, struct cil_sort *sort) +static size_t __cil_cons_leaf_op_len(struct cil_list_item *op) { - uint32_t i = 0; + enum cil_flavor flavor = (enum cil_flavor)op->data; + size_t len; - for (i = 0; i < sort->count; i++) { - struct cil_pirqcon *pirqcon = (struct cil_pirqcon*)sort->array[i]; - fprintf(file_arr[NETIFCONS], "pirqcon %d ", pirqcon->pirq); - cil_context_to_policy(file_arr, NETIFCONS, pirqcon->context); - fprintf(file_arr[NETIFCONS], ";\n"); + switch (flavor) { + case CIL_EQ: + len = 4; /* " == " */ + break; + case CIL_NEQ: + len = 4; /* " != " */ + break; + case CIL_CONS_DOM: + len = 5; /* " dom " */ + break; + case CIL_CONS_DOMBY: + len = 7; /* " domby " */ + break; + case CIL_CONS_INCOMP: + len = 8; /* " incomp " */ + break; + default: + /* Should be impossible to be here */ + len = 5; /* " ??? " */ } - return SEPOL_OK; + return len; } -int cil_iomemcon_to_policy(FILE **file_arr, struct cil_sort *sort) + +static size_t cil_cons_expr_len(struct cil_db *db, struct cil_list *cons_expr) { - uint32_t i = 0; + struct cil_list_item *i1; + enum cil_flavor op; + size_t len; - for (i = 0; i < sort->count; i++) { - struct cil_iomemcon *iomemcon = (struct cil_iomemcon*)sort->array[i]; - fprintf(file_arr[NETIFCONS], "iomemcon %"PRId64"-%"PRId64" ", iomemcon->iomem_low, iomemcon->iomem_high); - cil_context_to_policy(file_arr, NETIFCONS, iomemcon->context); - fprintf(file_arr[NETIFCONS], ";\n"); + i1 = cons_expr->head; + + op = (enum cil_flavor)i1->data; + switch (op) { + case CIL_NOT: + len = 6; /* "(not )" */ + len += cil_cons_expr_len(db, i1->next->data); + break; + case CIL_AND: + len = 7; /* "( and )" */ + len += cil_cons_expr_len(db, i1->next->data); + len += cil_cons_expr_len(db, i1->next->next->data); + break; + case CIL_OR: + len = 6; /* "( or )" */ + len += cil_cons_expr_len(db, i1->next->data); + len += cil_cons_expr_len(db, i1->next->next->data); + break; + default: + len = 2; /* "()" */ + len += __cil_cons_leaf_operand_len(db, i1->next); + len += __cil_cons_leaf_op_len(i1); + len += __cil_cons_leaf_operand_len(db, i1->next->next); } - return SEPOL_OK; + return len; } -int cil_ioportcon_to_policy(FILE **file_arr, struct cil_sort *sort) +static char *__cil_userattribute_to_string(struct cil_db *db, struct cil_userattribute *attr, char *new) { - uint32_t i = 0; + ebitmap_node_t *unode; + unsigned int i; + char *str; + size_t len; + + ebitmap_for_each_bit(attr->users, unode, i) { + if (!ebitmap_get_bit(attr->users, i)) + continue; + str = DATUM(db->val_to_user[i])->fqn; + len = strlen(str); + memcpy(new, str, len); + new += len; + *new++ = ' '; + } + + return new; +} - for (i = 0; i < sort->count; i++) { - struct cil_ioportcon *ioportcon = (struct cil_ioportcon*)sort->array[i]; - fprintf(file_arr[NETIFCONS], "ioportcon %d-%d ", ioportcon->ioport_low, ioportcon->ioport_high); - cil_context_to_policy(file_arr, NETIFCONS, ioportcon->context); - fprintf(file_arr[NETIFCONS], ";\n"); +static char *__cil_cons_leaf_operand_to_string(struct cil_db *db, struct cil_list_item *operand, char *new) +{ + struct cil_list_item *i1; + enum cil_flavor flavor = operand->flavor; + char *o_str; + size_t o_len; + + if (flavor == CIL_CONS_OPERAND) { + enum cil_flavor o_flavor = (enum cil_flavor)operand->data; + switch (o_flavor) { + case CIL_CONS_U1: + o_str = "u1"; + break; + case CIL_CONS_U2: + o_str = "u2"; + break; + case CIL_CONS_U3: + o_str = "u3"; + break; + case CIL_CONS_R1: + o_str = "r1"; + break; + case CIL_CONS_R2: + o_str = "r2"; + break; + case CIL_CONS_R3: + o_str = "r3"; + break; + case CIL_CONS_T1: + o_str = "t1"; + break; + case CIL_CONS_T2: + o_str = "t2"; + break; + case CIL_CONS_T3: + o_str = "t3"; + break; + case CIL_CONS_L1: + o_str = "l1"; + break; + case CIL_CONS_L2: + o_str = "l2"; + break; + case CIL_CONS_H1: + o_str = "h1"; + break; + case CIL_CONS_H2: + o_str = "h2"; + break; + default: + /* Impossible */ + o_str = "??"; + } + strcpy(new, o_str); + new += 2; + } else if (flavor == CIL_DATUM) { + struct cil_tree_node *node = NODE(operand->data); + if (node->flavor == CIL_USERATTRIBUTE) { + *new++ = '{'; + new = __cil_userattribute_to_string(db, operand->data, new); + new--; + *new++ = '}'; + } else { + o_str = DATUM(operand->data)->fqn; + o_len = strlen(o_str); + memcpy(new, o_str, o_len); + new += o_len; + } + } else if (flavor == CIL_LIST) { + *new++ = '{'; + cil_list_for_each(i1, (struct cil_list *)operand->data) { + struct cil_tree_node *node = NODE(operand->data); + if (node->flavor == CIL_USERATTRIBUTE) { + new = __cil_userattribute_to_string(db, operand->data, new); + } else { + o_str = DATUM(operand->data)->fqn; + o_len = strlen(o_str); + memcpy(new, o_str, o_len); + new += o_len; + *new++ = ' '; + } + } + new--; + *new++ = '}'; } - return SEPOL_OK; + return new; } -int cil_pcidevicecon_to_policy(FILE **file_arr, struct cil_sort *sort) +static char *__cil_cons_leaf_op_to_string(struct cil_list_item *op, char *new) { - uint32_t i = 0; + enum cil_flavor flavor = (enum cil_flavor)op->data; + char *op_str; + size_t len; + + switch (flavor) { + case CIL_EQ: + op_str = " == "; + len = 4; + break; + case CIL_NEQ: + op_str = " != "; + len = 4; + break; + case CIL_CONS_DOM: + op_str = " dom "; + len = 5; + break; + case CIL_CONS_DOMBY: + op_str = " domby "; + len = 7; + break; + case CIL_CONS_INCOMP: + op_str = " incomp "; + len = 8; + break; + default: + /* Should be impossible to be here */ + op_str = " ??? "; + len = 5; + } + + strcpy(new, op_str); + new += len; + + return new; +} - for (i = 0; i < sort->count; i++) { - struct cil_pcidevicecon *pcidevicecon = (struct cil_pcidevicecon*)sort->array[i]; - fprintf(file_arr[NETIFCONS], "pcidevicecon %d ", pcidevicecon->dev); - cil_context_to_policy(file_arr, NETIFCONS, pcidevicecon->context); - fprintf(file_arr[NETIFCONS], ";\n"); +static char *__cil_cons_expr_to_string(struct cil_db *db, struct cil_list *cons_expr, char *new) +{ + struct cil_list_item *i1; + enum cil_flavor op; + + i1 = cons_expr->head; + + op = (enum cil_flavor)i1->data; + switch (op) { + case CIL_NOT: + *new++ = '('; + strcpy(new, "not "); + new += 4; + new = __cil_cons_expr_to_string(db, i1->next->data, new); + *new++ = ')'; + break; + case CIL_AND: + *new++ = '('; + new = __cil_cons_expr_to_string(db, i1->next->data, new); + strcpy(new, " and "); + new += 5; + new = __cil_cons_expr_to_string(db, i1->next->next->data, new); + *new++ = ')'; + break; + case CIL_OR: + *new++ = '('; + new = __cil_cons_expr_to_string(db, i1->next->data, new); + strcpy(new, " or "); + new += 4; + new = __cil_cons_expr_to_string(db, i1->next->next->data, new); + *new++ = ')'; + break; + default: + *new++ = '('; + new = __cil_cons_leaf_operand_to_string(db, i1->next, new); + new = __cil_cons_leaf_op_to_string(i1, new); + new = __cil_cons_leaf_operand_to_string(db, i1->next->next, new); + *new++ = ')'; } - return SEPOL_OK; + return new; } -int cil_fsuse_to_policy(FILE **file_arr, struct cil_sort *sort) +static char *cil_cons_expr_to_string(struct cil_db *db, struct cil_list *cons_expr) { - uint32_t i = 0; + char *new, *tail; + size_t len = cil_cons_expr_len(db, cons_expr); - for (i=0; icount; i++) { - struct cil_fsuse *fsuse = (struct cil_fsuse*)sort->array[i]; - if (fsuse->type == CIL_FSUSE_XATTR) { - fprintf(file_arr[NETIFCONS], "fs_use_xattr "); - } else if (fsuse->type == CIL_FSUSE_TASK) { - fprintf(file_arr[NETIFCONS], "fs_use_task "); - } else if (fsuse->type == CIL_FSUSE_TRANS) { - fprintf(file_arr[NETIFCONS], "fs_use_trans "); - } else { - return SEPOL_ERR; - } - fprintf(file_arr[NETIFCONS], "%s ", fsuse->fs_str); - cil_context_to_policy(file_arr, NETIFCONS, fsuse->context); - fprintf(file_arr[NETIFCONS], ";\n"); - } + new = cil_malloc(len+1); + tail = __cil_cons_expr_to_string(db, cons_expr, new); + *tail = '\0'; - return SEPOL_OK; + return new; } -int cil_multimap_insert(struct cil_list *list, struct cil_symtab_datum *key, struct cil_symtab_datum *value, uint32_t key_flavor, uint32_t val_flavor) +static void cil_classperms_to_string(struct cil_classperms *classperms, struct cil_list *classperms_strs) { - struct cil_list_item *curr_key; - struct cil_multimap_item *new_data; + struct cil_list_item *i1; + size_t len = 0; + char *new, *curr; - if (list == NULL || key == NULL) { - return SEPOL_ERR; + len += strlen(DATUM(classperms->class)->fqn) + 1; + cil_list_for_each(i1, classperms->perms) { + len += strlen(DATUM(i1->data)->fqn) + 1; } + len += 4; /* for "{ " and " }" */ - cil_list_for_each(curr_key, list) { - struct cil_multimap_item *curr_multimap_item = curr_key->data; - if (curr_multimap_item != NULL) { - if (curr_multimap_item->key != NULL && curr_multimap_item->key == key) { - struct cil_list_item *curr_value; - cil_list_for_each(curr_value, curr_multimap_item->values) { - if (curr_value == (struct cil_list_item*)value) { - return SEPOL_OK;; - } + new = cil_malloc(len); + curr = new; + + curr[len-1] = '\0'; + + len = strlen(DATUM(classperms->class)->fqn); + memcpy(curr, DATUM(classperms->class)->fqn, len); + curr += len; + *curr++ = ' '; + + *curr++ = '{'; + *curr++ = ' '; + cil_list_for_each(i1, classperms->perms) { + len = strlen(DATUM(i1->data)->fqn); + memcpy(curr, DATUM(i1->data)->fqn, len); + curr += len; + *curr++ = ' '; + } + *curr++ = '}'; + + cil_list_append(classperms_strs, CIL_STRING, new); +} + +static void cil_classperms_to_strings(struct cil_list *classperms, struct cil_list *classperms_strs) +{ + struct cil_list_item *i1; + + cil_list_for_each(i1, classperms) { + if (i1->flavor == CIL_CLASSPERMS) { + struct cil_classperms *cp = i1->data; + if (FLAVOR(cp->class) == CIL_CLASS) { + cil_classperms_to_string(cp, classperms_strs); + } else { /* MAP */ + struct cil_list_item *i2 = NULL; + cil_list_for_each(i2, cp->perms) { + struct cil_perm *cmp = i2->data; + cil_classperms_to_strings(cmp->classperms, classperms_strs); } - cil_list_append(curr_multimap_item->values, val_flavor, value); } - } else { - cil_log(CIL_INFO, "No data in list item\n"); - return SEPOL_ERR; + } else { /* SET */ + struct cil_classperms_set *cp_set = i1->data; + struct cil_classpermission *cp = cp_set->set; + cil_classperms_to_strings(cp->classperms, classperms_strs); } } +} - new_data = cil_malloc(sizeof(*new_data)); - new_data->key = key; - cil_list_init(&new_data->values, CIL_LIST_ITEM); - if (value != NULL) { - cil_list_append(new_data->values, val_flavor, value); - } - cil_list_append(list, key_flavor, new_data); +static void cil_class_decls_to_policy(FILE *out, struct cil_list *classorder) +{ + struct cil_list_item *i1; - return SEPOL_OK; + cil_list_for_each(i1, classorder) { + fprintf(out, "class %s\n", DATUM(i1->data)->fqn); + } } -int cil_userrole_to_policy(FILE **file_arr, struct cil_list *userroles) +static void cil_sid_decls_to_policy(FILE *out, struct cil_list *sidorder) { - struct cil_list_item *current_user; + struct cil_list_item *i1; - if (userroles == NULL) { - return SEPOL_OK; + cil_list_for_each(i1, sidorder) { + fprintf(out, "sid %s\n", DATUM(i1->data)->fqn); } - - cil_list_for_each(current_user, userroles) { - struct cil_multimap_item *user_multimap_item = current_user->data; - struct cil_list_item *current_role; - if (user_multimap_item->values->head == NULL) { - cil_log(CIL_INFO, "No roles associated with user %s\n", - user_multimap_item->key->name); - return SEPOL_ERR; +} + +static void cil_commons_to_policy(FILE *out, struct cil_list *commons) +{ + struct cil_list_item *i1; + struct cil_class* common; + struct cil_tree_node *node; + struct cil_tree_node *perm; + + cil_list_for_each(i1, commons) { + common = i1->data; + node = NODE(&common->datum); + perm = node->cl_head; + + fprintf(out, "common %s {", common->datum.fqn); + while (perm != NULL) { + fprintf(out, "%s ", DATUM(perm->data)->fqn); + perm = perm->next; } + fprintf(out, "}\n"); + } +} - fprintf(file_arr[USERROLES], "user %s roles {", user_multimap_item->key->name); +static void cil_classes_to_policy(FILE *out, struct cil_list *classorder) +{ + struct cil_list_item *i1; + struct cil_class *class; + struct cil_tree_node *node; - cil_list_for_each(current_role, user_multimap_item->values) { - fprintf(file_arr[USERROLES], " %s", ((struct cil_role*)current_role->data)->datum.name); + cil_list_for_each(i1, classorder) { + class = i1->data; + node = NODE(&class->datum); + + fprintf(out, "class %s", class->datum.fqn); + if (class->common != NULL) { + fprintf(out, " inherits %s", class->common->datum.fqn); + } + if (node->cl_head != NULL) { + struct cil_tree_node *perm = node->cl_head; + fprintf(out, " {"); + while (perm != NULL) { + fprintf(out, " %s", DATUM(perm->data)->fqn); + perm = perm->next; + } + fprintf(out, " }"); } - fprintf(file_arr[USERROLES], " };\n"); + fprintf(out, "\n"); } +} - return SEPOL_OK; +static void cil_defaults_to_policy(FILE *out, struct cil_list *defaults, char *kind) +{ + struct cil_list_item *i1, *i2, *i3; + struct cil_default *def; + struct cil_list *class_list; + + cil_list_for_each(i1, defaults) { + def = i1->data; + fprintf(out, "%s {",kind); + cil_list_for_each(i2, def->class_datums) { + class_list = cil_expand_class(i2->data); + cil_list_for_each(i3, class_list) { + fprintf(out, " %s", DATUM(i3->data)->fqn); + } + cil_list_destroy(&class_list, CIL_FALSE); + } + fprintf(out, " }"); + if (def->object == CIL_DEFAULT_SOURCE) { + fprintf(out," %s",CIL_KEY_SOURCE); + } else if (def->object == CIL_DEFAULT_TARGET) { + fprintf(out," %s",CIL_KEY_TARGET); + } + fprintf(out,";\n"); + } } -int cil_cat_to_policy(FILE **file_arr, struct cil_list *cats) +static void cil_default_ranges_to_policy(FILE *out, struct cil_list *defaults) { - struct cil_list_item *curr_cat; + struct cil_list_item *i1, *i2, *i3; + struct cil_defaultrange *def; + struct cil_list *class_list; + + cil_list_for_each(i1, defaults) { + def = i1->data; + fprintf(out, "default_range {"); + cil_list_for_each(i2, def->class_datums) { + class_list = cil_expand_class(i2->data); + cil_list_for_each(i3, class_list) { + fprintf(out, " %s", DATUM(i3->data)->fqn); + } + cil_list_destroy(&class_list, CIL_FALSE); + } + fprintf(out, " }"); - if (cats == NULL) { - return SEPOL_OK; + switch (def->object_range) { + case CIL_DEFAULT_SOURCE_LOW: + fprintf(out," %s %s", CIL_KEY_SOURCE, CIL_KEY_LOW); + break; + case CIL_DEFAULT_SOURCE_HIGH: + fprintf(out," %s %s", CIL_KEY_SOURCE, CIL_KEY_HIGH); + break; + case CIL_DEFAULT_SOURCE_LOW_HIGH: + fprintf(out," %s %s", CIL_KEY_SOURCE, CIL_KEY_LOW_HIGH); + break; + case CIL_DEFAULT_TARGET_LOW: + fprintf(out," %s %s", CIL_KEY_TARGET, CIL_KEY_LOW); + break; + case CIL_DEFAULT_TARGET_HIGH: + fprintf(out," %s %s", CIL_KEY_TARGET, CIL_KEY_HIGH); + break; + case CIL_DEFAULT_TARGET_LOW_HIGH: + fprintf(out," %s %s", CIL_KEY_TARGET, CIL_KEY_LOW_HIGH); + break; + default: + break; + } + fprintf(out,";\n"); } +} - cil_list_for_each(curr_cat, cats) { - struct cil_multimap_item *cat_multimap_item = curr_cat->data; - fprintf(file_arr[CATS], "category %s", cat_multimap_item->key->name); - if (cat_multimap_item->values->head == NULL) { - fprintf(file_arr[CATS], ";\n"); - } else { - struct cil_list_item *curr_catalias; - fprintf(file_arr[CATS], " alias"); - cil_list_for_each(curr_catalias, cat_multimap_item->values) { - fprintf(file_arr[CATS], " %s", ((struct cil_cat*)curr_catalias->data)->datum.name); +static void cil_sensitivities_to_policy(FILE *out, struct cil_list *sensorder, struct cil_list *all_aliases) +{ + struct cil_list_item *i1, *i2; + struct cil_sens *sens; + struct cil_list *aliases; + struct cil_alias *alias; + struct cil_sens *actual; + int num_aliases; + + cil_list_for_each(i1, sensorder) { + sens = i1->data; + num_aliases = 0; + cil_list_for_each(i2, all_aliases) { + alias = i2->data; + actual = alias->actual; + if (sens == actual) { + if (num_aliases == 0) { + cil_list_init(&aliases, CIL_LIST); + } + cil_list_append(aliases, CIL_SENSALIAS, alias); + num_aliases++; } - fprintf(file_arr[CATS], ";\n"); } + fprintf(out, "sensitivity %s", sens->datum.fqn); + if (num_aliases > 0) { + fprintf(out, " alias"); + if (num_aliases > 1) { + fprintf(out, " {"); + } + cil_list_for_each(i2, aliases) { + alias = i2->data; + fprintf(out, " %s", alias->datum.fqn); + } + if (num_aliases > 1) { + fprintf(out, " }"); + } + cil_list_destroy(&aliases, CIL_FALSE); + } + fprintf(out, ";\n"); } - - return SEPOL_OK; } -int cil_sens_to_policy(FILE **file_arr, struct cil_list *sens) +static void cil_dominance_to_policy(FILE *out, struct cil_list *sensorder) { - struct cil_list_item *curr_sens; + struct cil_list_item *item; + struct cil_sens *sens; - if (sens == NULL) { - return SEPOL_OK; + fprintf(out, "dominance {"); + cil_list_for_each(item, sensorder) { + sens = item->data; + fprintf(out, " %s", sens->datum.fqn); } + fprintf(out, " }\n"); +} - cil_list_for_each(curr_sens, sens) { - struct cil_multimap_item *sens_multimap_item = curr_sens->data; - fprintf(file_arr[SENS], "sensitivity %s", sens_multimap_item->key->name); - if (sens_multimap_item->values->head == NULL) - fprintf(file_arr[SENS], ";\n"); - else { - struct cil_list_item *curr_sensalias; - fprintf(file_arr[SENS], " alias"); - cil_list_for_each(curr_sensalias, sens_multimap_item->values) { - fprintf(file_arr[SENS], " %s", ((struct cil_sens*)curr_sensalias->data)->datum.name); +static void cil_categories_to_policy(FILE *out, struct cil_list *catorder, struct cil_list *all_aliases) +{ + struct cil_list_item *i1, *i2; + struct cil_sens *cat; + struct cil_list *aliases; + struct cil_alias *alias; + struct cil_sens *actual; + int num_aliases; + + cil_list_for_each(i1, catorder) { + cat = i1->data; + num_aliases = 0; + cil_list_for_each(i2, all_aliases) { + alias = i2->data; + actual = alias->actual; + if (cat == actual) { + if (num_aliases == 0) { + cil_list_init(&aliases, CIL_LIST); + } + cil_list_append(aliases, CIL_CATALIAS, alias); + num_aliases++; } - fprintf(file_arr[SENS], ";\n"); } + fprintf(out, "category %s",cat->datum.fqn); + if (num_aliases > 0) { + fprintf(out, " alias"); + if (num_aliases > 1) { + fprintf(out, " { "); + } + cil_list_for_each(i2, aliases) { + alias = i2->data; + fprintf(out, " %s", alias->datum.fqn); + } + if (num_aliases > 1) { + fprintf(out, " }"); + } + cil_list_destroy(&aliases, CIL_FALSE); + } + fprintf(out, ";\n"); } - - return SEPOL_OK; } -void cil_cats_to_policy(FILE **file_arr, uint32_t file_index, struct cil_cats *cats) +static void cil_levels_to_policy(FILE *out, struct cil_list *sensorder) { - cil_expr_to_policy(file_arr, file_index, cats->datum_expr); + struct cil_list_item *i1, *i2; + struct cil_sens *sens; + + cil_list_for_each(i1, sensorder) { + sens = i1->data; + if (sens->cats_list) { + cil_list_for_each(i2, sens->cats_list) { + fprintf(out, "level %s:",sens->datum.fqn); + cil_cats_to_policy(out, i2->data); + fprintf(out,";\n"); + } + } else { + fprintf(out, "level %s;\n",sens->datum.fqn); + } + } } -void cil_level_to_policy(FILE **file_arr, uint32_t file_index, struct cil_level *level) +static void cil_mlsconstrains_to_policy(FILE *out, struct cil_db *db, struct cil_list *mlsconstrains) { - char *sens_str = level->sens->datum.name; - - fprintf(file_arr[file_index], "%s", sens_str); - if (level->cats != NULL) { - fprintf(file_arr[file_index], ":"); - cil_cats_to_policy(file_arr, file_index, level->cats); + struct cil_list_item *i1, *i2; + struct cil_constrain *cons; + struct cil_list *classperms_strs; + char *cp_str; + char *expr_str; + + cil_list_for_each(i1, mlsconstrains) { + cons = i1->data; + cil_list_init(&classperms_strs, CIL_LIST); + cil_classperms_to_strings(cons->classperms, classperms_strs); + expr_str = cil_cons_expr_to_string(db, cons->datum_expr); + cil_list_for_each(i2, classperms_strs) { + cp_str = i2->data; + fprintf(out, "mlsconstrain %s %s;\n", cp_str, expr_str); + free(cp_str); + } + free(expr_str); + cil_list_destroy(&classperms_strs, CIL_FALSE); } } -void cil_levelrange_to_policy(FILE **file_arr, uint32_t file_index, struct cil_levelrange *lvlrange) +static void cil_validatetrans_to_policy(FILE *out, struct cil_db *db, struct cil_list *validatetrans, char *kind) { - struct cil_level *low = lvlrange->low; - struct cil_level *high = lvlrange->high; - - cil_level_to_policy(file_arr, file_index, low); - fprintf(file_arr[file_index], "-"); - cil_level_to_policy(file_arr, file_index, high); + struct cil_list_item *i1, *i2; + struct cil_validatetrans *trans; + struct cil_list *class_list; + struct cil_class *class; + char *expr_str; + + cil_list_for_each(i1, validatetrans) { + trans = i1->data; + class_list = cil_expand_class(trans->class); + expr_str = cil_cons_expr_to_string(db, trans->datum_expr); + cil_list_for_each(i2, class_list) { + class = i2->data; + fprintf(out, "%s %s %s;\n", kind, class->datum.fqn, expr_str); + } + free(expr_str); + cil_list_destroy(&class_list, CIL_FALSE); + } } -void cil_context_to_policy(FILE **file_arr, uint32_t file_index, struct cil_context *context) +static void cil_bools_to_policy(FILE *out, struct cil_list *bools) { - char *user_str = ((struct cil_symtab_datum*)context->user)->name; - char *role_str = ((struct cil_symtab_datum*)context->role)->name; - char *type_str = ((struct cil_symtab_datum*)context->type)->name; - struct cil_levelrange *lvlrange = context->range; + struct cil_list_item *i1; + struct cil_bool *bool; + char *value; - fprintf(file_arr[file_index], "%s:%s:%s:", user_str, role_str, type_str); - cil_levelrange_to_policy(file_arr, file_index, lvlrange); + cil_list_for_each(i1, bools) { + bool = i1->data; + value = bool->value ? "true" : "false"; + fprintf(out, "bool %s %s;\n", bool->datum.fqn, value); + } } -void cil_perms_to_policy(FILE **file_arr, uint32_t file_index, struct cil_list *list) +static void cil_typealiases_to_policy(FILE *out, struct cil_list *types, struct cil_list *all_aliases) { - struct cil_list_item *curr; - - fprintf(file_arr[file_index], " {"); - cil_list_for_each(curr, list) { - switch (curr->flavor) { - case CIL_LIST: - cil_perms_to_policy(file_arr, file_index, curr->data); - break; - case CIL_STRING: - fprintf(file_arr[file_index], " %s", (char *)curr->data); - break; - case CIL_DATUM: - fprintf(file_arr[file_index], " %s", ((struct cil_symtab_datum *)curr->data)->name); - break; - case CIL_OP: { - enum cil_flavor op_flavor = *((enum cil_flavor *)curr->data); - char *op_str = NULL; - - switch (op_flavor) { - case CIL_AND: - op_str = CIL_KEY_AND; - break; - case CIL_OR: - op_str = CIL_KEY_OR; - break; - case CIL_NOT: - op_str = CIL_KEY_NOT; - break; - case CIL_ALL: - op_str = CIL_KEY_ALL; - break; - case CIL_XOR: - op_str = CIL_KEY_XOR; - break; - default: - cil_log(CIL_ERR, "Unknown operator in expression\n"); - break; + struct cil_list_item *i1, *i2; + struct cil_type *type; + struct cil_list *aliases; + struct cil_alias *alias; + struct cil_type *actual; + int num_aliases; + + cil_list_for_each(i1, types) { + type = i1->data; + num_aliases = 0; + cil_list_for_each(i2, all_aliases) { + alias = i2->data; + actual = alias->actual; + if (type == actual) { + if (num_aliases == 0) { + cil_list_init(&aliases, CIL_LIST); + } + cil_list_append(aliases, CIL_TYPEALIAS, alias); + num_aliases++; } - fprintf(file_arr[file_index], " %s", op_str); - break; } - default: - cil_log(CIL_ERR, "Unknown flavor in expression\n"); - break; + if (num_aliases > 0) { + fprintf(out, "typealias %s alias", type->datum.fqn); + if (num_aliases > 1) { + fprintf(out, " {"); + } + cil_list_for_each(i2, aliases) { + alias = i2->data; + fprintf(out, " %s", alias->datum.fqn); + } + if (num_aliases > 1) { + fprintf(out, " }"); + } + fprintf(out, ";\n"); + cil_list_destroy(&aliases, CIL_FALSE); } } - fprintf(file_arr[file_index], " }"); } -void cil_constrain_to_policy_helper(FILE **file_arr, char *kind, struct cil_list *classperms, struct cil_list *expr) +static void cil_typebounds_to_policy(FILE *out, struct cil_list *types) { - struct cil_list_item *curr; + struct cil_list_item *i1; + struct cil_type *child; + struct cil_type *parent; + + cil_list_for_each(i1, types) { + child = i1->data; + if (child->bounds != NULL) { + parent = child->bounds; + fprintf(out, "typebounds %s %s\n", parent->datum.fqn, child->datum.fqn); + } + } +} - cil_list_for_each(curr, classperms) { - if (curr->flavor == CIL_CLASSPERMS) { - struct cil_classperms *cp = curr->data; - if (FLAVOR(cp->class) == CIL_CLASS) { - fprintf(file_arr[CONSTRAINS], "%s %s", kind, cp->class->datum.name); - cil_perms_to_policy(file_arr, CONSTRAINS, cp->perms); - fprintf(file_arr[CONSTRAINS], "\n\t"); - cil_expr_to_policy(file_arr, CONSTRAINS, expr); - fprintf(file_arr[CONSTRAINS], ";\n"); - } else { /* MAP */ - struct cil_list_item *i = NULL; - cil_list_for_each(i, cp->perms) { - struct cil_perm *cmp = i->data; - cil_constrain_to_policy_helper(file_arr, kind, cmp->classperms, expr); +static void cil_typeattributes_to_policy(FILE *out, struct cil_list *types, struct cil_list *attributes) +{ + struct cil_list_item *i1, *i2; + struct cil_type *type; + struct cil_typeattribute *attribute; + int first = CIL_TRUE; + + cil_list_for_each(i1, types) { + type = i1->data; + cil_list_for_each(i2, attributes) { + attribute = i2->data; + if (!attribute->used) + continue; + if (ebitmap_get_bit(attribute->types, type->value)) { + if (first) { + fprintf(out, "typeattribute %s %s", type->datum.fqn, attribute->datum.fqn); + first = CIL_FALSE; + } else { + fprintf(out, ", %s", attribute->datum.fqn); } - } - } else { /* SET */ - struct cil_classperms_set *cp_set = curr->data; - struct cil_classpermission *cp = cp_set->set; - cil_constrain_to_policy_helper(file_arr, kind, cp->classperms, expr); + } + } + if (!first) { + fprintf(out, ";\n"); + first = CIL_TRUE; } } } -void cil_constrain_to_policy(FILE **file_arr, __attribute__((unused)) uint32_t file_index, struct cil_constrain *cons, enum cil_flavor flavor) +static void cil_xperms_to_policy(FILE *out, struct cil_permissionx *permx) { - char *kind = NULL; + ebitmap_node_t *node; + unsigned int i, first, last; + int need_first = CIL_TRUE, need_last = CIL_TRUE; + char *kind; - if (flavor == CIL_CONSTRAIN) { - kind = CIL_KEY_CONSTRAIN; - } else if (flavor == CIL_MLSCONSTRAIN) { - kind = CIL_KEY_MLSCONSTRAIN; + if (permx->kind == CIL_PERMX_KIND_IOCTL) { + kind = "ioctl"; + } else { + kind = "???"; } - cil_constrain_to_policy_helper(file_arr, kind, cons->classperms, cons->datum_expr); -} + fprintf(out, "%s %s {", DATUM(permx->obj)->fqn, kind); -void cil_avrule_to_policy_helper(FILE **file_arr, uint32_t file_index, const char *kind, const char *src, const char *tgt, struct cil_list *classperms) -{ - struct cil_list_item *i; - - cil_list_for_each(i, classperms) { - if (i->flavor == CIL_CLASSPERMS) { - struct cil_classperms *cp = i->data; - if (FLAVOR(cp->class) == CIL_CLASS) { - fprintf(file_arr[file_index], "%s %s %s: %s", kind, src, tgt, cp->class->datum.name); - cil_perms_to_policy(file_arr, file_index, cp->perms); - fprintf(file_arr[file_index], ";\n"); - } else { /* MAP */ - struct cil_list_item *j = NULL; - cil_list_for_each(j, cp->perms) { - struct cil_perm *cmp = j->data; - cil_avrule_to_policy_helper(file_arr, file_index, kind, src, tgt, cmp->classperms); - } + ebitmap_for_each_bit(permx->perms, node, i) { + if (!ebitmap_get_bit(permx->perms, i)) + continue; + if (need_first == CIL_TRUE) { + first = i; + need_first = CIL_FALSE; + } else if (need_last == CIL_TRUE) { + if (i == first+1) { + last = i; + need_last = CIL_FALSE; + } else { + fprintf(out, " 0x%hx", first); + first = i; } - } else { /* SET */ - struct cil_list_item *j; - struct cil_classperms_set *cp_set = i->data; - struct cil_classpermission *cp = cp_set->set; - cil_list_for_each(j, cp->classperms) { - cil_avrule_to_policy_helper(file_arr, file_index, kind, src, tgt, j->data); + } else if (i == last+1) { + last = i; + } else { + if (last > first+1) { + fprintf(out, " 0x%hx-0x%hx", first, last); + } else { + fprintf(out, " 0x%hx 0x%hx", first, last); } + first = i; + need_last = CIL_TRUE; } } + if (need_first == CIL_FALSE) { + if (need_last == CIL_FALSE) { + fprintf(out, " 0x%hx-0x%hx", first, last); + } else { + fprintf(out, " 0x%hx", first); + } + } + fprintf(out," }"); +} + +static void cil_av_rulex_to_policy(FILE *out, struct cil_avrule *rule) +{ + char *kind; + struct cil_symtab_datum *src, *tgt; + + src = rule->src; + tgt = rule->tgt; + + switch (rule->rule_kind) { + case CIL_AVRULE_ALLOWED: + kind = "allowxperm"; + break; + case CIL_AVRULE_AUDITALLOW: + kind = "auditallowxperm"; + break; + case CIL_AVRULE_DONTAUDIT: + kind = "dontauditxperm"; + break; + case CIL_AVRULE_NEVERALLOW: + kind = "neverallowxperm"; + break; + default: + kind = "???"; + break; + } + + fprintf(out, "%s %s %s : ", kind, src->fqn, tgt->fqn); + cil_xperms_to_policy(out, rule->perms.x.permx); + fprintf(out, ";\n"); } -int cil_avrule_to_policy(FILE **file_arr, uint32_t file_index, struct cil_avrule *rule) +static void cil_av_rule_to_policy(FILE *out, struct cil_avrule *rule) { - const char *kind_str = NULL; - const char *src_str = DATUM(rule->src)->name; - const char *tgt_str = DATUM(rule->tgt)->name; + char *kind; + struct cil_symtab_datum *src, *tgt; + struct cil_list *classperms_strs; + struct cil_list_item *i1; + src = rule->src; + tgt = rule->tgt; switch (rule->rule_kind) { case CIL_AVRULE_ALLOWED: - kind_str = "allow"; + kind = "allow"; break; case CIL_AVRULE_AUDITALLOW: - kind_str = "auditallow"; + kind = "auditallow"; break; case CIL_AVRULE_DONTAUDIT: - kind_str = "dontaudit"; + kind = "dontaudit"; break; case CIL_AVRULE_NEVERALLOW: - kind_str = "neverallow"; + kind = "neverallow"; + break; + default: + kind = "???"; break; - default : - cil_log(CIL_INFO, "Unknown avrule with kind=%d src=%s tgt=%s\n", - rule->rule_kind, src_str, tgt_str); - return SEPOL_ERR; } - cil_avrule_to_policy_helper(file_arr, file_index, kind_str, src_str, tgt_str, rule->perms.classperms); - - return SEPOL_OK; + cil_list_init(&classperms_strs, CIL_LIST); + cil_classperms_to_strings(rule->perms.classperms, classperms_strs); + cil_list_for_each(i1, classperms_strs) { + char *cp_str = i1->data; + fprintf(out, "%s %s %s : %s;\n", kind, src->fqn, tgt->fqn, cp_str); + free(cp_str); + } + cil_list_destroy(&classperms_strs, CIL_FALSE); } -int cil_typerule_to_policy(FILE **file_arr, __attribute__((unused)) uint32_t file_index, struct cil_type_rule *rule) +static void cil_type_rule_to_policy(FILE *out, struct cil_type_rule *rule) { - char *src_str = ((struct cil_symtab_datum*)rule->src)->name; - char *tgt_str = ((struct cil_symtab_datum*)rule->tgt)->name; - char *obj_str = ((struct cil_symtab_datum*)rule->obj)->name; - char *result_str = ((struct cil_symtab_datum*)rule->result)->name; - + char *kind; + struct cil_symtab_datum *src, *tgt, *res; + struct cil_list *class_list; + struct cil_list_item *i1; + + src = rule->src; + tgt = rule->tgt; + res = rule->result; + switch (rule->rule_kind) { case CIL_TYPE_TRANSITION: - fprintf(file_arr[ALLOWS], "type_transition %s %s : %s %s;\n", src_str, tgt_str, obj_str, result_str); - break; - case CIL_TYPE_CHANGE: - fprintf(file_arr[ALLOWS], "type_change %s %s : %s %s\n;", src_str, tgt_str, obj_str, result_str); + kind = "type_transition"; break; case CIL_TYPE_MEMBER: - fprintf(file_arr[ALLOWS], "type_member %s %s : %s %s;\n", src_str, tgt_str, obj_str, result_str); + kind = "type_member"; + break; + case CIL_TYPE_CHANGE: + kind = "type_change"; break; default: - cil_log(CIL_INFO, "Unknown type_rule\n"); - return SEPOL_ERR; + kind = "???"; + break; } - return SEPOL_OK; + class_list = cil_expand_class(rule->obj); + cil_list_for_each(i1, class_list) { + fprintf(out, "%s %s %s : %s %s;\n", kind, src->fqn, tgt->fqn, DATUM(i1->data)->fqn, res->fqn); + } + cil_list_destroy(&class_list, CIL_FALSE); } -int cil_nametypetransition_to_policy(FILE **file_arr, uint32_t file_index, struct cil_nametypetransition *nametypetrans) +static void cil_nametypetransition_to_policy(FILE *out, struct cil_nametypetransition *trans) { - char *src_str = ((struct cil_symtab_datum*)nametypetrans->src)->name; - char *tgt_str = ((struct cil_symtab_datum*)nametypetrans->tgt)->name; - char *obj_str = ((struct cil_symtab_datum*)nametypetrans->obj)->name; - char *result_str = ((struct cil_symtab_datum*)nametypetrans->result)->name; + struct cil_symtab_datum *src, *tgt, *res; + struct cil_name *name; + struct cil_list *class_list; + struct cil_list_item *i1; - fprintf(file_arr[file_index], "type_transition %s %s : %s %s %s;\n", src_str, tgt_str, obj_str, result_str, nametypetrans->name_str); - return SEPOL_OK; + src = trans->src; + tgt = trans->tgt; + name = trans->name; + res = trans->result; + + class_list = cil_expand_class(trans->obj); + cil_list_for_each(i1, class_list) { + fprintf(out, "type_transition %s %s : %s %s \"%s\";\n", src->fqn, tgt->fqn, DATUM(i1->data)->fqn, res->fqn, name->datum.fqn); + } + cil_list_destroy(&class_list, CIL_FALSE); +} + +static void cil_rangetransition_to_policy(FILE *out, struct cil_rangetransition *trans) +{ + struct cil_symtab_datum *src, *exec; + struct cil_list *class_list; + struct cil_list_item *i1; + + src = trans->src; + exec = trans->exec; + + class_list = cil_expand_class(trans->obj); + cil_list_for_each(i1, class_list) { + fprintf(out, "range_transition %s %s : %s ", src->fqn, exec->fqn, DATUM(i1->data)->fqn); + cil_levelrange_to_policy(out, trans->range); + fprintf(out, ";\n"); + } + cil_list_destroy(&class_list, CIL_FALSE); +} + +static void cil_typepermissive_to_policy(FILE *out, struct cil_typepermissive *rule) +{ + fprintf(out, "permissive %s;\n", DATUM(rule->type)->fqn); } -static int cil_expr_to_string(struct cil_list *expr, char **out) +struct block_te_rules_extra { + FILE *out; + enum cil_flavor flavor; + uint32_t rule_kind; +}; + +static int __cil_block_te_rules_to_policy_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args) { - int rc = SEPOL_ERR; - struct cil_list_item *curr; - char *stack[COND_EXPR_MAXDEPTH] = {}; - int pos = 0; - int i; + struct block_te_rules_extra *args = extra_args; - cil_list_for_each(curr, expr) { - if (pos > COND_EXPR_MAXDEPTH) { - rc = SEPOL_ERR; - goto exit; + switch (node->flavor) { + case CIL_BLOCK: { + struct cil_block *blk = node->data; + if (blk->is_abstract == CIL_TRUE) { + *finished = CIL_TREE_SKIP_HEAD; } - switch (curr->flavor) { - case CIL_LIST: - rc = cil_expr_to_string(curr->data, &stack[pos]); - if (rc != SEPOL_OK) { - goto exit; - } - pos++; - break; - case CIL_STRING: - stack[pos] = curr->data; - pos++; - break; - case CIL_DATUM: - stack[pos] = ((struct cil_symtab_datum *)curr->data)->name; - pos++; - break; - case CIL_OP: { - int len; - char *expr_str; - enum cil_flavor op_flavor = *((enum cil_flavor *)curr->data); - char *op_str = NULL; - - if (pos == 0) { - rc = SEPOL_ERR; - goto exit; - } - switch (op_flavor) { - case CIL_AND: - op_str = CIL_KEY_AND; - break; - case CIL_OR: - op_str = CIL_KEY_OR; - break; - case CIL_NOT: - op_str = CIL_KEY_NOT; - break; - case CIL_ALL: - op_str = CIL_KEY_ALL; - break; - case CIL_EQ: - op_str = CIL_KEY_EQ; - break; - case CIL_NEQ: - op_str = CIL_KEY_NEQ; - break; - case CIL_XOR: - op_str = CIL_KEY_XOR; - break; - case CIL_CONS_DOM: - op_str = CIL_KEY_CONS_DOM; - break; - case CIL_CONS_DOMBY: - op_str = CIL_KEY_CONS_DOMBY; - break; - case CIL_CONS_INCOMP: - op_str = CIL_KEY_CONS_INCOMP; - break; - default: - cil_log(CIL_ERR, "Unknown operator in expression\n"); - goto exit; - break; - } - if (op_flavor == CIL_NOT) { - len = strlen(stack[pos-1]) + strlen(op_str) + 4; - expr_str = cil_malloc(len); - snprintf(expr_str, len, "(%s %s)", op_str, stack[pos-1]); - free(stack[pos-1]); - stack[pos-1] = NULL; - pos--; - } else { - if (pos < 2) { - rc = SEPOL_ERR; - goto exit; + break; + } + case CIL_MACRO: + *finished = CIL_TREE_SKIP_HEAD; + break; + case CIL_BOOLEANIF: + *finished = CIL_TREE_SKIP_HEAD; + break; + case CIL_AVRULE: + case CIL_AVRULEX: + if (args->flavor == node->flavor) { + struct cil_avrule *rule = node->data; + if (args->rule_kind == rule->rule_kind) { + if (rule->is_extended) { + cil_av_rulex_to_policy(args->out, rule); + } else { + cil_av_rule_to_policy(args->out, rule); } - len = strlen(stack[pos-1]) + strlen(stack[pos-2]) + strlen(op_str) + 5; - expr_str = cil_malloc(len); - snprintf(expr_str, len, "(%s %s %s)", stack[pos-1], op_str, stack[pos-2]); - free(stack[pos-2]); - free(stack[pos-1]); - stack[pos-2] = NULL; - stack[pos-1] = NULL; - pos -= 2; } - stack[pos] = expr_str; - pos++; - break; } - case CIL_CONS_OPERAND: { - enum cil_flavor operand_flavor = *((enum cil_flavor *)curr->data); - char *operand_str = NULL; - switch (operand_flavor) { - case CIL_CONS_U1: - operand_str = CIL_KEY_CONS_U1; - break; - case CIL_CONS_U2: - operand_str = CIL_KEY_CONS_U2; - break; - case CIL_CONS_U3: - operand_str = CIL_KEY_CONS_U3; - break; - case CIL_CONS_T1: - operand_str = CIL_KEY_CONS_T1; - break; - case CIL_CONS_T2: - operand_str = CIL_KEY_CONS_T2; - break; - case CIL_CONS_T3: - operand_str = CIL_KEY_CONS_T3; - break; - case CIL_CONS_R1: - operand_str = CIL_KEY_CONS_R1; - break; - case CIL_CONS_R2: - operand_str = CIL_KEY_CONS_R2; - break; - case CIL_CONS_R3: - operand_str = CIL_KEY_CONS_R3; - break; - case CIL_CONS_L1: - operand_str = CIL_KEY_CONS_L1; - break; - case CIL_CONS_L2: - operand_str = CIL_KEY_CONS_L2; - break; - case CIL_CONS_H1: - operand_str = CIL_KEY_CONS_H1; - break; - case CIL_CONS_H2: - operand_str = CIL_KEY_CONS_H2; - break; - default: - cil_log(CIL_ERR, "Unknown operand in expression\n"); - goto exit; - break; + break; + case CIL_TYPE_RULE: + if (args->flavor == node->flavor) { + struct cil_type_rule *rule = node->data; + if (args->rule_kind == rule->rule_kind) { + cil_type_rule_to_policy(args->out, rule); } - stack[pos] = operand_str; - pos++; - break; } - default: - cil_log(CIL_ERR, "Unknown flavor in expression\n"); - goto exit; - break; + + break; + case CIL_NAMETYPETRANSITION: + if (args->flavor == node->flavor) { + cil_nametypetransition_to_policy(args->out, node->data); + } + break; + case CIL_RANGETRANSITION: + if (args->flavor == node->flavor) { + cil_rangetransition_to_policy(args->out, node->data); } - } - *out = stack[0]; + break; + case CIL_TYPEPERMISSIVE: + if (args->flavor == node->flavor) { + cil_typepermissive_to_policy(args->out, node->data); + } + break; + default: + break; + } return SEPOL_OK; - -exit: - for (i = 0; i < pos; i++) { - free(stack[i]); - } - return rc; } -int cil_expr_to_policy(FILE **file_arr, uint32_t file_index, struct cil_list *expr) +static void cil_block_te_rules_to_policy(FILE *out, struct cil_tree_node *start, int mls) { - int rc = SEPOL_ERR; - char *str_out; - - rc = cil_expr_to_string(expr, &str_out); - if (rc != SEPOL_OK) { - goto out; + struct block_te_rules_extra args; + + args.out = out; + + args.flavor = CIL_TYPEPERMISSIVE; + args.rule_kind = 0; + cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args); + + args.flavor = CIL_AVRULE; + args.rule_kind = CIL_AVRULE_ALLOWED; + cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args); + args.rule_kind = CIL_AVRULE_AUDITALLOW; + cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args); + args.rule_kind = CIL_AVRULE_DONTAUDIT; + cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args); + args.rule_kind = CIL_AVRULE_NEVERALLOW; + cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args); + + args.flavor = CIL_AVRULEX; + args.rule_kind = CIL_AVRULE_ALLOWED; + cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args); + args.rule_kind = CIL_AVRULE_AUDITALLOW; + cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args); + args.rule_kind = CIL_AVRULE_DONTAUDIT; + cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args); + args.rule_kind = CIL_AVRULE_NEVERALLOW; + cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args); + + args.flavor = CIL_TYPE_RULE; + args.rule_kind = CIL_TYPE_TRANSITION; + cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args); + args.rule_kind = CIL_TYPE_MEMBER; + cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args); + args.rule_kind = CIL_TYPE_CHANGE; + cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args); + args.rule_kind = CIL_AVRULE_TYPE; + cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args); + + args.flavor = CIL_NAMETYPETRANSITION; + args.rule_kind = 0; + cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args); + + if (mls == CIL_TRUE) { + args.flavor = CIL_RANGETRANSITION; + args.rule_kind = 0; + cil_tree_walk(start, __cil_block_te_rules_to_policy_helper, NULL, NULL, &args); } - fprintf(file_arr[file_index], "%s", str_out); - free(str_out); - - return SEPOL_OK; - -out: - return rc; } -int __cil_booleanif_node_helper(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, void *extra_args) -{ - int rc = SEPOL_ERR; - struct cil_args_booleanif *args; - FILE **file_arr; - uint32_t *file_index; +struct te_rules_extra { + FILE *out; + int mls; +}; - args = extra_args; - file_arr = args->file_arr; - file_index = args->file_index; +static int __cil_te_rules_to_policy_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args) +{ + struct te_rules_extra *args = extra_args; switch (node->flavor) { - case CIL_AVRULE: - rc = cil_avrule_to_policy(file_arr, *file_index, (struct cil_avrule*)node->data); - if (rc != SEPOL_OK) { - cil_log(CIL_INFO, "cil_avrule_to_policy failed, rc: %d\n", rc); - return rc; - } - break; - case CIL_TYPE_RULE: - rc = cil_typerule_to_policy(file_arr, *file_index, (struct cil_type_rule*)node->data); - if (rc != SEPOL_OK) { - cil_log(CIL_INFO, "cil_typerule_to_policy failed, rc: %d\n", rc); - return rc; + case CIL_BLOCK: { + struct cil_block *blk = node->data; + if (blk->is_abstract == CIL_TRUE) { + *finished = CIL_TREE_SKIP_HEAD; } break; - case CIL_FALSE: - fprintf(file_arr[*file_index], "else {\n"); + } + case CIL_MACRO: + *finished = CIL_TREE_SKIP_HEAD; break; - case CIL_TRUE: + case CIL_BOOLEANIF: { + struct cil_booleanif *bool = node->data; + struct cil_tree_node *n; + struct cil_condblock *cb; + + fprintf(args->out, "if "); + cil_cond_expr_to_policy(args->out, bool->datum_expr, CIL_TRUE); + fprintf(args->out," {\n"); + n = node->cl_head; + cb = n != NULL ? n->data : NULL; + if (cb && cb->flavor == CIL_CONDTRUE) { + cil_block_te_rules_to_policy(args->out, n, args->mls); + n = n->next; + cb = n != NULL ? n->data : NULL; + } + if (cb && cb->flavor == CIL_CONDFALSE) { + fprintf(args->out,"} else {\n"); + cil_block_te_rules_to_policy(args->out, n, args->mls); + } + fprintf(args->out,"}\n"); + *finished = CIL_TREE_SKIP_HEAD; break; + } default: - return SEPOL_ERR; + break; } return SEPOL_OK; } -int __cil_booleanif_last_child_helper(struct cil_tree_node *node, void *extra_args) +static void cil_te_rules_to_policy(FILE *out, struct cil_tree_node *head, int mls) { - struct cil_args_booleanif *args; - FILE **file_arr; - uint32_t *file_index; + struct te_rules_extra args; - args = extra_args; - file_arr = args->file_arr; - file_index = args->file_index; + args.out = out; + args.mls = mls; - if (node->parent->flavor == CIL_FALSE) { - fprintf(file_arr[*file_index], "}\n"); - } - - return SEPOL_OK; + cil_block_te_rules_to_policy(out, head, mls); + cil_tree_walk(head, __cil_te_rules_to_policy_helper, NULL, NULL, &args); } -int cil_booleanif_to_policy(FILE **file_arr, uint32_t file_index, struct cil_tree_node *node) +static void cil_roles_to_policy(FILE *out, struct cil_list *rules) { - int rc = SEPOL_ERR; - struct cil_booleanif *bif = node->data; - struct cil_list *expr = bif->datum_expr; - struct cil_args_booleanif extra_args; - struct cil_tree_node *true_node = NULL; - struct cil_tree_node *false_node = NULL; - struct cil_condblock *cb = NULL; + struct cil_list_item *i1; + struct cil_role *role; - extra_args.file_arr = file_arr; - extra_args.file_index = &file_index;; - - fprintf(file_arr[file_index], "if "); - - rc = cil_expr_to_policy(file_arr, file_index, expr); - if (rc != SEPOL_OK) { - cil_log(CIL_ERR, "Failed to write expression\n"); - return rc; + cil_list_for_each(i1, rules) { + role = i1->data; + if (strcmp(role->datum.fqn,"object_r") == 0) + continue; + fprintf(out, "role %s;\n", role->datum.fqn); } +} - if (node->cl_head != NULL && node->cl_head->flavor == CIL_CONDBLOCK) { - cb = node->cl_head->data; - if (cb->flavor == CIL_CONDTRUE) { - true_node = node->cl_head; - } else if (cb->flavor == CIL_CONDFALSE) { - false_node = node->cl_head; +static void cil_role_types_to_policy(FILE *out, struct cil_list *roles, struct cil_list *types) +{ + struct cil_list_item *i1, *i2; + struct cil_role *role; + struct cil_type *type; + int first = CIL_TRUE; + + cil_list_for_each(i1, roles) { + role = i1->data; + if (strcmp(role->datum.fqn,"object_r") == 0) + continue; + if (role->types) { + cil_list_for_each(i2, types) { + type = i2->data; + if (ebitmap_get_bit(role->types, type->value)) { + if (first) { + fprintf(out, "role %s types { %s", role->datum.fqn, type->datum.fqn); + first = CIL_FALSE; + } else { + fprintf(out, " %s", type->datum.fqn); + } + } + } + if (!first) { + fprintf(out, " }"); + first = CIL_TRUE; + } + fprintf(out, ";\n"); } } +} - if (node->cl_head != NULL && node->cl_head->next != NULL && node->cl_head->next->flavor == CIL_CONDBLOCK) { - cb = node->cl_head->next->data; - if (cb->flavor == CIL_CONDTRUE) { - true_node = node->cl_head->next; - } else if (cb->flavor == CIL_CONDFALSE) { - false_node = node->cl_head->next; +static void cil_roleattributes_to_policy(FILE *out, struct cil_list *roles, struct cil_list *attributes) +{ + struct cil_list_item *i1, *i2; + struct cil_role *role; + struct cil_roleattribute *attribute; + int first = CIL_TRUE; + + cil_list_for_each(i1, roles) { + role = i1->data; + if (strcmp(role->datum.fqn,"object_r") == 0) + continue; + cil_list_for_each(i2, attributes) { + attribute = i2->data; + if (ebitmap_get_bit(attribute->roles, role->value)) { + if (first) { + fprintf(out, "roleattribute %s %s", role->datum.fqn, attribute->datum.fqn); + first = CIL_FALSE; + } else { + fprintf(out, ", %s", attribute->datum.fqn); + } + } } - } - - fprintf(file_arr[file_index], "{\n"); - if (true_node != NULL) { - rc = cil_tree_walk(true_node, __cil_booleanif_node_helper, __cil_booleanif_last_child_helper, NULL, &extra_args); - if (rc != SEPOL_OK) { - cil_log(CIL_INFO, "Failed to write booleanif content to file, rc: %d\n", rc); - return rc; + if (!first) { + fprintf(out, ";\n"); + first = CIL_TRUE; } } - fprintf(file_arr[file_index], "}\n"); +} - if (false_node != NULL) { - fprintf(file_arr[file_index], "else {\n"); - rc = cil_tree_walk(false_node, __cil_booleanif_node_helper, __cil_booleanif_last_child_helper, NULL, &extra_args); - if (rc != SEPOL_OK) { - cil_log(CIL_INFO, "Failed to write booleanif false content to file, rc: %d\n", rc); - return rc; - } - fprintf(file_arr[file_index], "}\n"); - } +static void cil_roleallows_to_policy(FILE *out, struct cil_list *roleallows) +{ + struct cil_list_item *i1; + struct cil_roleallow *allow; - return SEPOL_OK; + cil_list_for_each(i1, roleallows) { + allow = i1->data; + fprintf(out, "allow %s %s;\n", DATUM(allow->src)->fqn, DATUM(allow->tgt)->fqn); + } } -int cil_name_to_policy(FILE **file_arr, struct cil_tree_node *current) +static void cil_roletransitions_to_policy(FILE *out, struct cil_list *roletransitions) { - uint32_t flavor = current->flavor; - int rc = SEPOL_ERR; + struct cil_list_item *i1, *i2; + struct cil_list *class_list; + struct cil_roletransition *trans; - switch(flavor) { - case CIL_TYPEATTRIBUTE: - fprintf(file_arr[TYPEATTRTYPES], "attribute %s;\n", ((struct cil_symtab_datum*)current->data)->name); - break; - case CIL_TYPE: - fprintf(file_arr[TYPEATTRTYPES], "type %s;\n", ((struct cil_symtab_datum*)current->data)->name); - break; - case CIL_TYPEALIAS: { - struct cil_alias *alias = current->data; - fprintf(file_arr[ALIASES], "typealias %s alias %s;\n", ((struct cil_symtab_datum*)alias->actual)->name, ((struct cil_symtab_datum*)current->data)->name); - break; - } - case CIL_TYPEBOUNDS: { - struct cil_bounds *bnds = current->data; - fprintf(file_arr[ALLOWS], "typebounds %s %s;\n", bnds->parent_str, bnds->child_str); - break; - } - case CIL_TYPEPERMISSIVE: { - struct cil_typepermissive *typeperm = (struct cil_typepermissive*)current->data; - fprintf(file_arr[TYPEATTRTYPES], "permissive %s;\n", ((struct cil_symtab_datum*)typeperm->type)->name); - break; - } - case CIL_ROLE: - fprintf(file_arr[TYPEATTRTYPES], "role %s;\n", ((struct cil_symtab_datum*)current->data)->name); - break; - case CIL_BOOL: { - const char *boolean = ((struct cil_bool*)current->data)->value ? "true" : "false"; - fprintf(file_arr[TYPEATTRTYPES], "bool %s %s;\n", ((struct cil_symtab_datum*)current->data)->name, boolean); - break; - } - case CIL_COMMON: - fprintf(file_arr[COMMONS], "common %s", ((struct cil_symtab_datum*)current->data)->name); - if (current->cl_head != NULL) { - current = current->cl_head; - fprintf(file_arr[COMMONS], " {"); - } else { - cil_log(CIL_INFO, "No permissions given\n"); - return SEPOL_ERR; + cil_list_for_each(i1, roletransitions) { + trans = i1->data; + class_list = cil_expand_class(trans->obj); + cil_list_for_each(i2, class_list) { + fprintf(out, "role_transition %s %s : %s %s;\n", DATUM(trans->src)->fqn, DATUM(trans->tgt)->fqn, DATUM(i2->data)->fqn, DATUM(trans->result)->fqn); } + cil_list_destroy(&class_list, CIL_FALSE); + } +} - while (current != NULL) { - if (current->flavor == CIL_PERM) { - fprintf(file_arr[COMMONS], "%s ", ((struct cil_symtab_datum*)current->data)->name); - } else { - cil_log(CIL_INFO, "Improper data type found in common permissions: %d\n", current->flavor); - return SEPOL_ERR; +static void cil_users_to_policy(FILE *out, int mls, struct cil_list *users, struct cil_list *all_roles) +{ + struct cil_list_item *i1, *i2; + struct cil_user *user; + struct cil_list *roles; + struct cil_role *role; + int num_roles; + + cil_list_for_each(i1, users) { + user = i1->data; + num_roles = 0; + fprintf(out, "user %s",user->datum.fqn); + cil_list_for_each(i2, all_roles) { + role = i2->data; + if (ebitmap_get_bit(user->roles, role->value)) { + if (num_roles == 0) { + cil_list_init(&roles, CIL_LIST); + } + cil_list_append(roles, CIL_ROLE, role); + num_roles++; + } + } + if (num_roles > 0) { + fprintf(out, " roles"); + if (num_roles > 1) { + fprintf(out, " {"); + } + cil_list_for_each(i2, roles) { + role = i2->data; + fprintf(out, " %s", role->datum.fqn); } - current = current->next; + if (num_roles > 1) { + fprintf(out, " }"); + } + cil_list_destroy(&roles, CIL_FALSE); } - fprintf(file_arr[COMMONS], "}\n"); - - return SEPOL_DONE; - case CIL_AVRULE: { - struct cil_avrule *avrule = (struct cil_avrule*)current->data; - rc = cil_avrule_to_policy(file_arr, ALLOWS, avrule); - if (rc != SEPOL_OK) { - cil_log(CIL_INFO, "Failed to write avrule to policy\n"); - return rc; + + if (mls == CIL_TRUE && user->dftlevel != NULL) { + fprintf(out, " level "); + cil_level_to_policy(out, user->dftlevel); } - break; - } - case CIL_TYPE_RULE: { - struct cil_type_rule *rule = (struct cil_type_rule*)current->data; - rc = cil_typerule_to_policy(file_arr, ALLOWS, rule); - if (rc != SEPOL_OK) { - cil_log(CIL_INFO, "Failed to write type rule to policy\n"); - return rc; + + if (mls == CIL_TRUE && user->range != NULL) { + fprintf(out, " range "); + cil_levelrange_to_policy(out, user->range); } - break; + + fprintf(out,";\n"); } - case CIL_NAMETYPETRANSITION: { - struct cil_nametypetransition *nametypetrans = (struct cil_nametypetransition*)current->data; - rc = cil_nametypetransition_to_policy(file_arr, ALLOWS, nametypetrans); - if (rc != SEPOL_OK) { - cil_log(CIL_INFO, "Failed to write nametypetransition to policy\n"); - return rc; +} + +static void cil_constrains_to_policy(FILE *out, struct cil_db *db, struct cil_list *constrains) +{ + struct cil_list_item *i1, *i2; + struct cil_constrain *cons; + struct cil_list *classperms_strs; + char *cp_str; + char *expr_str; + + cil_list_for_each(i1, constrains) { + cons = i1->data; + cil_list_init(&classperms_strs, CIL_LIST); + cil_classperms_to_strings(cons->classperms, classperms_strs); + expr_str = cil_cons_expr_to_string(db, cons->datum_expr); + cil_list_for_each(i2, classperms_strs) { + cp_str = i2->data; + fprintf(out, "constrain %s %s;\n",cp_str, expr_str); + free(cp_str); } + free(expr_str); + cil_list_destroy(&classperms_strs, CIL_FALSE); } - case CIL_ROLETRANSITION: { - struct cil_roletransition *roletrans = (struct cil_roletransition*)current->data; - char *src_str = ((struct cil_symtab_datum*)roletrans->src)->name; - char *tgt_str = ((struct cil_symtab_datum*)roletrans->tgt)->name; - char *obj_str = ((struct cil_symtab_datum*)roletrans->obj)->name; - char *result_str = ((struct cil_symtab_datum*)roletrans->result)->name; - - fprintf(file_arr[ALLOWS], "role_transition %s %s:%s %s;\n", src_str, tgt_str, obj_str, result_str); - break; - } - case CIL_ROLEALLOW: { - struct cil_roleallow *roleallow = (struct cil_roleallow*)current->data; - char *src_str = ((struct cil_symtab_datum*)roleallow->src)->name; - char *tgt_str = ((struct cil_symtab_datum*)roleallow->tgt)->name; +} - fprintf(file_arr[ALLOWS], "roleallow %s %s;\n", src_str, tgt_str); - break; - } - case CIL_ROLETYPE: { - struct cil_roletype *roletype = (struct cil_roletype*)current->data; - char *role_str = ((struct cil_symtab_datum*)roletype->role)->name; - char *type_str = ((struct cil_symtab_datum*)roletype->type)->name; +static void cil_sid_contexts_to_policy(FILE *out, struct cil_list *sids, int mls) +{ + struct cil_list_item *i1; + struct cil_sid *sid; - fprintf(file_arr[ALIASES], "role %s types %s\n", role_str, type_str); - break; - } - case CIL_LEVEL: - fprintf(file_arr[LEVELS], "level "); - cil_level_to_policy(file_arr, LEVELS, (struct cil_level*)current->data); - fprintf(file_arr[LEVELS], ";\n"); - break; - case CIL_CONSTRAIN: - cil_constrain_to_policy(file_arr, CONSTRAINS, (struct cil_constrain*)current->data, flavor); - break; - case CIL_MLSCONSTRAIN: - cil_constrain_to_policy(file_arr, CONSTRAINS, (struct cil_constrain*)current->data, flavor); - break; - case CIL_VALIDATETRANS: { - struct cil_validatetrans *vt = current->data; - fprintf(file_arr[CONSTRAINS], "validatetrans"); - fprintf(file_arr[CONSTRAINS], " %s ", ((struct cil_class*)vt->class)->datum.name); - cil_expr_to_policy(file_arr, CONSTRAINS, vt->datum_expr); - fprintf(file_arr[CONSTRAINS], ";\n"); - break; + cil_list_for_each(i1, sids) { + sid = i1->data; + fprintf(out, "sid %s ", sid->datum.fqn); + cil_context_to_policy(out, sid->context, mls); + fprintf(out,"\n"); } - case CIL_MLSVALIDATETRANS: { - struct cil_validatetrans *vt = current->data; - fprintf(file_arr[CONSTRAINS], "mlsvalidatetrans"); - fprintf(file_arr[CONSTRAINS], " %s " , ((struct cil_class*)vt->class)->datum.name); - cil_expr_to_policy(file_arr, CONSTRAINS, vt->datum_expr); - fprintf(file_arr[CONSTRAINS], ";\n"); - break; +} + +static void cil_fsuses_to_policy(FILE *out, struct cil_sort *fsuses, int mls) +{ + unsigned i; + struct cil_fsuse *fsuse; + + for (i=0; icount; i++) { + fsuse = fsuses->array[i]; + if (fsuse->type == CIL_FSUSE_XATTR) { + fprintf(out, "fs_use_xattr %s ", fsuse->fs_str); + cil_context_to_policy(out, fsuse->context, mls); + fprintf(out,";\n"); + } } - case CIL_SID: - fprintf(file_arr[ISIDS], "sid %s\n", ((struct cil_symtab_datum*)current->data)->name); - break; - case CIL_SIDCONTEXT: { - struct cil_sidcontext *sidcon = (struct cil_sidcontext*)current->data; - fprintf(file_arr[SIDS], "sid %s ", sidcon->sid_str); - cil_context_to_policy(file_arr, SIDS, sidcon->context); - fprintf(file_arr[SIDS], "\n"); - break; + + for (i=0; icount; i++) { + fsuse = fsuses->array[i]; + if (fsuse->type == CIL_FSUSE_TASK) { + fprintf(out, "fs_use_task %s ", fsuse->fs_str); + cil_context_to_policy(out, fsuse->context, mls); + fprintf(out,";\n"); + } } - case CIL_POLICYCAP: - fprintf(file_arr[TYPEATTRTYPES], "policycap %s;\n", ((struct cil_symtab_datum*)current->data)->name); - break; - default: - break; + + for (i=0; icount; i++) { + fsuse = fsuses->array[i]; + if (fsuse->type == CIL_FSUSE_TRANS) { + fprintf(out, "fs_use_trans %s ", fsuse->fs_str); + cil_context_to_policy(out, fsuse->context, mls); + fprintf(out,";\n"); + } } +} - return SEPOL_OK; +static void cil_genfscons_to_policy(FILE *out, struct cil_sort *genfscons, int mls) +{ + unsigned i; + struct cil_genfscon *genfscon; + + for (i=0; icount; i++) { + genfscon = genfscons->array[i]; + fprintf(out, "genfscon %s %s ", genfscon->fs_str, genfscon->path_str); + cil_context_to_policy(out, genfscon->context, mls); + fprintf(out, "\n"); + } } -int __cil_gen_policy_node_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args) +static void cil_portcons_to_policy(FILE *out, struct cil_sort *portcons, int mls) { - int rc = SEPOL_ERR; - struct cil_args_genpolicy *args = NULL; - struct cil_list *users = NULL; - struct cil_list *sens = NULL; - struct cil_list *cats = NULL; - FILE **file_arr = NULL; + unsigned i; + struct cil_portcon *portcon; - if (extra_args == NULL) { - return SEPOL_ERR; + for (i=0; icount; i++) { + portcon = portcons->array[i]; + fprintf(out, "portcon "); + if (portcon->proto == CIL_PROTOCOL_UDP) { + fprintf(out, "udp "); + } else if (portcon->proto == CIL_PROTOCOL_TCP) { + fprintf(out, "tcp "); + } else if (portcon->proto == CIL_PROTOCOL_DCCP) { + fprintf(out, "dccp "); + } + if (portcon->port_low == portcon->port_high) { + fprintf(out, "%d ", portcon->port_low); + } else { + fprintf(out, "%d-%d ", portcon->port_low, portcon->port_high); + } + cil_context_to_policy(out, portcon->context, mls); + fprintf(out, "\n"); } +} - *finished = CIL_TREE_SKIP_NOTHING; +static void cil_netifcons_to_policy(FILE *out, struct cil_sort *netifcons, int mls) +{ + unsigned i; + struct cil_netifcon *netifcon; - args = extra_args; - users = args->users; - sens = args->sens; - cats = args->cats; - file_arr = args->file_arr; + for (i=0; icount; i++) { + netifcon = netifcons->array[i]; + fprintf(out, "netifcon %s ", netifcon->interface_str); + cil_context_to_policy(out, netifcon->if_context, mls); + fprintf(out, " "); + cil_context_to_policy(out, netifcon->packet_context, mls); + fprintf(out, ";\n"); + } +} - if (node->cl_head != NULL) { - if (node->flavor == CIL_MACRO) { - *finished = CIL_TREE_SKIP_HEAD; - return SEPOL_OK; - } +static void cil_nodecons_to_policy(FILE *out, struct cil_sort *nodecons, int mls) +{ + unsigned i; + struct cil_nodecon *nodecon; + char *addr, *mask; - if (node->flavor == CIL_BOOLEANIF) { - rc = cil_booleanif_to_policy(file_arr, CONDS, node); - if (rc != SEPOL_OK) { - cil_log(CIL_INFO, "Failed to write booleanif contents to file\n"); - return rc; - } - *finished = CIL_TREE_SKIP_HEAD; - return SEPOL_OK; - } + for (i=0; icount; i++) { + nodecon = nodecons->array[i]; + fprintf(out, "nodecon "); - if (node->flavor == CIL_BLOCK && ((struct cil_block*)node->data)->is_abstract == CIL_TRUE) { - *finished = CIL_TREE_SKIP_HEAD; - return SEPOL_OK; - } + if (nodecon->addr->family == AF_INET) { + errno = 0; + addr = cil_malloc(INET_ADDRSTRLEN); + inet_ntop(nodecon->addr->family, &nodecon->addr->ip.v4, addr, INET_ADDRSTRLEN); + if (errno == 0) { + fprintf(out, "%s ",addr); + } else { + fprintf(out, "[INVALID] "); + } + free(addr); - if (node->flavor != CIL_ROOT) { - rc = cil_name_to_policy(file_arr, node); - if (rc != SEPOL_OK && rc != SEPOL_DONE) { - cil_log(CIL_ERR, "Error converting node to policy %d\n", node->flavor); - return SEPOL_ERR; + errno = 0; + mask = cil_malloc(INET_ADDRSTRLEN); + inet_ntop(nodecon->mask->family, &nodecon->mask->ip.v4, mask, INET_ADDRSTRLEN); + if (errno == 0) { + fprintf(out, "%s ",mask); + } else { + fprintf(out, "[INVALID] "); } - } - } else { - switch (node->flavor) { - case CIL_USER: - cil_multimap_insert(users, node->data, NULL, CIL_USERROLE, CIL_NONE); - break; - case CIL_CATALIAS: { - struct cil_alias *alias = node->data; - struct cil_symtab_datum *datum = alias->actual; - cil_multimap_insert(cats, datum, node->data, CIL_CAT, CIL_CATALIAS); - } - break; - case CIL_SENSALIAS: { - struct cil_alias *alias = node->data; - struct cil_symtab_datum *datum = alias->actual; - cil_multimap_insert(sens, datum, node->data, CIL_SENS, CIL_SENSALIAS); - } - break; - default: - rc = cil_name_to_policy(file_arr, node); - if (rc != SEPOL_OK && rc != SEPOL_DONE) { - cil_log(CIL_ERR, "Error converting node to policy %d\n", rc); - return SEPOL_ERR; + free(mask); + } else { + errno = 0; + addr = cil_malloc(INET6_ADDRSTRLEN); + inet_ntop(nodecon->addr->family, &nodecon->addr->ip.v6, addr, INET6_ADDRSTRLEN); + if (errno == 0) { + fprintf(out, "%s ",addr); + } else { + fprintf(out, "[INVALID] "); } - break; + free(addr); + + errno = 0; + mask = cil_malloc(INET6_ADDRSTRLEN); + inet_ntop(nodecon->mask->family, &nodecon->mask->ip.v6, mask, INET6_ADDRSTRLEN); + if (errno == 0) { + fprintf(out, "%s ",mask); + } else { + fprintf(out, "[INVALID] "); + } + free(mask); } - } - return SEPOL_OK; + cil_context_to_policy(out, nodecon->context, mls); + fprintf(out, ";\n"); + } } -int cil_gen_policy(struct cil_db *db) +static void cil_pirqcons_to_policy(FILE *out, struct cil_sort *pirqcons, int mls) { - struct cil_tree_node *curr = db->ast->root; - struct cil_list_item *item; - int rc = SEPOL_ERR; - FILE *policy_file; - FILE **file_arr = cil_malloc(sizeof(FILE*) * NUM_POLICY_FILES); - char *file_path_arr[NUM_POLICY_FILES]; - char temp[32]; - - struct cil_list *users = NULL; - struct cil_list *cats = NULL; - struct cil_list *sens = NULL; - struct cil_args_genpolicy extra_args; - - cil_list_init(&users, CIL_LIST_ITEM); - cil_list_init(&cats, CIL_LIST_ITEM); - cil_list_init(&sens, CIL_LIST_ITEM); - - strcpy(temp, "/tmp/cil_classdecl-XXXXXX"); - file_arr[CLASS_DECL] = fdopen(mkstemp(temp), "w+"); - file_path_arr[CLASS_DECL] = cil_strpool_add(temp); - - strcpy(temp, "/tmp/cil_isids-XXXXXX"); - file_arr[ISIDS] = fdopen(mkstemp(temp), "w+"); - file_path_arr[ISIDS] = cil_strpool_add(temp); - - strcpy(temp,"/tmp/cil_common-XXXXXX"); - file_arr[COMMONS] = fdopen(mkstemp(temp), "w+"); - file_path_arr[COMMONS] = cil_strpool_add(temp); - - strcpy(temp, "/tmp/cil_class-XXXXXX"); - file_arr[CLASSES] = fdopen(mkstemp(temp), "w+"); - file_path_arr[CLASSES] = cil_strpool_add(temp); - - strcpy(temp, "/tmp/cil_interf-XXXXXX"); - file_arr[INTERFACES] = fdopen(mkstemp(temp), "w+"); - file_path_arr[INTERFACES] = cil_strpool_add(temp); - - strcpy(temp, "/tmp/cil_sens-XXXXXX"); - file_arr[SENS] = fdopen(mkstemp(temp), "w+"); - file_path_arr[SENS] = cil_strpool_add(temp); - - strcpy(temp, "/tmp/cil_cats-XXXXXX"); - file_arr[CATS] = fdopen(mkstemp(temp), "w+"); - file_path_arr[CATS] = cil_strpool_add(temp); - - strcpy(temp, "/tmp/cil_levels-XXXXXX"); - file_arr[LEVELS] = fdopen(mkstemp(temp), "w+"); - file_path_arr[LEVELS] = cil_strpool_add(temp); - - strcpy(temp, "/tmp/cil_mlscon-XXXXXX"); - file_arr[CONSTRAINS] = fdopen(mkstemp(temp), "w+"); - file_path_arr[CONSTRAINS] = cil_strpool_add(temp); - - strcpy(temp, "/tmp/cil_attrtypes-XXXXXX"); - file_arr[TYPEATTRTYPES] = fdopen(mkstemp(temp), "w+"); - file_path_arr[TYPEATTRTYPES] = cil_strpool_add(temp); - - strcpy(temp, "/tmp/cil_aliases-XXXXXX"); - file_arr[ALIASES] = fdopen(mkstemp(temp), "w+"); - file_path_arr[ALIASES] = cil_strpool_add(temp); - - strcpy(temp, "/tmp/cil_allows-XXXXXX"); - file_arr[ALLOWS] = fdopen(mkstemp(temp), "w+"); - file_path_arr[ALLOWS] = cil_strpool_add(temp); - - strcpy(temp, "/tmp/cil_conds-XXXXXX"); - file_arr[CONDS] = fdopen(mkstemp(temp), "w+"); - file_path_arr[CONDS] = cil_strpool_add(temp); - - strcpy(temp, "/tmp/cil_userroles-XXXXXX"); - file_arr[USERROLES] = fdopen(mkstemp(temp), "w+"); - file_path_arr[USERROLES] = cil_strpool_add(temp); - - strcpy(temp, "/tmp/cil_sids-XXXXXX"); - file_arr[SIDS] = fdopen(mkstemp(temp), "w+"); - file_path_arr[SIDS] = cil_strpool_add(temp); - - strcpy(temp, "/tmp/cil_netifcons-XXXXXX"); - file_arr[NETIFCONS] = fdopen(mkstemp(temp), "w+"); - file_path_arr[NETIFCONS] = cil_strpool_add(temp); - - policy_file = fopen("policy.conf", "w+"); - - cil_list_for_each(item, db->sidorder) { - fprintf(file_arr[ISIDS], "sid %s ", ((struct cil_sid*)item->data)->datum.name); - } - - cil_list_for_each(item, db->classorder) { - struct cil_class *class = item->data; - struct cil_tree_node *node = class->datum.nodes->head->data; - - fprintf(file_arr[CLASS_DECL], "class %s\n", class->datum.name); - - fprintf(file_arr[CLASSES], "class %s ", class->datum.name); - if (class->common != NULL) { - fprintf(file_arr[CLASSES], "inherits %s ", class->common->datum.name); - } - if (node->cl_head != NULL) { - struct cil_tree_node *curr_perm = node->cl_head; - fprintf(file_arr[CLASSES], "{ "); - while (curr_perm != NULL) { - fprintf(file_arr[CLASSES], "%s ", ((struct cil_symtab_datum*)curr_perm->data)->name); - curr_perm = curr_perm->next; - } - fprintf(file_arr[CLASSES], "}"); - } - fprintf(file_arr[CLASSES], "\n"); - } + unsigned i; + struct cil_pirqcon *pirqcon; - if (db->catorder->head != NULL) { - cil_list_for_each(item, db->catorder) { - cil_multimap_insert(cats, item->data, NULL, CIL_CAT, 0); - } + for (i = 0; icount; i++) { + pirqcon = pirqcons->array[i]; + fprintf(out, "pirqcon %d ", pirqcon->pirq); + cil_context_to_policy(out, pirqcon->context, mls); + fprintf(out, ";\n"); } +} - if (db->sensitivityorder->head != NULL) { - fprintf(file_arr[SENS], "sensitivityorder { "); - cil_list_for_each(item, db->sensitivityorder) { - fprintf(file_arr[SENS], "%s ", ((struct cil_sens*)item->data)->datum.name); - } - fprintf(file_arr[SENS], "};\n"); +static void cil_iomemcons_to_policy(FILE *out, struct cil_sort *iomemcons, int mls) +{ + unsigned i; + struct cil_iomemcon *iomemcon; + + for (i = 0; icount; i++) { + iomemcon = iomemcons->array[i]; + fprintf(out, "iomemcon %" PRIu64 "-%" PRIu64 " ", iomemcon->iomem_low, iomemcon->iomem_high); + cil_context_to_policy(out, iomemcon->context, mls); + fprintf(out, ";\n"); } +} - extra_args.users = users; - extra_args.sens = sens; - extra_args.cats = cats; - extra_args.file_arr= file_arr; +static void cil_ioportcons_to_policy(FILE *out, struct cil_sort *ioportcons, int mls) +{ + unsigned i; + struct cil_ioportcon *ioportcon; - rc = cil_tree_walk(curr, __cil_gen_policy_node_helper, NULL, NULL, &extra_args); - if (rc != SEPOL_OK) { - cil_log(CIL_ERR, "Error walking tree\n"); - return rc; + for (i = 0; i < ioportcons->count; i++) { + ioportcon = ioportcons->array[i]; + fprintf(out, "ioportcon %d-%d ", ioportcon->ioport_low, ioportcon->ioport_high); + cil_context_to_policy(out, ioportcon->context, mls); + fprintf(out, ";\n"); } +} - rc = cil_netifcon_to_policy(file_arr, db->netifcon); - if (rc != SEPOL_OK) { - cil_log(CIL_ERR, "Error creating policy.conf\n"); - return rc; - } - - rc = cil_genfscon_to_policy(file_arr, db->genfscon); - if (rc != SEPOL_OK) { - cil_log(CIL_ERR, "Error creating policy.conf\n"); - return rc; - } +static void cil_pcidevicecons_to_policy(FILE *out, struct cil_sort *pcidevicecons, int mls) +{ + unsigned i; + struct cil_pcidevicecon *pcidevicecon; - rc = cil_portcon_to_policy(file_arr, db->portcon); - if (rc != SEPOL_OK) { - cil_log(CIL_ERR, "Error creating policy.conf\n"); - return rc; + for (i = 0; i < pcidevicecons->count; i++) { + pcidevicecon = pcidevicecons->array[i]; + fprintf(out, "pcidevicecon %d ", pcidevicecon->dev); + cil_context_to_policy(out, pcidevicecon->context, mls); + fprintf(out, ";\n"); } +} - rc = cil_nodecon_to_policy(file_arr, db->nodecon); - if (rc != SEPOL_OK) { - cil_log(CIL_ERR, "Error creating policy.conf\n"); - return rc; - } +static void cil_devicetreecons_to_policy(FILE *out, struct cil_sort *devicetreecons, int mls) +{ + unsigned i; + struct cil_devicetreecon *devicetreecon; - rc = cil_fsuse_to_policy(file_arr, db->fsuse); - if (rc != SEPOL_OK) { - cil_log(CIL_ERR, "Error creating policy.conf\n"); - return rc; + for (i = 0; i < devicetreecons->count; i++) { + devicetreecon = devicetreecons->array[i]; + fprintf(out, "devicetreecon %s ", devicetreecon->path); + cil_context_to_policy(out, devicetreecon->context, mls); + fprintf(out, ";\n"); } +} - rc = cil_pirqcon_to_policy(file_arr, db->pirqcon); - if (rc != SEPOL_OK) { - cil_log(CIL_ERR, "Error creating policy.conf\n"); - return rc; - } +void cil_gen_policy(FILE *out, struct cil_db *db) +{ + unsigned i; + struct cil_tree_node *head = db->ast->root; + struct cil_list *lists[CIL_LIST_NUM_LISTS]; - rc = cil_iomemcon_to_policy(file_arr, db->iomemcon); - if (rc != SEPOL_OK) { - cil_log(CIL_ERR, "Error creating policy.conf\n"); - return rc; + for (i=0; iioportcon); - if (rc != SEPOL_OK) { - cil_log(CIL_ERR, "Error creating policy.conf\n"); - return rc; - } + cil_gather_statements(head, lists); - rc = cil_pcidevicecon_to_policy(file_arr, db->pcidevicecon); - if (rc != SEPOL_OK) { - cil_log(CIL_ERR, "Error creating policy.conf\n"); - return rc; - } + cil_class_decls_to_policy(out, db->classorder); - rc = cil_userrole_to_policy(file_arr, users); - if (rc != SEPOL_OK) { - cil_log(CIL_ERR, "Error creating policy.conf\n"); - return SEPOL_ERR; - } + cil_sid_decls_to_policy(out, db->sidorder); - rc = cil_sens_to_policy(file_arr, sens); - if (rc != SEPOL_OK) { - cil_log(CIL_ERR, "Error creating policy.conf\n"); - return SEPOL_ERR; - } + cil_commons_to_policy(out, lists[CIL_LIST_COMMON]); + cil_classes_to_policy(out, db->classorder); - rc = cil_cat_to_policy(file_arr, cats); - if (rc != SEPOL_OK) { - cil_log(CIL_ERR, "Error creating policy.conf\n"); - return SEPOL_ERR; - } + cil_defaults_to_policy(out, lists[CIL_LIST_DEFAULT_USER], CIL_KEY_DEFAULTUSER); + cil_defaults_to_policy(out, lists[CIL_LIST_DEFAULT_ROLE], CIL_KEY_DEFAULTROLE); + cil_defaults_to_policy(out, lists[CIL_LIST_DEFAULT_TYPE], CIL_KEY_DEFAULTTYPE); - rc = cil_combine_policy(file_arr, policy_file); - if (rc != SEPOL_OK) { - cil_log(CIL_ERR, "Error creating policy.conf\n"); - return SEPOL_ERR; + if (db->mls == CIL_TRUE) { + cil_default_ranges_to_policy(out, lists[CIL_LIST_DEFAULT_RANGE]); + cil_sensitivities_to_policy(out, db->sensitivityorder, lists[CIL_LIST_SENSALIAS]); + cil_dominance_to_policy(out, db->sensitivityorder); + cil_categories_to_policy(out, db->catorder, lists[CIL_LIST_CATALIAS]); + cil_levels_to_policy(out, db->sensitivityorder); + cil_mlsconstrains_to_policy(out, db, lists[CIL_LIST_MLSCONSTRAIN]); + cil_validatetrans_to_policy(out, db, lists[CIL_LIST_MLSVALIDATETRANS], CIL_KEY_MLSVALIDATETRANS); } - // Remove temp files - int i; - for (i=0; imls); + + cil_roles_to_policy(out, lists[CIL_LIST_ROLE]); + cil_role_types_to_policy(out, lists[CIL_LIST_ROLE], lists[CIL_LIST_TYPE]); + cil_roleattributes_to_policy(out, lists[CIL_LIST_ROLE], lists[CIL_LIST_ROLEATTRIBUTE]); + cil_roleallows_to_policy(out, lists[CIL_LIST_ROLEALLOW]); + cil_roletransitions_to_policy(out, lists[CIL_LIST_ROLETRANSITION]); + + cil_users_to_policy(out, db->mls, lists[CIL_LIST_USER], lists[CIL_LIST_ROLE]); + + cil_constrains_to_policy(out, db, lists[CIL_LIST_CONSTRAINT]); + cil_validatetrans_to_policy(out, db, lists[CIL_LIST_VALIDATETRANS], CIL_KEY_VALIDATETRANS); + + cil_sid_contexts_to_policy(out, db->sidorder, db->mls); + cil_fsuses_to_policy(out, db->fsuse, db->mls); + cil_genfscons_to_policy(out, db->genfscon, db->mls); + cil_portcons_to_policy(out, db->portcon, db->mls); + cil_netifcons_to_policy(out, db->netifcon, db->mls); + cil_nodecons_to_policy(out, db->nodecon, db->mls); + cil_pirqcons_to_policy(out, db->pirqcon, db->mls); + cil_iomemcons_to_policy(out, db->iomemcon, db->mls); + cil_ioportcons_to_policy(out, db->ioportcon, db->mls); + cil_pcidevicecons_to_policy(out, db->pcidevicecon, db->mls); + cil_devicetreecons_to_policy(out, db->devicetreecon, db->mls); + + for (i=0; i