From patchwork Fri Nov 18 18:05:27 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Carter X-Patchwork-Id: 9437187 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 DE1F660237 for ; Fri, 18 Nov 2016 18:07:48 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CA7B42998F for ; Fri, 18 Nov 2016 18:07:48 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id BAE7A299C6; Fri, 18 Nov 2016 18:07:48 +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=-1.9 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 Received: from emsm-gh1-uea10.nsa.gov (smtp.nsa.gov [8.44.101.8]) (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 492F12998F for ; Fri, 18 Nov 2016 18:07:43 +0000 (UTC) X-IronPort-AV: E=Sophos;i="5.31,510,1473120000"; d="scan'208";a="1110403" IronPort-PHdr: =?us-ascii?q?9a23=3A9TjnARVbmd/M4buZkzgJOeyuwIzV8LGtZVwlr6E/?= =?us-ascii?q?grcLSJyIuqrYYheCu6dThVPEFb/W9+hDw7KP9fuxAipZsd3Y6CtKWacPfidNsd?= =?us-ascii?q?8RkQ0kDZzNImzAB9muURYHGt9fXkRu5XCxPBsdMs//Y1rPvi/6tmZKSV3wOgVv?= =?us-ascii?q?O+v6BJPZgdip2OCu4Z3TZBhDiCagbb9oIhi7qQvcutMLjYZhJao91wfFr3VVcO?= =?us-ascii?q?lK2G1kIk6ekQzh7cmq5p5j9CpQu/Ml98FeVKjxYro1Q79FAjk4Km45/MLkuwXN?= =?us-ascii?q?QguJ/XscT34ZkgFUDAjf7RH1RYn+vy3nvedgwiaaPMn2TbcpWTS+6qpgVRHlhD?= =?us-ascii?q?sbOzM/7WrbjMt+g7xGrxK6vhBw3YjUa5yROPZgfq7RYdYWSGxcVchTSiNBGJux?= =?us-ascii?q?YYsRAeQcM+hWrI7zqFkArRumBwSgGe3ixTBUiXH5w6I6yP8sER3E0QE6A94Dqm?= =?us-ascii?q?jYoMvzOawPUe611q7IzTDbYv1Swzj97ZbHcgs8qvySR71wa9bRxlc1FwjYiViQ?= =?us-ascii?q?q4LkMC+P2eQXr2iX8fFtVf6vimE7qwFxpSKjxsE3iobTnI4VxVfE9TtgzYszON?= =?us-ascii?q?a2Rkl7Ydu+H5tRsSGXL452Tdk6Q21yuSY6zLsLsoO4cigS0Jkr2hHSZvOdf4WI?= =?us-ascii?q?/x7vTvidLDhmiH5/Zb6ygQu5/1K6xe3mTMa01U5Hri9CktbRqH8AzwfT6s2bSv?= =?us-ascii?q?tl+UehxCqP2xjT6u5aJUA0krLWK4I7zb4ql5oTrF/DEjXqmET2kKCWdkIk9vKu?= =?us-ascii?q?6+v7ebXpuoWQN4p1igH6Kqgum8q/DvokMgUWQmSW9uux2Kfj8EHkWrlGkPI7nr?= =?us-ascii?q?fDvJzHPcgbo7S2Aw5R0oYt8Ra/CDKm3cwDnXYZKFJFeRSHj5XmOl3XO//4Cuq/?= =?us-ascii?q?g1Kwnzh13PDLJaHhA5XRIXjDl7ftZ7B961VGxwYpwtBf4IxUBqkbIP3vQk/xqM?= =?us-ascii?q?DYDhghPgy62eboEtN92Z8fWWKUGaKZNbvSsV6R6uI0LeiMf5UZuDHnK/gq//Tu?= =?us-ascii?q?l2M2mUcBfam12psacHO4Ee5lI0WefHrhmdQBHn0Jvgo5UezmklqCUSRcZ3yqRa?= =?us-ascii?q?Iz+ik7CJ66DYfEXo2imqGO3D26HpJIfGBLEUqDHmvtd4meXPcMci2SKNd7kjMY?= =?us-ascii?q?TbihV5Mh1Ra2uQ/61bVnKu7U+ioDuJLnydh1++rTlRQo+jBuCMSdyW6NRXlunm?= =?us-ascii?q?wUXz82wLx/oUtlx1eY36h4mftYFcdP5/5SSQc6M5nczuJ/C9/oXALNZNGJR0i6?= =?us-ascii?q?Qt++GzE+Usoxw8MSY0Z6A9ijgArM3y62A7ALjbyLH4c58rzC0HjrPMl91nPG2L?= =?us-ascii?q?Mmj1k8TctFLXemibJn9wjPG47JlF2Ul7q3eqsB3S7C7mODwHGSs0FfVQ5/Tb/K?= =?us-ascii?q?XWsDZkfMq9T2+F/CRae0Cbs7KgtB1dKCKqxSZ93vjFVGQPPjN8rFY2+qgWi/Gw?= =?us-ascii?q?yIxrSWYIrtYWUd0z3XCFIYnAAL4XaGKQ8+Cz+8rG3EEDxhD0zgY03j8ORltHy7?= =?us-ascii?q?TlU7zxuWb0J/zbq54BgViuKAS/kLxLILpD8hqyloHFa6x9/WFduAqBZ9fKVbe9?= =?us-ascii?q?Mx+ktI1WLetwx7MZytNKRihl8YcwttpUPu0A97CoJakcgltHkq1hZ9KbqE0FNd?= =?us-ascii?q?cDOVxZTwOrzMKmnu5RyvcLDZ2lXf0NaQ56cO5+81q077vAGoEEoi8mlo08JP33?= =?us-ascii?q?ua+JrKEBIYUYjtXUYv6xh6u7babzEn54PT0X1sNbe7siXe1NIuCuoo0Q2gf8pD?= =?us-ascii?q?P6OfDgPyFNcaB8e2Iuwwh1epdg4EPPxV9KMsJ8OpbeaG2KqxMOl6hj6plmNH4I?= =?us-ascii?q?Rh0kKL8SpxUevI04oDw/GfwgSLTTH8g0m9ssrvg4BLeSkSHnajySjjHINRY6ly?= =?us-ascii?q?cZ8VBmeoOMC32Mtxh5rpW3FG7l6vHVUG19G1eRCKdVzywRVQ1VgLoXyggSa4zC?= =?us-ascii?q?J7kzcyrqeE3yzB3eLidAEBOmFVWGlul1DsIZK7j9oCRkincxAplAe55Ub936Vb?= =?us-ascii?q?uqJ/IHTITEdWeSj5MmFiXrG2trWcf85F8IkovjlPUOSgfVCaTabwowMA3CP+G2?= =?us-ascii?q?tT3yw0dzC2upT5hhB6hniSLHBpoHreY8Fwyg/V5MbASv5JwjoGWC54hCHPBlem?= =?us-ascii?q?Itmp+cubl4/ZveC4S2KuSIdTfDL2zYObqiS7/3ZqDQekn/C0h93nCxQ13jH119?= =?us-ascii?q?ltTyXIowjzbpPt16ukLeJtZlNoC0Pk68pmBoF+lZM9hJ8K1ngcmpWV+n8HnHz9?= =?us-ascii?q?MdpFxK3+a2ANSiQTw97P5wjl2lNsIW6Vx47jUXWd2MRhbcGgYmwKwiI989xKCK?= =?us-ascii?q?CM4bxLnSt6vkC4rALJYfhhmTcQ0v0u52AGg+ESpAUi1D2dDa4IEUleIyPsiwyC?= =?us-ascii?q?78qio6VPeGavbb+w2VJ7nd+7CLGCph9TWGrlepg4ByB99cN/P0zQ0H3o9o7rYs?= =?us-ascii?q?HQYswJuh2SjRjAk/BfKIgtmfoSmSpnJWX9sGU/y+Ihgx1ix5S6s5KDK2Vq/KO0?= =?us-ascii?q?GQRXOSHwZ88J/THtl6lelN6M34+zBpVhBikLXJzwQPKuCjIdr+znNx6VHT0yq3?= =?us-ascii?q?ebA6HfHROR6EdnqXLACZarOG2WJHYDydVuXh6dJFZQgAoMRjU1goY5Fhy2xMzm?= =?us-ascii?q?aEp5/i4e6UXmpRtKy+JoKx7/X3zepAi2dDg7VoKTLB1M7gFN/03VK9CR7vpvHy?= =?us-ascii?q?FE+Z2stBeCJXecawRMDGEJQVCEB0v5Mrm1+9bP7/KUBvGgIPvKYLWOr/FeVviT?= =?us-ascii?q?yJ2z0opm5SuMNt6VMnhsFfI7xlFDXXd/G8jDnDUPUSMXnTrXb8GHvBe85jF3rs?= =?us-ascii?q?en/fTwQg3v+5GAC7RMPtV04B22mr2MN/CKiyZ2NzlYzYkAxXnWx7gDxFQSkT1h?= =?us-ascii?q?dyGxEbQcsi7AVLnfmq5YDx4cbSN+L9ZH4Lwn0QlMI8HbjMn51rlijv46E11FT0?= =?us-ascii?q?Dumtm1ZcwWJGGwLEnIBEmRO7SYOzLG2Mb3YbuiRr1WieVbrRywuTKAHE/kMTWP?= =?us-ascii?q?jT7pVwqgMetUliGUIAReuJ2hchZqEWXjUNXmahihPN9tij03wKM7hnXROm4GNj?= =?us-ascii?q?hzbUBNo6aM4iNfh/VwB3ZO7mF5LeWenSaW8fXYII4MsfR3GiR0i/5a4HMixrtW?= =?us-ascii?q?7CBEQOJ6lTDXrt5prVGmnPeAyiZ7UBpOrTZLgZyEsV9kOarH6plKQWzE8w4V7W?= =?us-ascii?q?WMFxQKoMNoCtzpu6BM1NfPkLz8KDJc/NLI58sdB9PZKMWfMHU/NxrpHSTbDAoB?= =?us-ascii?q?TTGwMmHeiFZRkPaI9n2atpI6sITjmIISSr9HU1w4DvUaBVp/E9wGO5p3XTQkka?= =?us-ascii?q?WHjMES43q+txrRRMRAspDBSP2SHe3lKCyFgrlcexsI3bT4IJwJNoLlwExtdEN1?= =?us-ascii?q?nJ7WFErQRt1CuSxhbhUpr0VK/nh+Vncz1Fzlaw+35n8cC+K0lAYsigRieeQt6C?= =?us-ascii?q?vs41AvK1XXoyswlk8xlsj7jjCVcT78N72/Up9MCyrzrUQxNYn7QwltZw2ogUNk?= =?us-ascii?q?LCvER65Wj7Z4aG9kkhHcuZpSFv5HVqBLegUQxeuQZ/QmylRTtDmoxVJd5evEFZ?= =?us-ascii?q?tjlBEmcZiyoHJcwwhjdsI6JbTMJKpVyVhdnr+BvjS22e8rzw8ePVwC8H2JdS4T?= =?us-ascii?q?okMINaQmJzCy8eB27QyChj1Dd3IWV/YzvvJq8UA9OuSHzy761b5MNFyxPfSFL6?= =?us-ascii?q?yFo2jAidKIQlQo20MGjUlK46V50dw5fEqSS0Avy6CRGg8TOsXeLAFZdc1S9GLc?= =?us-ascii?q?fSyWq+XC3Yp1P5mhFuDvVeKOsKEUgli6EwYvHoUM6d8MHpaq0EHFN8vnK6QFyR?= =?us-ascii?q?o17gTxOFqFFOhJeA6MkDofuMGw0pt33YhbJjEADmRwKjm45rHSpgA2mvWDR8s2?= =?us-ascii?q?bm0cXoQaKnI8QNe6lDJBv3RcEDm31foUyAuY7z78vCvQCiX8b9p4afebYhNsEM?= =?us-ascii?q?259S8586eolV7d6o/eKH3iNdR+pt/P7vsXp4qGC/NRSrl9r0fcmolDSnO3Um7O?= =?us-ascii?q?EcS6KIPqZ4kqc9P0Fm6wUkajhDItU8fxINGtI7CIgQHvW4lUvpeU3Co4OM+8CD?= =?us-ascii?q?4RBQl/q/sE5KJmag0Je4A7bgLwtwQiK6y/Jx+V3c+qQ2asNTRZUeFQzeC6ZrxR?= =?us-ascii?q?yCosaPW1xWA7QZE71ea391cBRJ8Xjh3Ew/aseZVeWzDpGnNBYwXPuTY5l295O+?= =?us-ascii?q?kp3Og/xgjFvkMBPDCVauNpcndEsMsmBVKSO3l2DXA4R1CEh4rZ/gGsx6wS/zda?= =?us-ascii?q?n9tM3u1FrXn+vpvbYD2yXaymsojavDQ7YtgnuaJxN5bvIsyctJPRhjbfVoXfsh?= =?us-ascii?q?WZUC6mEPpXgsJQICRZQPZUmWElPsgGuZFZ50QoS8kwPaBCBq43q7+2bjpkCDId?= =?us-ascii?q?wjUCV4OcxjAChPmz26fCnBeKbJsiKAAEsIlFgtYFSS55fz4RqbSsV4XTmG6IUG?= =?us-ascii?q?4LLxkP7Q5U/gIPipdwfvz54IrPVJJD1zxWrOhoXSbQCpZo8F/7SmWXgVfmUvWh?= =?us-ascii?q?j/Km0h5SzP721dkbQhF/A1BHx+lKjksoNK13K64Is47QqDCIb0T6s3n2xeu6Pl?= =?us-ascii?q?le09PUeEP8DIrEs2r8XSkc+XwbRY9P1HHfG44dkxB8aKoxolVDPpymcF7k5zM4?= =?us-ascii?q?34RpA6W4Vcezylclt3kGXD2lE99AC+Fgq1/XWSFlbIqwqJr5IZpeWGlQ94OBq1?= =?us-ascii?q?1BikViLza5yYZAK8FK+jMNUiJDrimdvNuzTc1D2NV5D5wXL9d+pXjyBr1LNIKW?= =?us-ascii?q?o30stbzl0mXZ9CwksFem2DWzHLe1QPhD/20DHAUlPWeep1IuD+st82fS7kvCvk?= =?us-ascii?q?py/+hFGriFlV9xryplHpBSGjZJ0mioL1tpTHZcteVaNL/Yc81bQ/g8Yx+vJxw+?= =?us-ascii?q?GuAn30yP4UF7g235bzZ0tgRE5yDXRxM0WjUNgrfxhT0erdmqOSMdS5JNdjghcz?= =?us-ascii?q?vJKweAlixNuhZQdV1qUYgDAtlZ47EbwZdU/s3aREasMy4FRgZtNgYl3vdEiEFM?= =?us-ascii?q?rl2YeTjDAgqsa/nPqAd7fcCLrM6mNP755htIipv7sOAk8KUOX3+mmQqzTt3Fso?= =?us-ascii?q?DzqMaKuVWUdKfkLeKzfGXNTD7SghCsnb0kFYXF/zDPMApHLJl30WErYZb9BmLX?= =?us-ascii?q?PxlKOqwWKlFHWqB9bNVJvvpVZ9R4eKoT/69iGA6HTAv1GIOztPlGMkrTRTPGIi?= =?us-ascii?q?Wb7OOwvILT4qbBSeX7YsyMwGjHTLxpMphm7jn0Bqnl3ZVY+kXoxvdn7ll6RkTe?= =?us-ascii?q?MyCdsNThIRsG5NG5dkv+pJImAC/WDYxrkHrq20FAbdYYTDOs8JQE0pNW8nLwRf?= =?us-ascii?q?h/0kjpv+1Y76Nk5pUv47B11ce0Ir/fKehAsUB5HBebGx5n9ogpAGhjXWBeePER?= =?us-ascii?q?KPbWfaQdk8/ut/r7F6sN6B2a4+ZZc8fIJ1ndmsmjDTGRUQFLnAEbpjMBMwSc0e?= =?us-ascii?q?SKl7VzSca/qujzwlgt7ESmLh4a0LBt4p+J+qiSq+/NaBvR1rwEVbL0Rs7oq7Qs?= =?us-ascii?q?pkeS5eEllLESe2x6eQunEPMHWs4a3GfgwrggzTgwHMPbA7Lg5PlDWmo7nj36nZ?= =?us-ascii?q?B9EU8WGvQJErWV5olegn03m+rCNt0RaKxCnHiAFQK8GL8Y1XGr8zeXIHVighzW?= =?us-ascii?q?1RHwRXi+7F7wrS99WyfMztHjkkRPVratHkdSQzCpOVJkvzOTIQrorsT4tb4y7E?= =?us-ascii?q?EsPWzurMiNm3e5OLNLA83/I8SRIS81pF0Li50xQsag2ZsBFdq8J9cR92p+buDF?= =?us-ascii?q?5mOunCJArL1Lh43E4sGa4v/XB2Wvj7WGq7WRwzBV0mQ3sks76t++LfHO+92LQ/?= =?us-ascii?q?Oz2mYKUyh/uhXOXxipqrzatV8YI0qL31nXmIYSJNFWwWE41l365OgkWN8z8B5e?= =?us-ascii?q?FoPAav4ZqzD8Jib7wVGFY90tTimeyTxXHlDrHlZkBKgwwmXwvNjGlX3I4V0nWp?= =?us-ascii?q?Fwd1D7hRxwF4g4LEYt50YSwioEDwcNbQuWDL62CkTiNosETVIMaQiG3Legfqc3?= =?us-ascii?q?3Etzwq+x6+/Xaex8BqUNOehbjgGSgldXAJQWvrMCQLhkYV9S6LbXphT+C4jgR/?= =?us-ascii?q?Xml3swNfiuT8Bf788Yt2Ut4hy+Rxqm5pdP9bAbh46UdqRce5jDoNh871t75T4I?= =?us-ascii?q?biFNgRl+gAmjXu8Av+3j+cbUsIa25emyTqotQP8X9xcsDWRkk5TwmEwjoc3Q1+?= =?us-ascii?q?pEUYLViJ//8Q5XLH6IuYbazwF8JvATK4KvZ7tv63IHKDUAKH0UINqWcf484zV3?= =?us-ascii?q?PznJ4FxCGMwMb8sCPMXRgQBUllHpWLZL+8rDAFCYF5t8d8Am7mrw0jA18oIwUv?= =?us-ascii?q?3+5z+yJJDf6UxNPvxYgSV0jt3CuPQawfrcCSgQ+3mZaAJ5wiCcxJmXDfb/4+GM?= =?us-ascii?q?xMvTV1McES48S51dKyaa+Qy7Wuq1k43kUh+O6sDthJIxbkSQSWKqkasYs6ZMHu?= =?us-ascii?q?9Aijnh0ThFDI/1ne+Vv8Cq6GRJql1NCJxz4gHdGKVDIpV7Pgz1lsaxSUhmGCT/?= =?us-ascii?q?ZMHUewEquOqX2ucD/eV+OFHjZY8AOB4Ezaz16WZNRAt0VLH2pkqZXf4WZNZ+R/?= =?us-ascii?q?PLsHZV6Z5nK68IO1Sdv4LlrjNJqFAwHQ8oZ6Q9rjhEeUnUnAxaQbz4uLgehQsA?= =?us-ascii?q?SdR5o1NDGXqsOGIi4DrKTaFVjK6XCPwJ/TWcULcDU0BpMixkRRO6xoluerWunf?= =?us-ascii?q?BdsWNGhTlxoP403Dx6XBG8ozHjp7oR2TI8/7G1rDoBtmBeTuWFiivGFFpNwvIL?= =?us-ascii?q?jacaFnbj5kexYHYGbITo5rloO97s9Y4743QweR8jZTEJXfy8CyHsiKOFGo6PsN?= =?us-ascii?q?VchB6LosnBcb+zLSwPNrsgyBPjRn590hPdnBZp62YLXDSg7ME+K4W5JMklxzCk?= =?us-ascii?q?GW7Fe1YQ+qlJqtf+tUYXTOsqblNs2GRj0tadSS0LX8HPH3s1gRUlaWVDa5JP8x?= =?us-ascii?q?gaF7MngjyQpKlJ4hkUYCvIEoSi4oTQn9nH2XczTddu3W/XqLeKhpU03315gd90?= =?us-ascii?q?6DCBuGgKfezCT8BsGmTz1ptYyeHmaPWttucHSYV4x7SlVP8PKdKj+Wyw2JVrRk?= =?us-ascii?q?Cp3LIeEESlMOUb3LfUTz+lSXGEWeSMa2WMnTY5M07q5RmvKl03adtKoFEmP+vH?= =?us-ascii?q?h55cixfhXq1uSiWXv1/bw3QpMfkGeAIupIenZwsKQfYNZ+idIOgj2+E+CFoQYH?= =?us-ascii?q?/KAyR2D/W6sVizk4hnI39g+1n1Yfzx8gD6N9ufAhwEEY/Zrp5y/vy3XWCBNmVj?= =?us-ascii?q?zB11Okl76eHfG043tuBCb5abhcLQiMhj0e4Za/dtNjUwtcUNlYJl9YmZy9yKcR?= =?us-ascii?q?XWzpbuOdHVvOaXDODFw0QtYGFaXaITYRnp6IUiIt45R7rTEKNBvRQbAag1WoYh?= =?us-ascii?q?Nmn29KFwIgN+aQvRZLOzgsnxuO2EeoFUp3jN7lIrLSfcvRIDxuazTQxhYJCgn2?= =?us-ascii?q?/yL4woRjJds91tDQNrHIVRFMMErgqnG4Cblbq6it+w/kN6vvEFsbD0Cv/Uzti5?= =?us-ascii?q?2J9xX5dC70yRIDnRHLVrglhijumqgvfAzpnxCcTnedweT+h2WWvFar7aHoWlND?= =?us-ascii?q?2CIMX8e1RJ87SEyrJ2Tg2RZDzlX6qBrCClOu1k4V86yoNkYuXe1zkt77DH2Nvo?= =?us-ascii?q?eW5XvCCjrWSGNJFH9lzFGfTeXw5ISfqC6GtlGqkXYpXv+ecWNdwt2sOc4xVy7D?= =?us-ascii?q?tezMuFObauoVHW1kJ9a53bMFPj2zwlVokSPBS/LUwsjHfdqnTcB3RcM8elJdBp?= =?us-ascii?q?gNaUFRzt+1JxlHosZmFbHGroQs2dOW8B28KxfAeK7h5ED84fn+6rfk41rrayRv?= =?us-ascii?q?dsOpVEn+WqqboGndFmJSHTRMhVITvQI6FuPjVLFejPp0YnYgQCs7crXoc6foWO?= =?us-ascii?q?IEwdPEeH0yPywhPI0VfoeNy0yKaJPCEW/21Dz7LEyjhMuxK0uPeAgs3lSr/Vdp?= =?us-ascii?q?f2U+DOMCA9TDGVWSwyEVq1+Vejo/cEueCXLnsfolAVZCKSDxUepr5urdjWEGDT?= =?us-ascii?q?nexjfJsXhPGVQSzwTzd4lKUqDCZRqU+MW+YDFRXRb3L5gmpTog+iJvhX8n/+cr?= =?us-ascii?q?2YwLZVW+wRAotRff2ZQ8fYdepYJzg2ijUTIPy8cMHEr7YlzlLISnMUE6bS+1KF?= =?us-ascii?q?Vk6WQ+KTxzbwUIULu4g7oDEo+tPNniNtFaTHIaqfrSa08oGklCaYpfHeVm41bk?= =?us-ascii?q?w3heICB3OBwANBKGEfENwVvlviQqueaEZNzn4pjvhu2xAUcgRpTnJuymFWnOq6?= =?us-ascii?q?GsBBV1EUjmSuQP0AbFBsCzMw+1SH4gLoYdwdp8DcWXVe+qEKSYUDMPki8JPXN7?= =?us-ascii?q?cIwPY1wDJmpzQ3sz6TD1NYkg2I8qndEblixrJc/2k4/vB3XkaJQz/FdGjI1Jam?= =?us-ascii?q?AdpVxShyuXDky9bUvud1ObtYoIF5BlMKDDlzJt/D4D9BX2b02BGusBmlBjieJi?= =?us-ascii?q?wW4CpYbRACI/14y+59rQbgasfK6UTWsbko7kSsF1WlEL2xjb5CD8zynS6xczVG?= =?us-ascii?q?a33/FY99o+xRzv4OcKgnYs64GFmHIQ/gWFHL8xsQ/QTn9+34RfFBxX8Tx/9xcN?= =?us-ascii?q?w=3D?= X-IPAS-Result: =?us-ascii?q?A2FtCgDgQi9Y/wHyM5BeGwEBAQMBAQEJAQEBFgEBAQMBAQE?= =?us-ascii?q?JAQEBgwwBAQEBAR9YcBCmUQGKSYodIAOBeFOFRFMBAQEBAQEBAQIBAl8FI4I9A?= =?us-ascii?q?QMDAgIBAQaBAls8AgQBAhcBDBMUIA4DCQEBFykICAMBLRURDgsFGASIS61nPSo?= =?us-ascii?q?Ci06PMQoHAYVfHgWBJQGHKAeGFHxFih8ChkCGHIQWAoIFOIdbhg2RZlVdEQI4L?= =?us-ascii?q?4IyAQEBRByBe1SGBwINFwQDgg8BAQE?= Received: from unknown (HELO tarius.tycho.ncsc.mil) ([144.51.242.1]) by emsm-gh1-uea10.nsa.gov with ESMTP; 18 Nov 2016 18:07:39 +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 uAII7ajm004158; Fri, 18 Nov 2016 13:07:38 -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 uAII5pGQ225053 for ; Fri, 18 Nov 2016 13:05:51 -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 uAII5o82004033 for ; Fri, 18 Nov 2016 13:05:50 -0500 From: James Carter To: selinux@tycho.nsa.gov Subject: [PATCH 1/2] libsepol/cil: Add ability to write policy.conf file from CIL AST Date: Fri, 18 Nov 2016 13:05:27 -0500 Message-Id: <1479492328-12238-2-git-send-email-jwcart2@tycho.nsa.gov> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1479492328-12238-1-git-send-email-jwcart2@tycho.nsa.gov> References: <1479492328-12238-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_gen_policy() 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 | 2696 ++++++++++++++++++++++++---------------- libsepol/cil/src/cil_policy.h | 12 +- libsepol/src/libsepol.map.in | 1 + 5 files changed, 1611 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..d343ffa 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,1063 +39,1413 @@ #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 (attr->used) { + 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; - - 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"); - } - - return SEPOL_OK; + cil_tree_walk(start, __cil_gather_statements_helper, NULL, NULL, lists); } -int cil_genfscon_to_policy(FILE **file_arr, struct cil_sort *sort) +static void cil_simple_rules_to_policy(FILE *out, struct cil_list *rules, char *kind) { - uint32_t i = 0; + struct cil_list_item *i1; - 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"); + cil_list_for_each(i1, rules) { + fprintf(out, "%s %s;\n", kind, DATUM(i1->data)->fqn); } - - return SEPOL_OK; } -int cil_netifcon_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_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"); + char lead = '\0'; + 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, "%c%s,%s", lead, + DATUM(first)->fqn, DATUM(cat)->fqn); + lead = ','; + first = NULL; + } + } else if (cat->value == last->value + 1) { + last = cat; + } else { + fprintf(out, "%c%s", lead, DATUM(first)->fqn); + if (last->value >= first->value + 1) { + fprintf(out, "."); + } else { + fprintf(out, ","); + } + fprintf(out, "%s", DATUM(last)->fqn); + lead = ','; + first = cat; + last = NULL; + } + } + if (first) { + fprintf(out, "%c%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_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 (lvlrange->low != lvlrange->high) { + 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 char *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, ")"); } - - fprintf(file_arr[NETIFCONS], "%s ", buf); - free(buf); - - cil_context_to_policy(file_arr, NETIFCONS, nodecon->context); - fprintf(file_arr[NETIFCONS], ";\n"); + } else if (i1->flavor == CIL_LIST) { + cil_cond_expr_to_policy(out, i1->data, CIL_FALSE); + } else { + fprintf(out, "???"); } - - return SEPOL_OK; - -exit: - return rc; } - -int cil_pirqcon_to_policy(FILE **file_arr, struct cil_sort *sort) +static size_t __cil_userattribute_len(struct cil_db *db, struct cil_userattribute *attr) { - uint32_t i = 0; + ebitmap_node_t *unode; + unsigned int i; + size_t len = 0; - 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"); + 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; + return len; } -int cil_iomemcon_to_policy(FILE **file_arr, struct cil_sort *sort) -{ - uint32_t i = 0; - 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"); +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; + + 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 SEPOL_OK; + return len; } -int cil_ioportcon_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_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"); + 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_pcidevicecon_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_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"); + 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_fsuse_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; 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 "); +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 { - return SEPOL_ERR; + 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++ = ' '; + } } - fprintf(file_arr[NETIFCONS], "%s ", fsuse->fs_str); - cil_context_to_policy(file_arr, NETIFCONS, fsuse->context); - fprintf(file_arr[NETIFCONS], ";\n"); + new--; + *new++ = '}'; } - 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 char *__cil_cons_leaf_op_to_string(struct cil_list_item *op, char *new) { - struct cil_list_item *curr_key; - struct cil_multimap_item *new_data; - - if (list == NULL || key == NULL) { - return SEPOL_ERR; - } - - 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;; - } - } - cil_list_append(curr_multimap_item->values, val_flavor, value); - } - } else { - cil_log(CIL_INFO, "No data in list item\n"); - return SEPOL_ERR; - } + 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; } - 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); + strcpy(new, op_str); + new += len; - return SEPOL_OK; + return new; } -int cil_userrole_to_policy(FILE **file_arr, struct cil_list *userroles) +static char *__cil_cons_expr_to_string(struct cil_db *db, struct cil_list *cons_expr, char *new) { - struct cil_list_item *current_user; - - if (userroles == NULL) { - return SEPOL_OK; + 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++ = ')'; } - - 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; - } - fprintf(file_arr[USERROLES], "user %s roles {", user_multimap_item->key->name); + return new; +} + +static char *cil_cons_expr_to_string(struct cil_db *db, struct cil_list *cons_expr) +{ + char *new, *tail; + size_t len = cil_cons_expr_len(db, cons_expr); - cil_list_for_each(current_role, user_multimap_item->values) { - fprintf(file_arr[USERROLES], " %s", ((struct cil_role*)current_role->data)->datum.name); - } - fprintf(file_arr[USERROLES], " };\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_cat_to_policy(FILE **file_arr, struct cil_list *cats) +static void cil_classperms_to_string(struct cil_classperms *classperms, struct cil_list *classperms_strs) { - struct cil_list_item *curr_cat; + struct cil_list_item *i1; + size_t len = 0; + char *new, *curr; - if (cats == NULL) { - return SEPOL_OK; + 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_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); - } - fprintf(file_arr[CATS], ";\n"); - } + 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++ = '}'; - return SEPOL_OK; + cil_list_append(classperms_strs, CIL_STRING, new); } -int cil_sens_to_policy(FILE **file_arr, struct cil_list *sens) +static void cil_classperms_to_strings(struct cil_list *classperms, struct cil_list *classperms_strs) { - struct cil_list_item *curr_sens; + struct cil_list_item *i1; - if (sens == NULL) { - return SEPOL_OK; - } - - 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); + 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); + } } - fprintf(file_arr[SENS], ";\n"); + } 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); } } - - return SEPOL_OK; } -void cil_cats_to_policy(FILE **file_arr, uint32_t file_index, struct cil_cats *cats) +static void cil_class_decls_to_policy(FILE *out, struct cil_list *classorder) { - cil_expr_to_policy(file_arr, file_index, cats->datum_expr); + struct cil_list_item *i1; + + cil_list_for_each(i1, classorder) { + fprintf(out, "class %s\n", DATUM(i1->data)->fqn); + } } -void cil_level_to_policy(FILE **file_arr, uint32_t file_index, struct cil_level *level) +static void cil_sid_decls_to_policy(FILE *out, struct cil_list *sidorder) { - char *sens_str = level->sens->datum.name; + struct cil_list_item *i1; - 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); + cil_list_for_each(i1, sidorder) { + fprintf(out, "sid %s\n", DATUM(i1->data)->fqn); } } -void cil_levelrange_to_policy(FILE **file_arr, uint32_t file_index, struct cil_levelrange *lvlrange) +static void cil_commons_to_policy(FILE *out, struct cil_list *commons) { - 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; + 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"); + } } -void cil_context_to_policy(FILE **file_arr, uint32_t file_index, struct cil_context *context) +static void cil_classes_to_policy(FILE *out, struct cil_list *classorder) { - 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_class *class; + struct cil_tree_node *node; + + 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(out, "\n"); + } +} - fprintf(file_arr[file_index], "%s:%s:%s:", user_str, role_str, type_str); - cil_levelrange_to_policy(file_arr, file_index, lvlrange); +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"); + } } -void cil_perms_to_policy(FILE **file_arr, uint32_t file_index, struct cil_list *list) +static void cil_default_ranges_to_policy(FILE *out, struct cil_list *defaults) { - struct cil_list_item *curr; + 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, " }"); - 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); + switch (def->object_range) { + case CIL_DEFAULT_SOURCE_LOW: + fprintf(out," %s %s", CIL_KEY_SOURCE, CIL_KEY_LOW); break; - case CIL_STRING: - fprintf(file_arr[file_index], " %s", (char *)curr->data); + case CIL_DEFAULT_SOURCE_HIGH: + fprintf(out," %s %s", CIL_KEY_SOURCE, CIL_KEY_HIGH); break; - case CIL_DATUM: - fprintf(file_arr[file_index], " %s", ((struct cil_symtab_datum *)curr->data)->name); + case CIL_DEFAULT_SOURCE_LOW_HIGH: + fprintf(out," %s %s", CIL_KEY_SOURCE, CIL_KEY_LOW_HIGH); 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; - } - fprintf(file_arr[file_index], " %s", op_str); + 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: - cil_log(CIL_ERR, "Unknown flavor in expression\n"); break; } + fprintf(out,";\n"); } - 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_sensitivities_to_policy(FILE *out, struct cil_list *sensorder, struct cil_list *all_aliases) { - struct cil_list_item *curr; - - 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); + struct cil_list_item *i1, *i2; + struct cil_sens *sens; + struct cil_list *aliases; + struct cil_alias *alias; + struct cil_sens *actual; + int num_aliases; + + cil_list_for_each(i1, sensorder) { + sens = i1->data; + num_aliases = 0; + cil_list_for_each(i2, all_aliases) { + alias = i2->data; + actual = alias->actual; + if (sens == actual) { + if (num_aliases == 0) { + cil_list_init(&aliases, CIL_LIST); } - } - } 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); + cil_list_append(aliases, CIL_SENSALIAS, alias); + num_aliases++; + } + } + 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"); } } -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_dominance_to_policy(FILE *out, struct cil_list *sensorder) { - char *kind = NULL; + struct cil_list_item *item; + struct cil_sens *sens; - if (flavor == CIL_CONSTRAIN) { - kind = CIL_KEY_CONSTRAIN; - } else if (flavor == CIL_MLSCONSTRAIN) { - kind = CIL_KEY_MLSCONSTRAIN; + fprintf(out, "dominance {"); + cil_list_for_each(item, sensorder) { + sens = item->data; + fprintf(out, " %s", sens->datum.fqn); } - - cil_constrain_to_policy_helper(file_arr, kind, cons->classperms, cons->datum_expr); + fprintf(out, " }\n"); } -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) +static void cil_categories_to_policy(FILE *out, struct cil_list *catorder, struct cil_list *all_aliases) { - 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); + struct cil_list_item *i1, *i2; + struct cil_sens *cat; + struct cil_list *aliases; + struct cil_alias *alias; + struct cil_sens *actual; + int num_aliases; + + cil_list_for_each(i1, catorder) { + cat = i1->data; + num_aliases = 0; + cil_list_for_each(i2, all_aliases) { + alias = i2->data; + actual = alias->actual; + if (cat == actual) { + if (num_aliases == 0) { + cil_list_init(&aliases, CIL_LIST); } + cil_list_append(aliases, CIL_CATALIAS, alias); + num_aliases++; } - } 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); + } + 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"); } } -int cil_avrule_to_policy(FILE **file_arr, uint32_t file_index, struct cil_avrule *rule) +static void cil_levels_to_policy(FILE *out, struct cil_list *sensorder) { - const char *kind_str = NULL; - const char *src_str = DATUM(rule->src)->name; - const char *tgt_str = DATUM(rule->tgt)->name; - - - switch (rule->rule_kind) { - case CIL_AVRULE_ALLOWED: - kind_str = "allow"; - break; - case CIL_AVRULE_AUDITALLOW: - kind_str = "auditallow"; - break; - case CIL_AVRULE_DONTAUDIT: - kind_str = "dontaudit"; - break; - case CIL_AVRULE_NEVERALLOW: - kind_str = "neverallow"; - 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; + struct cil_list_item *i1, *i2; + struct cil_sens *sens; + + cil_list_for_each(i1, sensorder) { + sens = i1->data; + fprintf(out, "level %s",sens->datum.fqn); + if (sens->cats_list) { + fprintf(out, ":"); + cil_list_for_each(i2, sens->cats_list) { + cil_cats_to_policy(out, i2->data); + } + } } +} - cil_avrule_to_policy_helper(file_arr, file_index, kind_str, src_str, tgt_str, rule->perms.classperms); - - return SEPOL_OK; +static void cil_mlsconstrains_to_policy(FILE *out, struct cil_db *db, struct cil_list *mlsconstrains) +{ + 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); + } } -int cil_typerule_to_policy(FILE **file_arr, __attribute__((unused)) uint32_t file_index, struct cil_type_rule *rule) +static void cil_validatetrans_to_policy(FILE *out, struct cil_db *db, struct cil_list *validatetrans, char *kind) { - 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; - - 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); - break; - case CIL_TYPE_MEMBER: - fprintf(file_arr[ALLOWS], "type_member %s %s : %s %s;\n", src_str, tgt_str, obj_str, result_str); - break; - default: - cil_log(CIL_INFO, "Unknown type_rule\n"); - return SEPOL_ERR; + 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); } - - return SEPOL_OK; } -int cil_nametypetransition_to_policy(FILE **file_arr, uint32_t file_index, struct cil_nametypetransition *nametypetrans) +static void cil_bools_to_policy(FILE *out, struct cil_list *bools) { - 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_list_item *i1; + struct cil_bool *bool; + char *value; - 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; + cil_list_for_each(i1, bools) { + bool = i1->data; + value = bool->value ? "true" : "false"; + fprintf(out, "bool %s %s;\n", bool->datum.fqn, value); + } } -static int cil_expr_to_string(struct cil_list *expr, char **out) +static void cil_typealiases_to_policy(FILE *out, struct cil_list *types, struct cil_list *all_aliases) { - int rc = SEPOL_ERR; - struct cil_list_item *curr; - char *stack[COND_EXPR_MAXDEPTH] = {}; - int pos = 0; - int i; - - cil_list_for_each(curr, expr) { - if (pos > COND_EXPR_MAXDEPTH) { - rc = SEPOL_ERR; - goto exit; - } - 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; + struct cil_list_item *i1, *i2; + struct cil_type *type; + struct cil_list *aliases; + struct cil_alias *alias; + struct cil_type *actual; + int num_aliases; + + cil_list_for_each(i1, types) { + type = i1->data; + num_aliases = 0; + cil_list_for_each(i2, all_aliases) { + alias = i2->data; + actual = alias->actual; + if (type == actual) { + if (num_aliases == 0) { + cil_list_init(&aliases, CIL_LIST); } - 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; + cil_list_append(aliases, CIL_TYPEALIAS, alias); + num_aliases++; } - 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; + if (num_aliases > 0) { + fprintf(out, "typealias %s alias", type->datum.fqn); + if (num_aliases > 1) { + fprintf(out, " {"); } - stack[pos] = operand_str; - pos++; - break; - } - default: - cil_log(CIL_ERR, "Unknown flavor in expression\n"); - goto exit; - break; + 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); } } +} - *out = stack[0]; - - return SEPOL_OK; +static void cil_typebounds_to_policy(FILE *out, struct cil_list *types) +{ + 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); + } + } +} -exit: - for (i = 0; i < pos; i++) { - free(stack[i]); +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); + } + } + } + if (!first) { + fprintf(out, ";\n"); + first = CIL_TRUE; + } } - return rc; } -int cil_expr_to_policy(FILE **file_arr, uint32_t file_index, struct cil_list *expr) +static void cil_xperms_to_policy(FILE *out, struct cil_permissionx *permx) { - int rc = SEPOL_ERR; - char *str_out; + ebitmap_node_t *node; + unsigned int i; + int first = -1, last = -1; + char *kind; - rc = cil_expr_to_string(expr, &str_out); - if (rc != SEPOL_OK) { - goto out; + if (permx->kind == CIL_PERMX_KIND_IOCTL) { + kind = "ioctl"; + } else { + kind = "???"; } - fprintf(file_arr[file_index], "%s", str_out); - free(str_out); - return SEPOL_OK; + fprintf(out, "%s %s {", DATUM(permx->obj)->fqn, kind); -out: - return rc; + ebitmap_for_each_bit(permx->perms, node, i) { + if (!ebitmap_get_bit(permx->perms, i)) + continue; + if (first < 0) { + first = i; + } else if (last < 0) { + if (i == first+1) { + last = i; + } else { + fprintf(out, " 0x%hx 0x%hx", first, i); + first = -1; + } + } else if (i == last+1) { + last = i; + } else { + if (last > first+1) { + fprintf(out, " 0x%hx-0x%hx", first, last); + } else { + fprintf(out, " 0x%hx 0x%hx", first, last); + } + first = i; + last = -1; + } + } + if (first >= 0) { + if (last >= 0) { + fprintf(out, " 0x%hx-0x%hx", first, last); + } else { + fprintf(out, " 0x%hx", first); + } + } + fprintf(out," }"); } -int __cil_booleanif_node_helper(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, void *extra_args) +static void cil_av_rulex_to_policy(FILE *out, struct cil_avrule *rule) { - int rc = SEPOL_ERR; - struct cil_args_booleanif *args; - FILE **file_arr; - uint32_t *file_index; + char *kind; + struct cil_symtab_datum *src, *tgt; - args = extra_args; - file_arr = args->file_arr; - file_index = args->file_index; + src = rule->src; + tgt = rule->tgt; - 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; - } + switch (rule->rule_kind) { + case CIL_AVRULE_ALLOWED: + kind = "allowxperm"; 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_AVRULE_AUDITALLOW: + kind = "auditallowxperm"; break; - case CIL_FALSE: - fprintf(file_arr[*file_index], "else {\n"); + case CIL_AVRULE_DONTAUDIT: + kind = "dontauditxperm"; break; - case CIL_TRUE: + case CIL_AVRULE_NEVERALLOW: + kind = "neverallowxperm"; break; default: - return SEPOL_ERR; + kind = "???"; + break; } - return SEPOL_OK; + fprintf(out, "%s %s %s : ", kind, src->fqn, tgt->fqn); + cil_xperms_to_policy(out, rule->perms.x.permx); + fprintf(out, ";\n"); } -int __cil_booleanif_last_child_helper(struct cil_tree_node *node, void *extra_args) +static void cil_av_rule_to_policy(FILE *out, struct cil_avrule *rule) { - struct cil_args_booleanif *args; - FILE **file_arr; - uint32_t *file_index; + char *kind; + struct cil_symtab_datum *src, *tgt; + struct cil_list *classperms_strs; + struct cil_list_item *i1; - args = extra_args; - file_arr = args->file_arr; - file_index = args->file_index; + src = rule->src; + tgt = rule->tgt; + + switch (rule->rule_kind) { + case CIL_AVRULE_ALLOWED: + kind = "allow"; + break; + case CIL_AVRULE_AUDITALLOW: + kind = "auditallow"; + break; + case CIL_AVRULE_DONTAUDIT: + kind = "dontaudit"; + break; + case CIL_AVRULE_NEVERALLOW: + kind = "neverallow"; + break; + default: + kind = "???"; + break; + } - if (node->parent->flavor == CIL_FALSE) { - fprintf(file_arr[*file_index], "}\n"); + 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); } - - return SEPOL_OK; + cil_list_destroy(&classperms_strs, CIL_FALSE); } -int cil_booleanif_to_policy(FILE **file_arr, uint32_t file_index, struct cil_tree_node *node) +static void cil_type_rule_to_policy(FILE *out, struct cil_type_rule *rule) { - 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; + char *kind; + struct cil_symtab_datum *src, *tgt, *res; + struct cil_list *class_list; + struct cil_list_item *i1; - extra_args.file_arr = file_arr; - extra_args.file_index = &file_index;; + src = rule->src; + tgt = rule->tgt; + res = rule->result; - 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; + switch (rule->rule_kind) { + case CIL_TYPE_TRANSITION: + kind = "type_transition"; + break; + case CIL_TYPE_MEMBER: + kind = "type_member"; + break; + case CIL_TYPE_CHANGE: + kind = "type_change"; + break; + default: + kind = "???"; + break; } - 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; - } + 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); +} - 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_nametypetransition_to_policy(FILE *out, struct cil_nametypetransition *trans) +{ + 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], "{\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; - } + 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;\n", src->fqn, tgt->fqn, DATUM(i1->data)->fqn, res->fqn); } - fprintf(file_arr[file_index], "}\n"); + cil_list_destroy(&class_list, CIL_FALSE); +} - 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_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); +} - return SEPOL_OK; +static void cil_typepermissive_to_policy(FILE *out, struct cil_typepermissive *rule) +{ + fprintf(out, "permissive %s;\n", DATUM(rule->type)->fqn); } -int cil_name_to_policy(FILE **file_arr, struct cil_tree_node *current) +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) { - uint32_t flavor = current->flavor; - int rc = SEPOL_ERR; + struct block_te_rules_extra *args = extra_args; - 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); + 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_ROLE: - fprintf(file_arr[TYPEATTRTYPES], "role %s;\n", ((struct cil_symtab_datum*)current->data)->name); + case CIL_MACRO: + *finished = CIL_TREE_SKIP_HEAD; 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); + case CIL_BOOLEANIF: + *finished = CIL_TREE_SKIP_HEAD; 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; + 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); + } + } } - - 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; + 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); } - current = current->next; } - 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; + + break; + case CIL_NAMETYPETRANSITION: + if (args->flavor == node->flavor) { + cil_nametypetransition_to_policy(args->out, node->data); } 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; + case CIL_RANGETRANSITION: + if (args->flavor == node->flavor) { + cil_rangetransition_to_policy(args->out, node->data); } + break; - } - 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; + case CIL_TYPEPERMISSIVE: + if (args->flavor == node->flavor) { + cil_typepermissive_to_policy(args->out, node->data); } - } - 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); + default: 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; - 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; + return SEPOL_OK; +} + +static void cil_block_te_rules_to_policy(FILE *out, struct cil_tree_node *start, int mls) +{ + 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); } - 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"); +} + +struct te_rules_extra { + FILE *out; + int mls; +}; + +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_BLOCK: { + struct cil_block *blk = node->data; + if (blk->is_abstract == CIL_TRUE) { + *finished = CIL_TREE_SKIP_HEAD; + } break; } - case CIL_SID: - fprintf(file_arr[ISIDS], "sid %s\n", ((struct cil_symtab_datum*)current->data)->name); + case CIL_MACRO: + *finished = CIL_TREE_SKIP_HEAD; 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"); + 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; } - case CIL_POLICYCAP: - fprintf(file_arr[TYPEATTRTYPES], "policycap %s;\n", ((struct cil_symtab_datum*)current->data)->name); - break; default: break; } @@ -1103,324 +1453,482 @@ int cil_name_to_policy(FILE **file_arr, struct cil_tree_node *current) return SEPOL_OK; } -int __cil_gen_policy_node_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args) +static void cil_te_rules_to_policy(FILE *out, struct cil_tree_node *head, 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; + struct te_rules_extra args; - if (extra_args == NULL) { - return SEPOL_ERR; - } + args.out = out; + args.mls = mls; - *finished = CIL_TREE_SKIP_NOTHING; + cil_block_te_rules_to_policy(out, head, mls); + cil_tree_walk(head, __cil_te_rules_to_policy_helper, NULL, NULL, &args); +} - args = extra_args; - users = args->users; - sens = args->sens; - cats = args->cats; - file_arr = args->file_arr; +static void cil_roles_to_policy(FILE *out, struct cil_list *rules) +{ + struct cil_list_item *i1; + struct cil_role *role; - if (node->cl_head != NULL) { - if (node->flavor == CIL_MACRO) { - *finished = CIL_TREE_SKIP_HEAD; - return SEPOL_OK; - } + 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->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; +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; + 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); + } } - *finished = CIL_TREE_SKIP_HEAD; - return SEPOL_OK; } - - if (node->flavor == CIL_BLOCK && ((struct cil_block*)node->data)->is_abstract == CIL_TRUE) { - *finished = CIL_TREE_SKIP_HEAD; - return SEPOL_OK; + if (!first) { + fprintf(out, "};\n"); + first = CIL_TRUE; } + } +} - 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; +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); + } } } - } 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; - } - break; + if (!first) { + fprintf(out, ";\n"); + first = CIL_TRUE; } } +} - return SEPOL_OK; +static void cil_roleallows_to_policy(FILE *out, struct cil_list *roleallows) +{ + struct cil_list_item *i1; + struct cil_roleallow *allow; + + 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_gen_policy(struct cil_db *db) +static void cil_roletransitions_to_policy(FILE *out, struct cil_list *roletransitions) { - 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); + struct cil_list_item *i1, *i2; + struct cil_list *class_list; + struct cil_roletransition *trans; + + + 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); } - 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; + cil_list_destroy(&class_list, CIL_FALSE); + } +} + +static void cil_users_to_policy(FILE *out, int mls, struct cil_list *users, struct cil_list *all_roles) +{ + struct cil_list_item *i1, *i2; + struct cil_user *user; + struct cil_list *roles; + struct cil_role *role; + int num_roles; + + cil_list_for_each(i1, users) { + user = i1->data; + num_roles = 0; + fprintf(out, "user %s",user->datum.fqn); + cil_list_for_each(i2, all_roles) { + role = i2->data; + if (ebitmap_get_bit(user->roles, role->value)) { + if (num_roles == 0) { + cil_list_init(&roles, CIL_LIST); + } + cil_list_append(roles, CIL_ROLE, role); + num_roles++; } - fprintf(file_arr[CLASSES], "}"); } - fprintf(file_arr[CLASSES], "\n"); - } + 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); + } + if (num_roles > 1) { + fprintf(out, " }"); + } + cil_list_destroy(&roles, CIL_FALSE); + } + + if (mls == CIL_TRUE && user->dftlevel != NULL) { + fprintf(out, " level "); + cil_level_to_policy(out, user->dftlevel); + } - if (db->catorder->head != NULL) { - cil_list_for_each(item, db->catorder) { - cil_multimap_insert(cats, item->data, NULL, CIL_CAT, 0); + if (mls == CIL_TRUE && user->range != NULL) { + fprintf(out, " range "); + cil_levelrange_to_policy(out, user->range); } + + 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); +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); } - fprintf(file_arr[SENS], "};\n"); + free(expr_str); + cil_list_destroy(&classperms_strs, CIL_FALSE); } +} - extra_args.users = users; - extra_args.sens = sens; - extra_args.cats = cats; - extra_args.file_arr= file_arr; +static void cil_sid_contexts_to_policy(FILE *out, struct cil_list *sids, int mls) +{ + struct cil_list_item *i1; + struct cil_sid *sid; - 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; + 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"); } +} - 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_fsuses_to_policy(FILE *out, struct cil_sort *fsuses, int mls) +{ + int 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"); + } } - 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; 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"); + } } - rc = cil_nodecon_to_policy(file_arr, db->nodecon); - if (rc != SEPOL_OK) { - cil_log(CIL_ERR, "Error creating policy.conf\n"); - return rc; + 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"); + } } +} + +static void cil_genfscons_to_policy(FILE *out, struct cil_sort *genfscons, int mls) +{ + int i; + struct cil_genfscon *genfscon; - 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; 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"); } +} - rc = cil_pirqcon_to_policy(file_arr, db->pirqcon); - if (rc != SEPOL_OK) { - cil_log(CIL_ERR, "Error creating policy.conf\n"); - return rc; +static void cil_portcons_to_policy(FILE *out, struct cil_sort *portcons, int mls) +{ + int i; + struct cil_portcon *portcon; + + 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"); } +} - rc = cil_iomemcon_to_policy(file_arr, db->iomemcon); - if (rc != SEPOL_OK) { - cil_log(CIL_ERR, "Error creating policy.conf\n"); - return rc; +static void cil_netifcons_to_policy(FILE *out, struct cil_sort *netifcons, int mls) +{ + int i; + struct cil_netifcon *netifcon; + + 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"); } +} + +static void cil_nodecons_to_policy(FILE *out, struct cil_sort *nodecons, int mls) +{ + int i; + struct cil_nodecon *nodecon; + char *addr, *mask; + + for (i=0; icount; i++) { + nodecon = nodecons->array[i]; + fprintf(out, "nodecon "); - rc = cil_ioportcon_to_policy(file_arr, db->ioportcon); - if (rc != SEPOL_OK) { - cil_log(CIL_ERR, "Error creating policy.conf\n"); - return rc; + 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); + + 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] "); + } + 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] "); + } + 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); + } + + cil_context_to_policy(out, nodecon->context, mls); + fprintf(out, ";\n"); } +} - rc = cil_pcidevicecon_to_policy(file_arr, db->pcidevicecon); - if (rc != SEPOL_OK) { - cil_log(CIL_ERR, "Error creating policy.conf\n"); - return rc; +static void cil_pirqcons_to_policy(FILE *out, struct cil_sort *pirqcons, int mls) +{ + int i; + struct cil_pirqcon *pirqcon; + + 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"); } +} - rc = cil_userrole_to_policy(file_arr, users); - if (rc != SEPOL_OK) { - cil_log(CIL_ERR, "Error creating policy.conf\n"); - return SEPOL_ERR; +static void cil_iomemcons_to_policy(FILE *out, struct cil_sort *iomemcons, int mls) +{ + int 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"); } +} + +static void cil_ioportcons_to_policy(FILE *out, struct cil_sort *ioportcons, int mls) +{ + int i; + struct cil_ioportcon *ioportcon; - rc = cil_sens_to_policy(file_arr, sens); - if (rc != SEPOL_OK) { - cil_log(CIL_ERR, "Error creating policy.conf\n"); - return SEPOL_ERR; + 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_cat_to_policy(file_arr, cats); - if (rc != SEPOL_OK) { - cil_log(CIL_ERR, "Error creating policy.conf\n"); - return SEPOL_ERR; +static void cil_pcidevicecons_to_policy(FILE *out, struct cil_sort *pcidevicecons, int mls) +{ + int i; + struct cil_pcidevicecon *pcidevicecon; + + 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"); } +} + +static void cil_devicetreecons_to_policy(FILE *out, struct cil_sort *devicetreecons, int mls) +{ + int i; + struct cil_devicetreecon *devicetreecon; - rc = cil_combine_policy(file_arr, policy_file); - if (rc != SEPOL_OK) { - cil_log(CIL_ERR, "Error creating policy.conf\n"); - return SEPOL_ERR; + 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"); } +} - // Remove temp files +void cil_gen_policy(FILE *out, struct cil_db *db) +{ int i; - for (i=0; iast->root; + struct cil_list *lists[CIL_LIST_NUM_LISTS]; + + for (i=0; iclassorder); + + cil_sid_decls_to_policy(out, db->sidorder); + + cil_commons_to_policy(out, lists[CIL_LIST_COMMON]); + cil_classes_to_policy(out, db->classorder); + + 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); + + 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); } - free(file_arr); - - cil_list_destroy(&users, CIL_FALSE); - cil_list_destroy(&cats, CIL_FALSE); - cil_list_destroy(&sens, CIL_FALSE); - - return SEPOL_OK; + + cil_simple_rules_to_policy(out, lists[CIL_LIST_POLICYCAP], CIL_KEY_POLICYCAP); + + cil_simple_rules_to_policy(out, lists[CIL_LIST_TYPEATTRIBUTE], "attribute"); + cil_simple_rules_to_policy(out, lists[CIL_LIST_ROLEATTRIBUTE], "attribute_role"); + + cil_bools_to_policy(out, lists[CIL_LIST_BOOL]); + + cil_simple_rules_to_policy(out, lists[CIL_LIST_TYPE], "type"); + cil_typealiases_to_policy(out, lists[CIL_LIST_TYPE], lists[CIL_LIST_TYPEALIAS]); + cil_typebounds_to_policy(out, lists[CIL_LIST_TYPE]); + cil_typeattributes_to_policy(out, lists[CIL_LIST_TYPE], lists[CIL_LIST_TYPEATTRIBUTE]); + cil_te_rules_to_policy(out, head, db->mls); + + 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