From patchwork Tue Nov 29 14:50:56 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Carter X-Patchwork-Id: 9452309 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 5682B6071C for ; Tue, 29 Nov 2016 15:00:11 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3D83428384 for ; Tue, 29 Nov 2016 15:00:11 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 2EE7728389; Tue, 29 Nov 2016 15:00:11 +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]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 250FA2837F for ; Tue, 29 Nov 2016 15:00:05 +0000 (UTC) X-IronPort-AV: E=Sophos;i="5.31,717,1473120000"; d="scan'208";a="1118690" IronPort-PHdr: =?us-ascii?q?9a23=3AYPH5bhOr1q5FdkywO1ol6mtUPXoX/o7sNwtQ0KIM?= =?us-ascii?q?zox0LP//r8bcNUDSrc9gkEXOFd2CrakV0KyN7Ou5CDdIyK3CmUhKSIZLWR4BhJ?= =?us-ascii?q?detC0bK+nBN3fGKuX3ZTcxBsVIWQwt1Xi6NU9IBJS2PAWK8TW94jEIBxrwKxd+?= =?us-ascii?q?KPjrFY7OlcS30P2594HObwlSijewZb1/IA+4oAjTucUanI9vJ6gswRbVv3VEfP?= =?us-ascii?q?hby3l1LlyJhRb84cmw/J9n8ytOvv8q6tBNX6bncakmVLJUFDspPXw7683trhnD?= =?us-ascii?q?UBCA5mAAXWUMkxpHGBbK4RfnVZrsqCT6t+592C6HPc3qSL0/RDqv47t3RBLulS?= =?us-ascii?q?wLMTk3/3/Khcxrla5UvhShrAF7z4LKYIyZKP9yc6XAdt0YWGVBRN5cWSxfDI2h?= =?us-ascii?q?YYUBDO0PMuRWr4nlpVYCsBWzCgawC+3g1DBInWT73bE43uk7DQ3LxhAsE8wIvX?= =?us-ascii?q?/JrNv1LqASUeWtwafM1zrDau1Z2Szg44XWaB8hu+2MUqxqccHMzkQvFQ3EgUmK?= =?us-ascii?q?poz/IzOZyP8As3Sb7uV8VeKvjHQrqwdqoje13MsshY7JhpwMx13C6C53zoE1Jd?= =?us-ascii?q?iiR056Z96pCJ5QuDuCN4dsQ8MiRWdlszs5xL0eoZO3YScHxZs9yxPfdvCLaZaE?= =?us-ascii?q?7x39WOqLPDt1gm9udqiliBao60egz/XxVsyz0FlXsCVIisLMtnUR1xzL7ciHV+?= =?us-ascii?q?d98l+h2TmR0wDT7flJIVwumqrBKp4h36UwmoAPsUXDAiD2mEL2gLWQdko44ein?= =?us-ascii?q?9/7rYrDnpp+YL4N0iwf+PboymsGnHOg1PQcDU3Kb9OihzrHv40L0TKtQgvEriq?= =?us-ascii?q?XZtYrVJcUfpq63GQ9V1YMj5g6kDzi41NQYnH8HLE9KeR6elIfpPEzOIPbkAvih?= =?us-ascii?q?mFShiytrxvDaMb3hBZXBNH7DkKz7crpn5E5czxQzwchF551IErEBPO7zWkjpud?= =?us-ascii?q?PGFh82KRa0w+f8CNhmzoMRQ3iPAq6CMKPKtV+H/P4gLPeWaI8Sojb9JOAv5+Ty?= =?us-ascii?q?gn8hhV8dYa6p0IMZaHCiBPtmJVmWYXv3gtoaFGcKpgs+QPXxiFyMSj5ffXGyX7?= =?us-ascii?q?gz5jsjEoKpEZ/DRpyxgLyGxCq7HYdZZmNBClCRCnrodJ+LW/QLaCKPOMNhlSYE?= =?us-ascii?q?Vbe5QY87yR6urBP6y6ZgLufM4CIXqIjj1Nlr6O3Jjhw97yB7D8GH32GKVWF0kX?= =?us-ascii?q?sCRyUq06BnvUx91lCD3LB4g/NGEdxT4/RJXxw+NZ7B0+x6DNXyVRjbcteOUlam?= =?us-ascii?q?Tc2sASstQdIp398Of0F9Fs25jhDNxSqqBKQVl6CQCZwv9KLc2HbwJ8NnxHbAzq?= =?us-ascii?q?UhiUcpQtdXP228mqF/7xTTB5LOk0iBmaelb6Ac3DLT+2eZ1mqDp19YXxBqUare?= =?us-ascii?q?QHAfY1HardPj5kPNV7WuE6goMhNdyc6eLatHcsHpgkhbS/fiItveZ3m8lHu3BR?= =?us-ascii?q?aN2ryDdpHqe3kH0CXbFkcEjxgZ/WyaOggmGiehv2XeASRoFVLuZ0Ps9fdxqGig?= =?us-ascii?q?Q0Au0Q6KdUph26Cy+h4PivyWU+kT0a4cuCc9tzV0G06w0M/MBNqcvQVuYqtcYN?= =?us-ascii?q?wm7Vhb1WLWrRZ9PoC+IKB4nFIedRp4v1/23RVtFopAidQqrG8tzAdqN6KY0U9O?= =?us-ascii?q?dy+f3ZDqILHYNmny/Bepa67ZwVze1NeW+qEV5/QirFXvpgapFlAt839/ydlaz2?= =?us-ascii?q?Oc5onWDAoVSZ/xVkc39wNmp73DeSky+YfU1XxqMampvT7PwMkpBPMkyhamftdQ?= =?us-ascii?q?LLiEGBX0E8IEG8ikMPYqlESxbhIYIOBS87Y5P9mhd/uC3K6kIvxgky6hjWVJ+4?= =?us-ascii?q?19yV+M+DZnSuLS2JYF2f6Y1BOdVzjglFehrtz3mYdcaDEKBGW/1CzkCJRLaaFo?= =?us-ascii?q?ZokLDmOuI9GwxtV4nJPtXmJU9FikB1wawsOpfwSdb0Dl1w1KyUsXuWCnmTe/zz?= =?us-ascii?q?FsljEpqrOT0zLIw+n5ahoIJGpLRG18glf2O4S0ic4VXFSwZQgziBSl/Vr6x7Rc?= =?us-ascii?q?pKlnLGncX0FIfzPtImFhTKSwsKGCY8hR55M0qylXV/68YV+CQL7nvxQayz/jH3?= =?us-ascii?q?dZxD0jaTGqvIj2kgdkiGKbMXlzrGDVecduyhfD/NbcX+Je3iIaRClkjjnaHkC8?= =?us-ascii?q?MMO0/dWQjJrMruG+V36hV5FKfynk14WAuDG85W1wDh21h+qzlcH/EQgmzS/70M?= =?us-ascii?q?FnVT3SoxbhZonkyby6Pvhhfkl0GlD88dF3GpxlkoQunpEQwmIWho6S/Xoai2f8?= =?us-ascii?q?LctU2az5bHoXSj4E3cTZ4A77101/NniJ3Z72Vm2Bwst9YNm3em0W1Tg778BWD6?= =?us-ascii?q?eU6adJnSVrrVWlqgLRe+Jyni8Hyfsp6n4Vnf0GuBY3wiWaGLASElFSPTbwmBSQ?= =?us-ascii?q?89C+sKJXaX6gcbiwyEV+h9CgDKmeogFbQ3v5fIktHTNr7spjKl3MyGP85pvieN?= =?us-ascii?q?bOcdIZrgeUnAvYj+hJNJIxkeIHhS99NmL5uX0q1fI7jQB00p6gp4WHLXti/L6i?= =?us-ascii?q?AhFELDL1f90c9ivrjalAgsacx5qvEYl5GjUXQJvoSuqlECgIufXpLQqOFSczqn?= =?us-ascii?q?OcGbvfBgKQ8ltpr3fVH5CsLXGXK2ETzc9+SxmFOExfnAcUUS08np4jDA+q3NTh?= =?us-ascii?q?fVx35jAQ/F74sQdMyuxpNxn5SGjfohunajYuR5ibNhZW6RtC50jNO8yE8u1zBz?= =?us-ascii?q?1Y/oGmrAGVMmyUeR9HAn8PWkyFG1DjOaKj5dje/OeGGOWyNfzOYa+BqeZGTfeH?= =?us-ascii?q?2Yqv0pd6/zaLLsiAJWJtA/o/2kpCRnB5B9/Zly8USyMJiy3BddWbqwm4+i12qM?= =?us-ascii?q?C/7fvqVRnz6oqPEbtSLM5v9wq4gKiZK+6QnyF5KTBC2pML33/Ix6AV3EQOhCF2?= =?us-ascii?q?azmtDbMAuDbWTK3KhK9YFREbZD1oNMZT9KIzxBdNNtTUitzrzb50lPg1BElZVV?= =?us-ascii?q?b5gMGmedQKI32hNFPAHEuEL7WGJTLMw8Hxeq6zVKNfg/5VtxKqvzaXCUjjPi6M?= =?us-ascii?q?lzPxTRCgLflMjD2HPBxZoIyyaBltBnL9TN34cRC7N8d3giMwwb0xnHzKNGocPi?= =?us-ascii?q?N7c0JCtLGQ6jlYgvpnEWxb8nVlNfWEmzqe7+TANpYWtv5rDj5ul+Jd4XU11b1V?= =?us-ascii?q?4zpeRPxyhiTSrcVjrE2hkumK1jVoSgFOqipRiIKNo0piJb3T9oNcVnbc4BIN8W?= =?us-ascii?q?KQBgwJp9plDt3gpbtdyt3IlKL9JjdN7c7U/dccB8jTLcKILmAtMRz3Fz7IFAEF?= =?us-ascii?q?VyKkNXnDh0xBl/Gf7nyVrp4mqpfynJoBVLpbW0IpFvMACkVoB9sCII9pUTMilL?= =?us-ascii?q?6Uls8I5X6loxnWS8RWpJfHVuidAf/3MjaWkaFEZwcUwbP/NYkTMJP01FZmalRh?= =?us-ascii?q?n4TKHFHQXcxXrS1ndQ80o0RN/GJ4TmItx0Lvchmt72MLFf6ogh42jRNzYf4z+z?= =?us-ascii?q?f3/Vg4PEDKqzcwkEQqgtrlgCqRfyP2LKe+RYFWETT7tkgrPpP9XQl1cRW4nVZ4?= =?us-ascii?q?OzfcW7JRk7xgeHh2hw/bv5tPH+NTQrNAYB8R3vyYfesn0U5bqim9wk9H/+TFA4?= =?us-ascii?q?N4lAQ2aZ6ss25A2wV7YdEoP6PQOqtJwUVLhq+VpCCozPoxwAgQJkYW7mydZDMI?= =?us-ascii?q?uFYJNrk6Jyuk5Ops5hKemzFbYmgDS+Iqou529kM6I+mP0jng3KBZJUC+LeyQNb?= =?us-ascii?q?2ZtnPblcGSQVMwy1kImFNf8bhyzMcjdVCbV1o2wLuNEBQJNsrDKQZPY8pU6nfT?= =?us-ascii?q?YT6Esf/RzpJtI4W9CufoQPeAtKYOnE2rAR0pEJ4K7sQdGZmsy1rVIt37I74A0x?= =?us-ascii?q?kt4x7rJFqdBvRTZB2LiCsHo924zJJv2YldISsdDnt7MSS24bbavQAqgPyeXNss?= =?us-ascii?q?ZXcaRIQEPGosWMKmgy5Zo2hADD6v3+IC1geC6z78piLNDDjzdNdsePCUZRZwB9?= =?us-ascii?q?6s4jU/77K6iVjJ/ZXCP2v6L8htusfT6eMGoJaKE/BUTaN9skjGnYlYW3yqXnXA?= =?us-ascii?q?Ed6yP5j/d5MgbdrqBXamSla/kS46T9/tPNaxKaiFmR3oRYdRsImcwDAjNc+8Gy?= =?us-ascii?q?oDFBdxp+AM/rlzaRcFY5UlfR7irx4+OLCnIAeEztWuRH6gKTtRT/ZBw+W1eaZX?= =?us-ascii?q?wjEtbuCk1nQvUIs2z+6t8U4CXJsKlA3Rxe6/Z4lCVij+AmZSewHOpSUliWduLu?= =?us-ascii?q?Myw+c5wBPPt1kTKSuGe/doaGNeudEwHF2SIWhsBmo+WVCckZLJ4hSw0LAK4ytd?= =?us-ascii?q?g9FU3PVev3fguJ/SeyijV7G1qZrLqSogdsIpo7dxMID5JcuGrpzelCTFTJbMqg?= =?us-ascii?q?2FTDK6F/1Cl9hfPSJYQf1ImWU7NswDoodO9FQ+Wdw/J7NVDqkgvLeqaSBrDSQK?= =?us-ascii?q?1y8WS5uA3CAegue7w7bajBGQcJU+PxwEt5VChsAdXTZvbC0DvqGuS4LYmnSYRW?= =?us-ascii?q?gMJQcc8R5D5BkcloNqeODq/pbIRodWyzFKu/J0TjfLFp5w+lvhV26ZnEP1SPqk?= =?us-ascii?q?k+2mxw5Syuzj0sUDUh5lFUdd3/pWllcvKLxvN6YQvJTFvSOTeEzmu2LtzO+mJF?= =?us-ascii?q?hPxs3Oa133EpbKtWrmXi0b430USpdFyGvDGpQKjwp5dKErqU1WII+8YEb+4Ccr?= =?us-ascii?q?yp91H7miT8+r2UgqrXIHRyesHNpBD+BmsF3XWD15bZCkso/lO5BITm9W5pKdt0?= =?us-ascii?q?9TkF9xPC6h1ZpcN8ZN7yYMXTdVujWSpt6ySMxF2cJtDp8MPs1wu2zhF6xeIpSR?= =?us-ascii?q?pWM5uqD3wH/D5z88qEu6xCm0G6KgQeNV5XERGgUoJ2Sbq0kgFegs/3zT8l/TrF?= =?us-ascii?q?974f1XBr+VjUV+uDx9BIxBBi5V1XC5KFR+VGNJs/9HKKTTacBcQOI/ZR6uOxw/?= =?us-ascii?q?Cf4pxFaF/UdqknfleyZyrBdV+zjBXwkoUikYmrjtmScEpcGhJT8XUJNIbTIvbi?= =?us-ascii?q?fDNwKbmT5YvBdZa0F2RZ8ZGMxJ+7cF0otI5sDCU1qjKTkZXBx+MQI1yeZflUlG?= =?us-ascii?q?sEiDZSDREQ+oeu3Vvh1xY8iRsNajLO7l8wdfloPnrOc4+r0DR3K8gw2iW9TeoJ?= =?us-ascii?q?Lnu9KXqESObL/4PPO4YXDfVjjAlxewha0rD5PS5SjcLBJbK4VmyXojeZXhC2nL?= =?us-ascii?q?MgpdKq0GOUVbTr51ac9aou9EesBoYqAJ9rFxBhifXBPgBJSvrOVaLlbUXTnRNC?= =?us-ascii?q?uB/fCjrY/R8LDQR/PtadCLx3bCX614JIx66SXhF7fsz4Be5lL82u1x+UNiVVjG?= =?us-ascii?q?LyeBocz7JgwV+caidlHtvoEyEDPSB5dwjmTiyl9ceMoQXiKl7o4UyJVH53bsUe?= =?us-ascii?q?h4yFT8sPVO97l47ok6+6hpydyoJajINPtarVRqAgOTBgV37JUiHHZwR2ZNYu8L?= =?us-ascii?q?MvjReb4Vjcf0q+D4D6YX8gGa+/RFadvbIEHMgtW/CiuCRhNagQgMsiMaLg+A1/?= =?us-ascii?q?6fgaB0V8elpe/92k0z/1iyNBkGzKpi5Y2c4KqHuPfXbwfNzbgDQqXlW8Xzoa43?= =?us-ascii?q?tkyP4/0rjqQCemtvYw2oCOIdTNISxn/8zaA2yiIhC8HDEKj6+P5ETHI5mijvm4?= =?us-ascii?q?5mElUTB/MUGaaL/YVCkWc5gePZMMYWfrpFmmaVGh6uCqUCxmKz6yuLPGllhQnD?= =?us-ascii?q?0xPqTmO14l/2tyh4TjbSwNr4jkpaTL+3BVxVXyazP093ri+PNhLytNXroaQ18F?= =?us-ascii?q?02Mmv8udKLlWuuJLRXH8nlK9yHOyU0pVUXjJoqRty0wo0bHNWwIdgL/HF5dPve?= =?us-ascii?q?5HuhkzVdrKdfm4re/saV9+3LEna6i62Vta6NxCxYy3g/plw/8cyvNvDQ6N2MX/?= =?us-ascii?q?So1nweQz15uwTfQx6/sqbboEwMOUyXzEfLn5QHPtVC3Xk91kzr/+YjT8wu+wVZ?= =?us-ascii?q?DIbPfesCpSr0ODv231mQf843WjOZ0ztNEVL/CUN4F7Qk2GLsoMLJkm/d+1gsRo?= =?us-ascii?q?ZuckznggJ4D4EjJEIi9lcXxTEDERAXZhCHDbGnH0DlLYoCVUgfdxuH2Ly6eqY4?= =?us-ascii?q?3UJtxLOg+PHcYfZ6B6UTKvZXlhSOk0RDGpIKra0eR6pxe11c9K7SvQXiDpboXv?= =?us-ascii?q?j4mnoqNP21RM9a/doft3Q8/ga1XwCg5otb77YHlJCIcbZJYZnNvc9m9Uho+SUC?= =?us-ascii?q?djdTjxhjkRy2TfoQpOf54tjUqJCo8PqhVL4xR+UL8Bg5H39xj5rrgFEtu97X1e?= =?us-ascii?q?ZcSpHNiYvl7QBNJ2WHt5rd0xZhN+UBMZ+rfKxn93UdPScSPXUOPcCZa/Mk+S9i?= =?us-ascii?q?LC3T50BeAsMLfd4YJNDCmRxIhU3pVrBT8dDbGlyBB4doac8o62v3yDYo8ZozSe?= =?us-ascii?q?vg8CW5JYzD4FFNMfJDiz9slNHYqOgW3/XSEi4X7medaxRvxSOC0ZaNAe7q/eqQ?= =?us-ascii?q?0NHUS08GHikuXodBPjqN5winSfCzlJr3SQ6b987zgJ0/dEKMXHOxh74KsrxREe?= =?us-ascii?q?JajCX0wCReHJjvh/2Jq9qs9HdXtlpfHYZ89xLFArtQPol7ORnjksmrR1R8CTX/?= =?us-ascii?q?eM7Oaxouo/CaxuES7OViL0H+f5MUIgoYy7Lm7npYVgRuR6DwvlaFWuIRY9xqSO?= =?us-ascii?q?jaoXBR6IJgLbIPPVeGqZzusDhIslA3DxUzZL82sDNaalHEnBdJVKbspL4Algwc?= =?us-ascii?q?XMZ8uU9LH2KwJG0+6CTcWKRQjameEvoV/SuPTq0AVEVoKCB+Qwiv1JVoZbSpge?= =?us-ascii?q?hNsnlakSNlvPgqzztmSQOzuSLwvKINwiss9qy3ujsHuHxFSPiekijTBFVMyfQF?= =?us-ascii?q?l6EcBGj45Vy7enkDY5P44KN7KsT46Ykh/3M/bA0hfy0BXeSgDTv8gL+IAoyLrd?= =?us-ascii?q?JTmR+MuMTIbb+oLigSN68wyQziR3hjyAfemAtn8GoRTjWm8tAkOJ23Odw5ySqw?= =?us-ascii?q?BWjbaFEM77tIsMvvr1ELSvA7aVd8wGp+08iHQTYNSNbIG2YvgQgucX9Ef45b6R?= =?us-ascii?q?8GC6kohS6FvqtY8QEabjfUFp+o+4fKksfOx3Y9Uc1mxmTIqa2ZnpkqymFqm8to?= =?us-ascii?q?7i6Sv3Qfb+PYU8trAnn9yIhfzej+au62suAATotmyaiuXOUEMsa95Wu8wI9qVV?= =?us-ascii?q?O9xrQCA1q5N/cOxrXbUyalUW2YXuCLc2mQnzknKUPy4BioLkEtaMhUtUM9NfHC?= =?us-ascii?q?hpFEnQ37Tbx0XjmQpUPczGE7LeMadgc2tZy7ewwLUOERZPaTJew0zP04FlQMc2?= =?us-ascii?q?fDHTFqBO+urV6tgI97Nm1l4UX7YuTt8QfmPcCQGhYeEo7aqZhx9uK8Rm6bP39v?= =?us-ascii?q?0gFyNlFu9+jDD1QxqvNcc5GJkNfLmdt71/IFeux2MS05vd4Thp5j6ZeK38iXax?= =?us-ascii?q?3RyYzyJd7NqPiCH/Lf11gqen1dUrcBeQP14IE6McQjW7zdGrtZuRocCLM/QJwm?= =?us-ascii?q?MGfx7797Ix9pcg7Wf7S0mcjqpuSEZpdOoH/W9F0wJj/GuxIf0vy0URB7b5eyin?= =?us-ascii?q?X8Pp8wQjNBr8VzBRZ9HYpPGsYArw+5DJ6OnKG0lcW9+0Rgu+8FqaDwEOzF1Myl?= =?us-ascii?q?34VtWJhX/UyLPCrRBKlsh0RqlP+yj+zF0pnwFcPiY80LWPJ8Qm7fZb/MBp+/JS?= =?us-ascii?q?6WOsLgZ05G9KaR0bxhUhWLZSD2Q7SJuTahNPVl/UU70JJ3cPDUzDw34LHRwMHy?= =?us-ascii?q?aH1Dpie/sX6JM4NS7FvOBePARB9UUf6F/3x+Ha0LbIv76PsOMcY8z9eC+QVz6i?= =?us-ascii?q?pN0NedKai7skDMwl57dY7cLEbx3yY5WI8KIAmwMEc1hW/Zq2/dAWhHLsW/KMli?= =?us-ascii?q?mtCVDhv360l2g2EtaXZLGnD0SteJJWgbx8W+aRWR9A1VC9YDnui3eVM3t6G1Ru?= =?us-ascii?q?doJpVFlvuwtLoZidZmMTrCRMtEMCHKKr95ID5RAf7SpFgneBIEtKI1Wogtb5iU?= =?us-ascii?q?PEwHKFuAyT/1zQba1U30dses1LqSLScX63VHyajK3SJKpwanpfaTmtfjX6zBbJ?= =?us-ascii?q?HqQP7SNzIoVjSASjsuEUap+FGku/0fsfqGIGcfpE4bYiaTCA4Vu6BuosLcDmjJ?= =?us-ascii?q?me1sZJcKnuyVWzjsSC1kk6o/HiRLulqPQ/oEDgbbdGLhgGxAuAyiIf9M4H3lb7?= =?us-ascii?q?2ExqZPXewZHJdMeOWDQ9TEYfBeOysoljIBNeazZdLTtKw50lPWQmsdCKTI6lme?= =?us-ascii?q?Q1SNQvyd2jLnR4MVsJYouiAw4NLfgjd3E7jUP7aYvzOu8Iu4jCGCue3EV2kteF?= =?us-ascii?q?c4gOQYD2mE3hZAKXsIC9YPuEHiWqSAfVpD1Go1ieJy3B8BYBp8Un9p0n1Wmva9?= =?us-ascii?q?AcpZSVgPgWOhWv0GcU53Ay0q/UOQ5A39f8AAs9jJR2BC7rsMVZYdLP4w5YnMNq?= =?us-ascii?q?sQxeom0TNlrSEhrSWSEUldjgOE8qrXGqJw3LtC6nck//tuREGAXyvfcnTbyoqh?= =?us-ascii?q?E89PxyBuoXbg18fPu+BiKqZVp49+AFcQHS15OMrR/TZfXmHoi0OOuEOgETCfJi?= =?us-ascii?q?8JyCoaLiwCMOBuxql0twibWMzG7BayvqcsswOAAByXB6D8jJ5UAcjzyV+QdThA?= =?us-ascii?q?cTLtEYt/7PlKioBBMusceYGiDgWYfUDFBQWCtnVWqUDn?= X-IPAS-Result: =?us-ascii?q?A2GpEQCblj1Y/wHyM5BdGwEBAQMBAQEJAQEBFgEBAQMBAQE?= =?us-ascii?q?JAQEBgw0BAQEBAR9YcxCmaAGKUYojIQOBeFOFIlMBAQEBAQEBAQIBAl8FI4I9A?= =?us-ascii?q?QMDAgIBAQaBAls8AgQBAhcBDBMUIA4DCQEBFykICAMBLRURDgsFGASITK5YPSo?= =?us-ascii?q?Ci02PNAoHAYVfHgWBJQGHLQeGGHxFiiAChkiGH4QfAoIHOIddhhSRfVVhFwI/N?= =?us-ascii?q?oI6AQEBRByBe1SFUAINFwQDghABAQE?= Received: from unknown (HELO tarius.tycho.ncsc.mil) ([144.51.242.1]) by emsm-gh1-uea11.nsa.gov with ESMTP; 29 Nov 2016 14:59:37 +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 uATEupPt025538; Tue, 29 Nov 2016 09:56:58 -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 uATEpFjl096776 for ; Tue, 29 Nov 2016 09:51:15 -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 uATEpEI1023914 for ; Tue, 29 Nov 2016 09:51:14 -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, 29 Nov 2016 09:50:56 -0500 Message-Id: <1480431057-8768-2-git-send-email-jwcart2@tycho.nsa.gov> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1480431057-8768-1-git-send-email-jwcart2@tycho.nsa.gov> References: <1480431057-8768-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..bb832f2 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 = NULL; + 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 = NULL; + 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 = NULL; + 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 = 0, last = 0; + 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%x", 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%x-0x%x", first, last); + } else { + fprintf(out, " 0x%x 0x%x", first, last); } + first = i; + need_last = CIL_TRUE; } } + if (need_first == CIL_FALSE) { + if (need_last == CIL_FALSE) { + fprintf(out, " 0x%x-0x%x", first, last); + } else { + fprintf(out, " 0x%x", 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 = NULL; + 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