2 * This file is part of MSM security plugin
3 * Greatly based on the code of MSSF security plugin
5 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
7 * Contact: Ilhan Gurel <ilhan.gurel@nokia.com>
9 * Copyright (C) 2011 - 2013 Intel Corporation.
11 * Contact: Elena Reshetova <elena.reshetova@intel.com>
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
29 #include <libxml/tree.h>
31 #include "rpmio/rpmbase64.h"
32 #include "rpmio/rpmlog.h"
33 #include "rpm/rpmfileutil.h"
34 #include <rpm/rpmmacro.h>
38 typedef enum credType_e {
39 CRED_ALLOWMATCHES = 0,
48 * @todo Problem with getting keydata
49 * @param parent XML node
50 * @param keyinfo keyinfo structure
53 static void msmHandleKeyinfo(xmlNode *parent, keyinfo_x *keyinfo)
61 xmlNode *node = xmlNewNode(NULL, BAD_CAST "keyinfo");
63 /* b64 encode keydata first */
64 if ((enc = rpmBase64Encode(keyinfo->keydata, keyinfo->keylen, -1)) != NULL) {
65 xmlAddChild(node, xmlNewText(BAD_CAST "\n"));
66 xmlAddChild(node, xmlNewText(BAD_CAST enc));
67 msmFreePointer((void**)&enc);
70 xmlAddChild(parent, node);
71 keyinfo = keyinfo->prev;
76 * Serializes ac_domain data
77 * @param parent XML node
78 * @param type Type (allow, deny,..)
79 * @param ac_domain ac_domain structure
82 static void msmHandleACDomains(xmlNode *parent, credType type,
83 ac_domain_x *ac_domain)
85 if (!ac_domain || !parent)
90 if ((type == CRED_ALLOWMATCHES) || (type == CRED_ALLOW)) {
91 node = xmlNewNode(NULL, BAD_CAST "allow");
92 } else if ((type == CRED_DENYMATCHES) || (type == CRED_DENY)) {
93 node = xmlNewNode(NULL, BAD_CAST "deny");
94 } else if (type == CRED_PROVIDE) {
101 xmlNode *childnode = xmlNewNode(NULL, BAD_CAST "ac_domain");
102 if ((type == CRED_ALLOWMATCHES) || (type == CRED_DENYMATCHES)) {
103 xmlNewProp(childnode, BAD_CAST "match", BAD_CAST ac_domain->match);
105 xmlNewProp(childnode, BAD_CAST "name", BAD_CAST ac_domain->name);
107 xmlNewProp(childnode, BAD_CAST "policy", BAD_CAST ac_domain->type);
108 if (ac_domain->plist)
109 xmlNewProp(childnode, BAD_CAST "plist", BAD_CAST ac_domain->plist);
111 xmlAddChild(node, childnode);
112 if (type == CRED_ALLOW || type == CRED_DENY)
113 ac_domain = ac_domain->hh.next;
115 ac_domain = ac_domain->prev;
118 if (type != CRED_PROVIDE)
119 xmlAddChild(parent, node);
123 * Serializes origin data
124 * @param parent XML node
125 * @param origin origin structure
128 static void msmHandleOrigin(xmlNode *parent, origin_x *origin)
134 xmlNode *node = xmlNewNode(NULL, BAD_CAST "origin");
135 xmlAddChild(parent, node);
136 msmHandleKeyinfo(node, origin->keyinfos);
137 origin = origin->prev;
142 * Serializes provides data
143 * @param parent XML node
144 * @param provide provide structure
147 static void msmHandleProvide(xmlNode *parent, provide_x *provide)
153 if (provide->ac_domains) {
154 xmlNode *node = xmlNewNode(NULL, BAD_CAST "provide");
155 xmlAddChild(parent, node);
156 msmHandleACDomains(node, CRED_PROVIDE, provide->ac_domains);
157 if (provide->origin) {
158 xmlNode *childnode = xmlNewNode(NULL, BAD_CAST "for");
159 xmlNewProp(childnode, BAD_CAST "origin", BAD_CAST provide->origin);
160 xmlAddChild(node, childnode);
163 provide = provide->prev;
168 * Serializes packages data
169 * @param parent XML node
170 * @param package package structure
173 static void msmHandlePackage(xmlNode *parent, package_x *package)
179 if (!package->newer) {
180 xmlNode *node = xmlNewNode(NULL, BAD_CAST "package");
181 xmlNewProp(node, BAD_CAST "name", BAD_CAST package->name);
182 if (package->modified)
183 xmlNewProp(node, BAD_CAST "modified", BAD_CAST package->modified);
184 xmlAddChild(parent, node);
185 msmHandleProvide(node, package->provides);
187 package = package->prev;
192 * Serializes sw source data
193 * @param parent XML node
194 * @param sw_source sw_source structure
197 static void msmHandleSWSource(xmlNode *parent, sw_source_x *sw_source)
200 xmlNode *node[MAX_DEPTH];
204 if (!sw_source || !parent)
210 depth = 1; /* recalculate depth */
211 for (temp = sw_source->parent; temp; temp = temp->parent) depth++;
212 if (!sw_source->newer && depth < MAX_DEPTH) {
213 node[depth] = xmlNewNode(NULL, BAD_CAST "sw_source");
214 xmlNewProp(node[depth], BAD_CAST "name", BAD_CAST sw_source->name);
215 xmlNewProp(node[depth], BAD_CAST "rankkey", BAD_CAST sw_source->rankkey);
216 xmlAddChild(node[depth-1], node[depth]);
217 msmHandleOrigin(node[depth], sw_source->origins);
218 msmHandleACDomains(node[depth], CRED_ALLOWMATCHES, sw_source->allowmatches);
219 msmHandleACDomains(node[depth], CRED_ALLOW, sw_source->allows);
220 msmHandleACDomains(node[depth], CRED_DENYMATCHES, sw_source->denymatches);
221 msmHandleACDomains(node[depth], CRED_DENY, sw_source->denys);
222 msmHandlePackage(node[depth], sw_source->packages);
223 if (sw_source->older) {
224 /* packages still belong to this sw_source */
225 msmHandlePackage(node[depth], sw_source->older->packages);
228 sw_source = sw_source->next;
233 * Saves sw_source configuration into /etc/dev-sec-policy.
234 * @param mfx data to serialize
235 * @return RPMRC_OK or RPMRC_FAIL
237 rpmRC msmSaveDeviceSecPolicyXml(manifest_x *mfx, const char *rootDir)
241 char *fullPath = NULL;
243 fullPath = rpmGenPath(rootDir, DEVICE_SECURITY_POLICY, NULL);
244 rpmlog(RPMLOG_DEBUG, "fullPath %s\n", fullPath);
246 rpmlog(RPMLOG_ERR, "Building a full path failed for device security policy\n");
250 /* if data doesn't have sw_source information, no need to do anything */
251 if (mfx && mfx->sw_sources) {
252 sw_source_x *sw_source;
253 xmlDoc *doc = xmlNewDoc( BAD_CAST "1.0");
254 xmlNode *rootnode = xmlNewNode(NULL, BAD_CAST "config");
255 xmlDocSetRootElement(doc, rootnode);
257 LISTHEAD(mfx->sw_sources, sw_source);
258 msmHandleSWSource(rootnode, sw_source);
260 outFile = fopen(fullPath, "w");
262 xmlElemDump(outFile, doc, rootnode);
265 rpmlog(RPMLOG_ERR, "Unable to write device security policy to %s\n",
267 msmFreePointer((void**)&fullPath);
274 msmFreePointer((void**)&fullPath);
280 * @param old_filename old file name
281 * @param new_filename new file name
282 * @return result of copy or -1 on failure
284 static int copyFile(char *old_filename, char *new_filename)
286 FD_t ptr_old, ptr_new;
289 ptr_old = Fopen(old_filename, "r.fdio");
290 ptr_new = Fopen(new_filename, "w.fdio");
292 if ((ptr_old == NULL) || (Ferror(ptr_old))) {
296 if ((ptr_new == NULL) || (Ferror(ptr_new))) {
301 res = ufdCopy(ptr_old, ptr_new);
309 * Loads device security policy.
310 * @param rootDir --root rpm optional prefix
311 * @param dsp pointer to the loaded policy
312 * @return RPMRC_OK or RPMRC_FAIL
314 rpmRC msmLoadDeviceSecurityPolicy(const char* rootDir, manifest_x **dsp)
316 char *dspFullPath = NULL, *dspFullPathDir = NULL;
317 char *defaultdspPath = NULL;
320 dspFullPath = rpmGenPath(rootDir, (const char*)DEVICE_SECURITY_POLICY, NULL);
321 rpmlog(RPMLOG_DEBUG, "Device Security policy full path %s\n", dspFullPath);
323 rpmlog(RPMLOG_ERR, "Building a full path failed for the device security policy\n");
327 if (stat(dspFullPath, &buf) != 0) { // the policy file is missing
328 if (rootDir) { // we are running with --root option and policy is missing, need to copy it for now
329 // first create prefix for it
330 char *sysconfdir = rpmExpand((const char*)"%{?_sysconfdir}", NULL);
331 if (!sysconfdir || !strcmp(sysconfdir, "")) {
332 rpmlog(RPMLOG_ERR, "Failed to expand %%_sysconfdir macro\n");
336 dspFullPathDir = rpmGenPath(rootDir, sysconfdir, NULL);
337 rpmlog(RPMLOG_DEBUG, "Device Security policy full path dir %s\n", dspFullPathDir);
338 msmFreePointer((void**)&sysconfdir);
339 if (!dspFullPathDir) {
340 rpmlog(RPMLOG_ERR, "Building a full path for the device security policy dir failed\n");
343 if (rpmioMkpath(dspFullPathDir, 0755, getuid(), getgid()) != 0) {
344 rpmlog(RPMLOG_ERR, "Failed to create a path for the device security policy dir\n");
347 defaultdspPath = rpmExpand((const char*)"%{?__transaction_msm_default_policy}", NULL);
348 if (!defaultdspPath || !strcmp(defaultdspPath, "")) {
349 rpmlog(RPMLOG_ERR, "Failed to expand transaction_msm_default_policy macro\n");
352 if(copyFile(defaultdspPath, dspFullPath) == -1) {
353 /* Do not allow plug-in to proceed without security policy existing */
354 rpmlog(RPMLOG_ERR, "Failed to copy the device security policy to the chroot environment\n");
358 /* Do not allow plug-in to proceed without security policy existing */
359 rpmlog(RPMLOG_ERR, "Policy file is missing at %s\n",
365 rpmlog(RPMLOG_DEBUG, "reading the device security policy from %s\n", dspFullPath);
366 *dsp = msmProcessDevSecPolicyXml(dspFullPath);
369 rpmlog(RPMLOG_ERR, "Failed to process sw sources from %s\n", dspFullPath);
372 if (msmSetupSWSources(NULL, *dsp, NULL)) {
373 rpmlog(RPMLOG_ERR, "Failed to setup the device security policy from %s\n", dspFullPath);
381 msmFreePointer((void**)&dspFullPath);
382 msmFreePointer((void**)&dspFullPathDir);
383 msmFreePointer((void**)&defaultdspPath);
388 * Creates a directory for the smack rules.
389 * @param rootDir --root rpm optional prefix
390 * @return RPMRC_OK or RPMRC_FAIL
392 rpmRC msmSetupSmackRulesDir(const char* rootDir)
394 char *smackRulesFullPath = NULL;
395 rpmRC res = RPMRC_FAIL;
397 smackRulesFullPath = rpmGenPath(rootDir, SMACK_RULES_PATH, NULL);
398 rpmlog(RPMLOG_DEBUG, "smackRulesFullPath for SMACK_RULES_PATH %s\n", smackRulesFullPath);
400 if (!smackRulesFullPath){
401 rpmlog(RPMLOG_ERR, "Building a full path failed for smack rules path\n");
405 if (rpmioMkpath(smackRulesFullPath, 0744, getuid(), getgid()) != 0) {
406 rpmlog(RPMLOG_ERR, "Failed to create a directory for smack rules\n");
411 msmFreePointer((void**)&smackRulesFullPath);