Modify eu-strip option to perform strip in post script of rpm package & add option...
[platform/upstream/rpm.git] / plugins / msmconfig.c
1 /*
2  * This file is part of MSM security plugin
3  * Greatly based on the code of MSSF security plugin
4  *
5  * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
6  *
7  * Contact: Ilhan Gurel <ilhan.gurel@nokia.com>
8  *
9  * Copyright (C) 2011 - 2013 Intel Corporation.
10  *
11  * Contact: Elena Reshetova <elena.reshetova@intel.com>
12  *
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.
17  *
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.
22  *
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
26  * 02110-1301 USA
27  */
28
29 #include <libxml/tree.h>
30
31 #include "rpmio/rpmbase64.h"
32 #include "rpmio/rpmlog.h"
33 #include "rpm/rpmfileutil.h"
34 #include <rpm/rpmmacro.h>
35
36 #include "msm.h"
37
38 typedef enum credType_e {
39     CRED_ALLOWMATCHES  = 0,
40     CRED_ALLOW         = 1,
41     CRED_DENYMATCHES   = 2,
42     CRED_DENY          = 3,
43     CRED_PROVIDE       = 4
44 } credType;
45
46 /**
47  * Serializes key data
48  * @todo Problem with getting keydata
49  * @param parent        XML node
50  * @param keyinfo       keyinfo structure
51  * @return              none
52  */
53 static void msmHandleKeyinfo(xmlNode *parent, keyinfo_x *keyinfo)
54 {    
55     char *enc = NULL;
56
57     if (!parent)
58         return;
59     
60     while (keyinfo) {
61         xmlNode *node = xmlNewNode(NULL, BAD_CAST "keyinfo");
62
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);   
68         }
69
70         xmlAddChild(parent, node);
71         keyinfo = keyinfo->prev;
72     }
73 }
74
75 /**
76  * Serializes ac_domain data
77  * @param parent        XML node
78  * @param type      Type (allow, deny,..)
79  * @param ac_domain     ac_domain structure
80  * @return                  none
81  */
82 static void msmHandleACDomains(xmlNode *parent, credType type, 
83                                   ac_domain_x *ac_domain)
84 {
85     if (!ac_domain || !parent)
86         return;
87
88     xmlNode *node = NULL;
89
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) {
95         node = parent;
96     } else {
97         return;    
98     }
99
100     while (ac_domain) {
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);
104         } else {
105             xmlNewProp(childnode, BAD_CAST "name", BAD_CAST ac_domain->name);
106             if (ac_domain->type)
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);
110         }
111         xmlAddChild(node, childnode);
112         if (type == CRED_ALLOW || type == CRED_DENY)
113             ac_domain = ac_domain->hh.next;
114         else
115             ac_domain = ac_domain->prev;
116     }
117
118     if (type != CRED_PROVIDE)
119             xmlAddChild(parent, node);
120 }
121
122 /**
123  * Serializes origin data
124  * @param parent        XML node
125  * @param origin        origin structure
126  * @return                  none
127  */
128 static void msmHandleOrigin(xmlNode *parent, origin_x *origin)
129 {    
130     if (!parent)
131         return;
132     
133     while (origin) {
134         xmlNode *node = xmlNewNode(NULL, BAD_CAST "origin");
135         xmlAddChild(parent, node);
136         msmHandleKeyinfo(node, origin->keyinfos);
137         origin = origin->prev;
138     }
139 }
140
141 /**
142  * Serializes provides data
143  * @param parent        XML node
144  * @param provide       provide structure
145  * @return                  none
146  */
147 static void msmHandleProvide(xmlNode *parent, provide_x *provide)
148 {    
149     if (!parent)
150         return;     
151
152     while (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);
161             }
162         }
163         provide = provide->prev;
164     }
165 }
166
167 /**
168  * Serializes packages data
169  * @param parent        XML node
170  * @param package       package structure
171  * @return              none
172  */
173 static void msmHandlePackage(xmlNode *parent, package_x *package)
174 {    
175     if (!parent)
176         return; 
177
178     while (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);
186         }
187         package = package->prev;
188     }
189 }
190
191 /**
192  * Serializes sw source data
193  * @param parent        XML node
194  * @param sw_source     sw_source structure
195  * @return                  none
196  */
197 static void msmHandleSWSource(xmlNode *parent, sw_source_x *sw_source)
198 {
199     #define MAX_DEPTH 10
200     xmlNode *node[MAX_DEPTH];
201     sw_source_x *temp;
202     int depth = 0;
203
204     if (!sw_source || !parent)
205         return;
206
207     node[0] = parent;
208
209     while (sw_source) {
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);
226             }
227         }
228         sw_source = sw_source->next;
229     }
230 }
231
232 /**
233  * Saves sw_source configuration into /etc/dev-sec-policy.
234  * @param mfx           data to serialize
235  * @return              RPMRC_OK or RPMRC_FAIL
236  */
237 rpmRC msmSaveDeviceSecPolicyXml(manifest_x *mfx, const char *rootDir)
238 {    
239     FILE *outFile;
240     rpmRC rc = RPMRC_OK;
241     char *fullPath = NULL;
242
243     fullPath = rpmGenPath(rootDir, DEVICE_SECURITY_POLICY, NULL);
244     rpmlog(RPMLOG_DEBUG, "fullPath %s\n", fullPath);
245     if (!fullPath) {
246         rpmlog(RPMLOG_ERR, "Building a full path failed for device security policy\n");
247         return RPMRC_FAIL;
248     }
249
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);
256
257         LISTHEAD(mfx->sw_sources, sw_source);   
258         msmHandleSWSource(rootnode, sw_source);
259
260         outFile = fopen(fullPath, "w");
261         if (outFile) {
262             xmlElemDump(outFile, doc, rootnode);
263             fclose(outFile);
264         } else {
265             rpmlog(RPMLOG_ERR, "Unable to write device security policy to %s\n",
266                    fullPath);
267             msmFreePointer((void**)&fullPath);
268             rc = RPMRC_FAIL;
269         }
270         xmlFreeDoc(doc);
271         xmlCleanupParser();
272     }
273
274     msmFreePointer((void**)&fullPath);
275     return rc;
276 }
277
278 /**
279  * Copies a file
280  * @param old_filename  old file name
281  * @param new_filename  new file name
282  * @return              result of copy or -1 on failure
283  */
284 static int copyFile(char *old_filename, char  *new_filename)
285 {
286     FD_t ptr_old, ptr_new;
287     int res;
288
289     ptr_old = Fopen(old_filename, "r.fdio");
290     ptr_new = Fopen(new_filename, "w.fdio");
291
292     if ((ptr_old == NULL) || (Ferror(ptr_old))) {
293         return  -1;
294     }
295
296     if ((ptr_new == NULL) || (Ferror(ptr_new))) {
297         Fclose(ptr_old);
298         return  -1;
299     }
300
301     res = ufdCopy(ptr_old, ptr_new);
302
303     Fclose(ptr_new);
304     Fclose(ptr_old);
305     return res;
306 }
307
308 /**
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
313  */
314 rpmRC msmLoadDeviceSecurityPolicy(const char* rootDir, manifest_x **dsp)
315 {
316     char *dspFullPath = NULL, *dspFullPathDir = NULL;
317     char *defaultdspPath = NULL;
318     struct stat buf;
319
320     dspFullPath = rpmGenPath(rootDir, (const char*)DEVICE_SECURITY_POLICY, NULL);
321     rpmlog(RPMLOG_DEBUG, "Device Security policy full path %s\n", dspFullPath);
322     if (!dspFullPath) {
323         rpmlog(RPMLOG_ERR, "Building a full path failed for the device security policy\n");
324         goto ldsp_error;
325     }
326
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");
333                 goto ldsp_error;
334             }
335
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");
341                 goto ldsp_error;
342             }
343             if (rpmioMkpath(dspFullPathDir, 0755, getuid(), getgid()) != 0) {
344                     rpmlog(RPMLOG_ERR, "Failed to create a path for the device security policy dir\n");
345                     goto ldsp_error;
346             }
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");
350                 goto ldsp_error;
351             }
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");
355                 goto ldsp_error;
356             }
357         } else {
358             /* Do not allow plug-in to proceed without security policy existing */
359             rpmlog(RPMLOG_ERR, "Policy file is missing at %s\n",
360                    dspFullPath);
361             goto ldsp_error;
362         }
363     }
364
365     rpmlog(RPMLOG_DEBUG, "reading the device security policy from %s\n", dspFullPath);
366     *dsp = msmProcessDevSecPolicyXml(dspFullPath);
367
368     if (!*dsp) {
369         rpmlog(RPMLOG_ERR, "Failed to process sw sources from %s\n", dspFullPath);
370         goto ldsp_error;
371     } else {
372         if (msmSetupSWSources(NULL, *dsp, NULL)) {
373             rpmlog(RPMLOG_ERR, "Failed to setup the device security policy from %s\n", dspFullPath);
374             goto ldsp_error;
375         }
376     }
377
378     return RPMRC_OK;
379
380 ldsp_error:
381     msmFreePointer((void**)&dspFullPath);
382     msmFreePointer((void**)&dspFullPathDir);
383     msmFreePointer((void**)&defaultdspPath);
384     return RPMRC_FAIL;
385 }
386
387 /**
388  * Creates a directory for the smack rules. 
389  * @param rootDir       --root rpm optional prefix
390  * @return              RPMRC_OK or RPMRC_FAIL
391  */
392 rpmRC msmSetupSmackRulesDir(const char* rootDir)
393 {
394     char *smackRulesFullPath = NULL;
395     rpmRC res = RPMRC_FAIL;
396
397     smackRulesFullPath = rpmGenPath(rootDir, SMACK_RULES_PATH, NULL);
398     rpmlog(RPMLOG_DEBUG, "smackRulesFullPath for SMACK_RULES_PATH %s\n", smackRulesFullPath);
399
400     if (!smackRulesFullPath){
401         rpmlog(RPMLOG_ERR, "Building a full path failed for smack rules path\n");
402         return res;
403     }
404
405     if (rpmioMkpath(smackRulesFullPath, 0744, getuid(), getgid()) != 0) {
406         rpmlog(RPMLOG_ERR, "Failed to create a directory for smack rules\n");
407     } else {
408         res = RPMRC_OK;
409     }
410
411     msmFreePointer((void**)&smackRulesFullPath);
412     return res;
413 }
414