Security plugin: adding support for l access type
[platform/upstream/rpm.git] / plugins / msmmanifest.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: Tero Aho <ext-tero.aho@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 <stdio.h>
30 #include <stdlib.h>
31 #include <stdarg.h>
32 #include <string.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <unistd.h>
36
37 #include <libxml/xmlreader.h>
38 #include <sys/capability.h>
39
40 #include "msm.h"
41
42 #include "rpmio/rpmbase64.h"
43 #include "rpmio/rpmlog.h"
44
45 /* We'll support only the basic set of characters */
46 #define ASCII(s) (const char *)s
47 #define XMLCHAR(s) (const xmlChar *)s
48
49 static int msmVerifyAccessType(const char* type)
50 {
51     int res = 0, idx = 0;
52
53     if (type) {
54         if (strlen(type) > SMACK_ACCESS_TYPE_LENGHT) {
55             rpmlog(RPMLOG_ERR, "Lenght of the access type is bigger than allowed value: %s\n", type);
56             return -1;
57         }
58         while ( type[idx] != '\0' ){
59             if ((type[idx] !='a') && (type[idx]!='r') && (type[idx]!='w') &&
60                 (type[idx]!='x') && (type[idx]!='t') && (type[idx]!='l') && (type[idx] !='-')) {
61                 rpmlog(RPMLOG_ERR, "Not allowed character in access type: %s\n", type);
62                 res = -1;
63                 break;
64             }
65             idx++;
66         }
67     } else return -1; 
68
69     return res;
70 }
71
72 static int msmVerifySmackLabel(const char* label)
73 {
74     int res = 0, idx = 0;
75
76     if (label) {
77         if (strlen(ASCII(label)) > SMACK_LABEL_LENGTH) { //smack limitation on lenght
78             rpmlog(RPMLOG_ERR, "Domain or label name  %s lenght is longer than defined SMACK_LABEL_LENGTH\n", label);
79             return -1; 
80         }
81         if (strlen(ASCII(label)) == 0){
82             rpmlog(RPMLOG_ERR, "An attempt to define an empty domain or label name\n");
83             return -1; 
84         }
85         if (label[0] == '-') {
86             rpmlog(RPMLOG_ERR, "Dash is not allowed as first character in smack label: %s\n", label);
87             return -1;
88         }
89         while ( label[idx] != '\0' ){
90             if ((label[idx] =='\"') || (label[idx] =='\'') || (label[idx] =='/') ||
91                 (label[idx] =='\\') || (label[idx] > '~') || (label[idx] <= ' ')) {
92                 rpmlog(RPMLOG_ERR, "Not allowed character in smack label: %s, position: %d \n", label, idx);
93                 res = -1;
94                 break;
95             }
96             idx++;
97         }
98     } else return -1; 
99
100     return res;
101 }
102
103 static int msmVerifyLabelPrefix(const char* sub_label, const char* domain_name) 
104 {
105     char *tmp = NULL;
106     char sep[]= "::";
107
108     tmp = calloc(strlen(domain_name) + 3, sizeof (const char));
109     if (!tmp) 
110         return -1;
111
112     strncpy(tmp, domain_name, strlen(domain_name));
113     strncpy(tmp + strlen(domain_name), sep, 2);
114
115     if (strstr(ASCII(sub_label), tmp) != ASCII(sub_label)) { //sub label name should be prefixed by domain name and "::"
116         rpmlog(RPMLOG_ERR, "Label name %s isn't prefixed by domain name %s\n", ASCII(sub_label), domain_name);
117         msmFreePointer((void**)&tmp);
118         return -1;
119     } 
120
121     msmFreePointer((void**)&tmp);
122     return 0;
123 }
124
125 static int msmNextChildElement(xmlTextReaderPtr reader, int depth) 
126 {
127     int ret = xmlTextReaderRead(reader);
128     int cur = xmlTextReaderDepth(reader);
129     while (ret == 1) {
130         /* rpmlog(RPMLOG_DEBUG, "node %s %d\n", 
131            ASCII(xmlTextReaderConstName(reader)), 
132            xmlTextReaderDepth(reader));
133         */
134         switch (xmlTextReaderNodeType(reader)) {
135         case XML_READER_TYPE_ELEMENT:
136         case XML_READER_TYPE_TEXT:
137             if (cur == depth+1) 
138                 return 1;
139             break;
140         case XML_READER_TYPE_END_ELEMENT:
141             if (cur == depth) 
142                 return 0;
143             break;
144         default:
145             if (cur <= depth)
146                 return 0;
147             break;
148         }
149         ret = xmlTextReaderRead(reader);
150         cur = xmlTextReaderDepth(reader);
151     }
152     return ret;
153 }
154
155 static ac_domain_x *msmFreeACDomain(ac_domain_x *ac_domain)
156 {
157     if (ac_domain) {
158         ac_domain_x *prev = ac_domain->prev;
159         msmFreePointer((void**)&ac_domain->name);
160         msmFreePointer((void**)&ac_domain->type);
161         msmFreePointer((void**)&ac_domain->match);
162         msmFreePointer((void**)&ac_domain->plist);
163         msmFreePointer((void**)&ac_domain);
164         return prev;
165     } else return NULL;
166 }
167
168 static annotation_x *msmProcessAnnotation(xmlTextReaderPtr reader)
169 {
170     const xmlChar *name, *value;
171
172     name = xmlTextReaderGetAttribute(reader, XMLCHAR("name"));
173     value = xmlTextReaderGetAttribute(reader, XMLCHAR("value"));
174     rpmlog(RPMLOG_DEBUG, "annotation %s %s\n", ASCII(name), ASCII(value));
175
176     if (name && value) {
177         annotation_x *annotation = calloc(1, sizeof(annotation_x));
178         if (annotation) {
179             annotation->name = ASCII(name);
180             annotation->value = ASCII(value);
181             return annotation;
182         }
183     }
184     msmFreePointer((void**)&name);
185     msmFreePointer((void**)&value);
186     return NULL;
187 }
188
189 static int msmProcessMember(xmlTextReaderPtr reader, member_x *member) 
190 {
191     const xmlChar *node, *name;
192     int ret, depth;
193
194     name = xmlTextReaderGetAttribute(reader, XMLCHAR("name"));
195     rpmlog(RPMLOG_DEBUG, "member %s\n", ASCII(name));
196     member->name = ASCII(name);
197
198     if (!name) return -1;
199
200     depth = xmlTextReaderDepth(reader);
201     while ((ret = msmNextChildElement(reader, depth))) {
202         node = xmlTextReaderConstName(reader);
203         if (!node) return -1;
204
205         if (!strcmp(ASCII(node), "annotation")) {
206             annotation_x *annotation = msmProcessAnnotation(reader);
207             if (annotation) {
208                 member->annotation = annotation;
209             } else return -1;
210         } else return -1;
211
212         if (ret < 0) return -1;
213     }
214     return ret;
215 }
216
217 static int msmProcessInterface(xmlTextReaderPtr reader, interface_x *interface) 
218 {
219     const xmlChar *node, *name;
220     int ret, depth;
221
222     name = xmlTextReaderGetAttribute(reader, XMLCHAR("name"));
223     rpmlog(RPMLOG_DEBUG, "interface %s\n", ASCII(name));
224     interface->name = ASCII(name);
225
226     if (!name) return -1;
227
228     depth = xmlTextReaderDepth(reader);
229     while ((ret = msmNextChildElement(reader, depth))) {
230         node = xmlTextReaderConstName(reader);
231         if (!node) return -1;
232
233         if (!strcmp(ASCII(node), "method")) {
234             member_x *member = calloc(1, sizeof(member_x));
235             if (member) {
236                 member->type = DBUS_METHOD;
237                 ret = msmProcessMember(reader, member);
238                 LISTADD(interface->members, member);
239             } else return -1;
240         } else if (!strcmp(ASCII(node), "signal")) {
241             member_x *member = calloc(1, sizeof(member_x));
242             if (member) {
243                 member->type = DBUS_SIGNAL;
244                 ret = msmProcessMember(reader, member);
245                 LISTADD(interface->members, member);
246             } else return -1;
247         } else if (!strcmp(ASCII(node), "annotation")) {
248             annotation_x *annotation = msmProcessAnnotation(reader);
249             if (annotation) {
250                 interface->annotation = annotation;
251             } else return -1;
252         } else return -1;
253
254         if (ret < 0) return -1;
255     }
256     return ret;
257 }
258
259 static int msmProcessNode(xmlTextReaderPtr reader, node_x *nodex) 
260 {
261     const xmlChar *node, *name;
262     int ret, depth;
263
264     name = xmlTextReaderGetAttribute(reader, XMLCHAR("name"));
265     rpmlog(RPMLOG_DEBUG, "node %s\n", ASCII(name));
266     nodex->name = ASCII(name);
267
268     if (!name) return -1;
269
270     depth = xmlTextReaderDepth(reader);
271     while ((ret = msmNextChildElement(reader, depth))) {
272         node = xmlTextReaderConstName(reader);
273         if (!node) return -1;
274
275         if (!strcmp(ASCII(node), "interface")) {
276             interface_x *interface = calloc(1, sizeof(interface_x));
277             if (interface) {
278                 ret = msmProcessInterface(reader, interface);
279                 LISTADD(nodex->interfaces, interface);
280             } else return -1;
281         } else if (!strcmp(ASCII(node), "method")) {
282             member_x *member = calloc(1, sizeof(member_x));
283             if (member) {
284                 member->type = DBUS_METHOD;
285                 ret = msmProcessMember(reader, member);
286                 LISTADD(nodex->members, member);
287             } else return -1;
288         } else if (!strcmp(ASCII(node), "signal")) {
289             member_x *member = calloc(1, sizeof(member_x));
290             if (member) {
291                 member->type = DBUS_SIGNAL;
292                 ret = msmProcessMember(reader, member);
293                 LISTADD(nodex->members, member);
294             } else return -1;
295         } else if (!strcmp(ASCII(node), "annotation")) {
296             annotation_x *annotation = msmProcessAnnotation(reader);
297             if (annotation) {
298                 nodex->annotation = annotation;
299             } else return -1;
300         } else return -1;
301
302         if (ret < 0) return -1;
303     }
304     return ret;
305 }
306
307 static int msmProcessDBus(xmlTextReaderPtr reader, dbus_x *dbus) 
308 {
309     const xmlChar *node, *name, *own, *bus;
310     int ret, depth;
311
312     name = xmlTextReaderGetAttribute(reader, XMLCHAR("name"));
313     own = xmlTextReaderGetAttribute(reader, XMLCHAR("own"));
314     bus = xmlTextReaderGetAttribute(reader, XMLCHAR("bus"));
315     rpmlog(RPMLOG_DEBUG, "dbus %s %s %s\n", ASCII(name), ASCII(own), ASCII(bus));
316     dbus->name = ASCII(name);
317     dbus->own = ASCII(own);
318     dbus->bus = ASCII(bus);    
319
320     if (!name || !bus) return -1;
321     if (strcmp(dbus->bus, "session") && strcmp(dbus->bus, "system"))
322         return -1;
323
324     depth = xmlTextReaderDepth(reader);
325     while ((ret = msmNextChildElement(reader, depth))) {
326         node = xmlTextReaderConstName(reader);
327         if (!node) return -1;
328
329         if (!strcmp(ASCII(node), "node")) {
330             node_x *nodex = calloc(1, sizeof(node_x));
331             if (nodex) {
332                 ret = msmProcessNode(reader, nodex);
333                 LISTADD(dbus->nodes, nodex);
334             } else return -1;
335         } else if (!strcmp(ASCII(node), "annotation")) {
336             annotation_x *annotation = msmProcessAnnotation(reader);
337             if (annotation) {
338                 dbus->annotation = annotation;
339             } else return -1;
340         } else return -1;
341
342         if (ret < 0) return -1;
343     }
344     return ret;
345 }
346
347 static ac_domain_x *msmProcessACDomain(xmlTextReaderPtr reader, sw_source_x *sw_source, const char* pkg_name)
348 {
349     const xmlChar *name, *match, *policy, *plist;
350
351     name = xmlTextReaderGetAttribute(reader, XMLCHAR("name"));
352     match = xmlTextReaderGetAttribute(reader, XMLCHAR("match"));
353     policy = xmlTextReaderGetAttribute(reader, XMLCHAR("policy"));
354     plist = xmlTextReaderGetAttribute(reader, XMLCHAR("plist"));
355     rpmlog(RPMLOG_DEBUG, "ac_domain %s match %s policy %s plist %s\n", ASCII(name), ASCII(match), ASCII(policy), ASCII(plist));
356
357     if (!((!name && !match) || (name && match))) {
358         ac_domain_x *ac_domain = calloc(1, sizeof(ac_domain_x));
359         if (ac_domain) {
360             ac_domain->name = ASCII(name);
361             ac_domain->match = ASCII(match);
362             ac_domain->type = ASCII(policy);
363             ac_domain->plist = ASCII(plist);
364             ac_domain->sw_source = sw_source;
365             ac_domain->pkg_name = pkg_name;     
366             return ac_domain;
367         }
368     }
369     rpmlog(RPMLOG_ERR, "Mandatory argument is missing for ac domain definition\n");
370     rpmlog(RPMLOG_ERR, "ac_domain %s match %s policy %s plist %s\n", ASCII(name), ASCII(match), ASCII(policy), ASCII(plist));
371     msmFreePointer((void**)&name);
372     msmFreePointer((void**)&match);
373     msmFreePointer((void**)&policy);
374     msmFreePointer((void**)&plist);
375     return NULL;
376 }
377
378 static filesystem_x *msmProcessFilesystem(xmlTextReaderPtr reader)
379 {
380     const xmlChar *path, *label, *type, *exec_label;
381
382     path = xmlTextReaderGetAttribute(reader, XMLCHAR("path"));
383     label = xmlTextReaderGetAttribute(reader, XMLCHAR("label"));
384     exec_label = xmlTextReaderGetAttribute(reader, XMLCHAR("exec_label"));
385     type = xmlTextReaderGetAttribute(reader, XMLCHAR("type"));
386
387     rpmlog(RPMLOG_DEBUG, "filesystem path %s label %s exec label %s type %s\n", 
388            ASCII(path), ASCII(label), ASCII(exec_label), ASCII(type));
389
390    if (path && (label || exec_label)) {
391         if ((label) && (msmVerifySmackLabel(ASCII(label)) < 0)) {
392             goto fail;
393         }
394         if ((exec_label) && (msmVerifySmackLabel(ASCII(exec_label)) < 0)) {
395             goto fail;
396         }
397
398         filesystem_x *filesystem = calloc(1, sizeof(filesystem_x));
399         if (filesystem) {
400             filesystem->path = ASCII(path);
401             filesystem->label = ASCII(label);
402             filesystem->exec_label = ASCII(exec_label);
403             filesystem->type = ASCII(type);
404             return filesystem;
405         }
406
407     } else {
408         rpmlog(RPMLOG_ERR, "Mandatory argument is missing for filesystem assign request\n");
409         rpmlog(RPMLOG_ERR, "filesystem path %s label %s exec label %s\n", 
410                ASCII(path), ASCII(label), ASCII(exec_label));
411     }
412
413 fail:
414     msmFreePointer((void**)&path);
415     msmFreePointer((void**)&label);
416     msmFreePointer((void**)&exec_label);
417     msmFreePointer((void**)&type);
418     return NULL;
419 }
420
421 static int msmProcessProvide(xmlTextReaderPtr reader, provide_x *provide, sw_source_x *current, manifest_x *mfx, const char* pkg_name)
422 {
423     const xmlChar *node, *name, *origin;
424     int ret, depth;
425
426     name = xmlTextReaderGetAttribute(reader, XMLCHAR("name"));
427     rpmlog(RPMLOG_DEBUG, "assign %s\n", ASCII(name));
428     provide->name = ASCII(name);
429
430     if (provide->name && 
431        (strcmp(provide->name, "_system_") || mfx->sw_source->parent))
432         return -1; /* only _system_ is accepted from root sw source */
433
434     depth = xmlTextReaderDepth(reader);
435     while ((ret = msmNextChildElement(reader, depth))) {
436         node = xmlTextReaderConstName(reader);
437         if (!node) return -1;
438
439         if (!strcmp(ASCII(node), "dbus")) {
440             dbus_x *dbus = calloc(1, sizeof(dbus_x));
441             if (dbus) {
442                 ret = msmProcessDBus(reader, dbus);
443                 LISTADD(provide->dbuss, dbus);
444             } else return -1;
445         } else if (!strcmp(ASCII(node), "ac_domain")) {
446             ac_domain_x *ac_domain = msmProcessACDomain(reader, current, pkg_name);
447             if (ac_domain) {
448                 const char *name = ac_domain->name;
449                 LISTADD(provide->ac_domains, ac_domain);
450                 if (!name) return -1;
451                 if (mfx && !provide->name) {
452                     ac_domain->name = malloc(strlen(mfx->name) + 2 +
453                                               strlen(name) + 1);
454                     sprintf((char *)ac_domain->name, "%s::%s", mfx->name, name);
455                     msmFreePointer((void**)&name);
456                 }
457             } else return -1;
458
459        } else if (!strcmp(ASCII(node), "for")) {
460             origin = xmlTextReaderGetAttribute(reader, XMLCHAR("origin"));
461             rpmlog(RPMLOG_DEBUG, "for %s\n", ASCII(origin));
462             if (!origin) return -1;
463             if (provide->origin) { 
464                 msmFreePointer((void**)&origin);
465                 return -1;
466             }
467             provide->origin = ASCII(origin);
468             if (strcmp(ASCII(origin), "trusted") && 
469                 strcmp(ASCII(origin), "current") &&
470                 strcmp(ASCII(origin), "all"))
471                 return -1;
472
473         } else if (!strcmp(ASCII(node), "filesystem")) {
474             filesystem_x *filesystem = msmProcessFilesystem(reader);
475             if (filesystem) {
476                 LISTADD(provide->filesystems, filesystem);
477             } else return -1;
478
479         } else {
480             rpmlog(RPMLOG_ERR, "No allowed element in assign section: %s\n", ASCII(node));
481             return -1;
482         }
483
484         if (ret < 0) return ret;
485     }
486
487     return ret;
488 }
489
490 static int msmProcessPackage(xmlTextReaderPtr reader, package_x *package, sw_source_x *current)
491 {
492     const xmlChar *node, *name, *modified;
493     int ret, depth;
494
495     /* config processing */
496     name = xmlTextReaderGetAttribute(reader, XMLCHAR("name"));
497     modified = xmlTextReaderGetAttribute(reader, XMLCHAR("modified"));
498     rpmlog(RPMLOG_DEBUG, "package %s %s\n", name, modified);
499
500     package->name = ASCII(name);
501     package->modified = ASCII(modified);
502     package->sw_source = current;
503
504     depth = xmlTextReaderDepth(reader);
505     while ((ret = msmNextChildElement(reader, depth))) {
506         node = xmlTextReaderConstName(reader);
507         if (!node) return -1;
508
509         if (!strcmp(ASCII(node), "provide")) {
510             provide_x *provide = calloc(1, sizeof(provide_x));
511             if (provide) {
512                 LISTADD(package->provides, provide);
513                 ret = msmProcessProvide(reader, provide, current, NULL, package->name);
514             } else return -1;
515         } else return -1;
516
517         if (ret < 0) return ret;
518     }
519     return ret;
520 }
521
522 static int msmProcessRequest(xmlTextReaderPtr reader, request_x *request) 
523 {
524     const xmlChar *node, *name;
525     int ret, depth, requestPresent = 0;
526
527     rpmlog(RPMLOG_DEBUG, "request \n");
528     depth = xmlTextReaderDepth(reader);
529     while ((ret = msmNextChildElement(reader, depth))) {
530         node = xmlTextReaderConstName(reader);
531         if (!node) return -1;
532
533         if (!strcmp(ASCII(node), "domain")) {
534             if (requestPresent) {
535                 rpmlog(RPMLOG_ERR, "A second domain defined inside a request section. Abort package installation\n");
536                 return -1;
537             }
538             name = xmlTextReaderGetAttribute(reader, XMLCHAR("name"));   
539             rpmlog(RPMLOG_DEBUG, "ac domain name %s\n", ASCII(name));
540             if (name) {
541                 request->ac_domain = ASCII(name);
542                 requestPresent = 1;
543             } else {
544                 rpmlog(RPMLOG_ERR, "No ac domain name defined in request.\n");
545                 return -1;
546             }
547         } else {
548             rpmlog(RPMLOG_ERR, "Not allowed element in request section: %s\n", ASCII(node));
549             return -1;
550         }
551     }
552     return ret;
553 }
554
555 static int msmProcessDRequest(xmlTextReaderPtr reader, define_x *define) 
556 {
557     const xmlChar *node = NULL, *label = NULL, *type = NULL;
558     int ret, depth;
559
560     rpmlog(RPMLOG_DEBUG, "request\n");
561
562     if (!define->name) {
563         rpmlog(RPMLOG_ERR, "An attempt to define a domain without a name. Abort.\n");
564         return -1;
565     }
566
567     depth = xmlTextReaderDepth(reader);
568     while ((ret = msmNextChildElement(reader, depth))) {
569         node = xmlTextReaderConstName(reader);
570         if (!node) return -1;
571
572         if (!strcmp(ASCII(node), "smack")) {
573             label = xmlTextReaderGetAttribute(reader, XMLCHAR("request"));
574             type = xmlTextReaderGetAttribute(reader, XMLCHAR("type"));
575             rpmlog(RPMLOG_DEBUG, "request label %s type %s\n", ASCII(label), ASCII(type));
576             if (label && type) {
577                 if (msmVerifyAccessType(ASCII(type)) < 0) {
578                     msmFreePointer((void**)&label);
579                     msmFreePointer((void**)&type);      
580                     return -1; 
581                 }
582                 if (msmVerifySmackLabel(ASCII(label)) < 0) {
583                     msmFreePointer((void**)&label);
584                     msmFreePointer((void**)&type);
585                     return -1;
586                 }
587                 d_request_x *request = calloc(1, sizeof(d_request_x));
588                 if (request) {
589                     request->label_name = ASCII(label);
590                     request->ac_type = ASCII(type);
591                     LISTADD(define->d_requests, request);
592                 } else {
593                     msmFreePointer((void**)&label);
594                     msmFreePointer((void**)&type);
595                     return -1;
596                 }
597             } else  {
598                 rpmlog(RPMLOG_ERR, "One of the mandatory arguments for domain request is missing. Abort installation\n");
599                 rpmlog(RPMLOG_ERR, "smack request label %s type %s\n", ASCII(label), ASCII(type));
600                 msmFreePointer((void**)&label);
601                 msmFreePointer((void**)&type);  
602                 return -1;
603             }
604         } else {
605             rpmlog(RPMLOG_ERR, "Not allowed element in domain request section: %s\n", ASCII(node));
606             return -1;
607         }
608         if (ret < 0) return ret;
609     }
610
611     return ret;
612 }
613
614 static int msmProcessDPermit(xmlTextReaderPtr reader, define_x *define) 
615 {
616     const xmlChar *node, *label, *type, *to_label;
617     int ret, depth;
618
619     rpmlog(RPMLOG_DEBUG, "permit\n");
620
621     if (!define->name) {
622         rpmlog(RPMLOG_ERR, "An attempt to define a domain without a name. Abort.\n");
623         return -1;
624     }
625
626     depth = xmlTextReaderDepth(reader);
627
628     while ((ret = msmNextChildElement(reader, depth))) {
629         node = xmlTextReaderConstName(reader);
630         if (!node) return -1;
631
632         if (!strcmp(ASCII(node), "smack")) {
633             label = xmlTextReaderGetAttribute(reader, XMLCHAR("permit"));
634             to_label = xmlTextReaderGetAttribute(reader, XMLCHAR("to"));
635             type = xmlTextReaderGetAttribute(reader, XMLCHAR("type"));
636             rpmlog(RPMLOG_DEBUG, "permit %s to %s type %s\n", ASCII(label), ASCII(to_label), ASCII(type));
637
638             if (label && type) {
639                 if (msmVerifyAccessType(ASCII(type)) < 0) {
640                     msmFreePointer((void**)&label);
641                     msmFreePointer((void**)&to_label);
642                     msmFreePointer((void**)&type);      
643                     return -1; 
644                 }
645                 if (msmVerifySmackLabel(ASCII(label)) < 0) {
646                     msmFreePointer((void**)&label);
647                     msmFreePointer((void**)&to_label);
648                     msmFreePointer((void**)&type);
649                     return -1;
650                 }
651                 if ((to_label) && (msmVerifyLabelPrefix(ASCII(to_label), define->name) < 0)) {
652                     msmFreePointer((void**)&label);
653                     msmFreePointer((void**)&to_label);
654                     msmFreePointer((void**)&type);
655                     return -1;
656                 }
657                 d_permit_x *permit = calloc(1, sizeof(d_permit_x));
658                 if (permit) {
659                     permit->label_name = ASCII(label);
660                     permit->to_label_name = ASCII(to_label);
661                     permit->ac_type = ASCII(type);
662                     LISTADD(define->d_permits, permit);
663                 } else {
664                     msmFreePointer((void**)&label);
665                     msmFreePointer((void**)&to_label);
666                     msmFreePointer((void**)&type);
667                     return -1;
668                 }
669             } else  {
670                 rpmlog(RPMLOG_ERR, "One of the mandatory arguments for domain permit is missing. Abort installation\n");
671                 rpmlog(RPMLOG_ERR, "smack permit label %s type %s\n", ASCII(label), ASCII(type));
672                 msmFreePointer((void**)&label);
673                 msmFreePointer((void**)&to_label);
674                 msmFreePointer((void**)&type);  
675                 return -1;
676             }
677         } else {
678             rpmlog(RPMLOG_ERR, "Not allowed element in domain permit section: %s\n", ASCII(node));
679             return -1;
680         }
681         if (ret < 0) return ret;
682     }
683
684     return ret;
685 }
686
687 static int msmProcessDProvide(xmlTextReaderPtr reader, define_x *define) 
688 {
689     const xmlChar *node, *label;
690     int ret = 0, depth;
691
692     rpmlog(RPMLOG_DEBUG, "provide\n");
693
694     if (!define->name) {
695         rpmlog(RPMLOG_ERR, "An attempt to define a domain without a name. Abort.\n");
696         return -1;
697     }
698
699     depth = xmlTextReaderDepth(reader);
700     while ((ret = msmNextChildElement(reader, depth))) {
701         node = xmlTextReaderConstName(reader);
702         if (!node) return -1;
703         if (!strcmp(ASCII(node), "label")) {
704             label = xmlTextReaderGetAttribute(reader, XMLCHAR("name"));
705             rpmlog(RPMLOG_DEBUG, "label %s \n", ASCII(label));
706
707             if (label) {
708                 if (msmVerifySmackLabel(ASCII(label)) < 0) {
709                     msmFreePointer((void**)&label);
710                     return -1;
711                 }
712                 if (msmVerifyLabelPrefix(ASCII(label), define->name) < 0) {
713                     msmFreePointer((void**)&label);
714                     return -1;
715                 }
716                 d_provide_x *provide = calloc(1, sizeof(d_provide_x));
717                 if (provide) {
718                     provide->label_name = ASCII(label);
719                     LISTADD(define->d_provides, provide);
720                 } else {
721                     msmFreePointer((void**)&label);
722                     return -1;
723                 }
724             } else {
725                  rpmlog(RPMLOG_INFO, "Label name is empty. Label provide is ignored\n");
726                  continue;
727             }
728         } else {
729             rpmlog(RPMLOG_ERR, "Not allowed element in domain provide section: %s\n", ASCII(node));
730             return -1;
731         }
732         if (ret < 0) return ret;
733     }
734
735     return ret;
736 }
737
738 static int msmProcessDefine(xmlTextReaderPtr reader, define_x *define, manifest_x *mfx, sw_source_x *current) 
739 {
740     const xmlChar *node, *name, *policy, *plist;
741     int ret, depth, domainPresent = 0;
742
743     rpmlog(RPMLOG_DEBUG, "define\n");
744
745     depth = xmlTextReaderDepth(reader);
746
747     while ((ret = msmNextChildElement(reader, depth))) {
748         node = xmlTextReaderConstName(reader);
749         if (!node) return -1;
750         if (!strcmp(ASCII(node), "domain")) {
751             if (domainPresent) {
752                 rpmlog(RPMLOG_ERR, "Only one domain is allowed per define section. Abort installation\n");
753                 return -1;
754             }
755             domainPresent = 1;
756             name = xmlTextReaderGetAttribute(reader, XMLCHAR("name"));
757             policy = xmlTextReaderGetAttribute(reader, XMLCHAR("policy"));
758             plist = xmlTextReaderGetAttribute(reader, XMLCHAR("plist"));
759             rpmlog(RPMLOG_DEBUG, "domain %s policy %s plist %s\n", 
760                    ASCII(name), ASCII(policy), ASCII(plist));
761
762             if (name) { 
763                 if (msmVerifySmackLabel(ASCII(name)) < 0) {
764                     msmFreePointer((void**)&name);
765                     msmFreePointer((void**)&policy);            
766                     msmFreePointer((void**)&plist);
767                     return -1; 
768                 }
769
770                 define->name = ASCII(name);
771                 define->policy = ASCII(policy);
772                 define->plist = ASCII(plist);
773                 // store defined ac domain name 
774                 ac_domain_x *ac_domain = calloc(1, sizeof(ac_domain_x));
775                 if (ac_domain) {
776                     if (define->name) {
777                         ac_domain->name = strdup(define->name);
778                     }
779                     ac_domain->match = strdup("trusted"); // hardcode trusted policy for ac domain definition
780                     if (define->policy) {
781                         ac_domain->type = strdup(define->policy);
782                     }   
783                     if (define->plist) {
784                         ac_domain->plist = strdup(define->plist);
785                     }                             
786                     ac_domain->sw_source = current;
787                     ac_domain->pkg_name = mfx->name;
788                     if (!mfx->provides){
789                         provide_x *provide = calloc(1, sizeof(provide_x));
790                         if (provide) {
791                             LISTADD(mfx->provides, provide);
792                         } else { 
793                             if (ac_domain) {
794                                 msmFreeACDomain(ac_domain);
795                                 return -1;
796                             }
797                         }
798                     }
799                     LISTADD(mfx->provides->ac_domains, ac_domain);
800                 } else return -1;
801             } else {
802                 rpmlog(RPMLOG_ERR, "Domain name must be defined. Abort installation\n");
803                 msmFreePointer((void**)&policy);        
804                 msmFreePointer((void**)&plist);
805                 return -1; 
806             }
807         } else if (!strcmp(ASCII(node), "request")) {
808             int res = msmProcessDRequest(reader, define);
809             if (res < 0) return res;
810         } else if (!strcmp(ASCII(node), "permit")) {
811             int res = msmProcessDPermit(reader, define);
812             if (res < 0) return res;
813         } else if (!strcmp(ASCII(node), "provide")) {
814             int res = msmProcessDProvide(reader, define);
815             if (res < 0) return res;
816         } else {
817             rpmlog(RPMLOG_ERR, "Not allowed element in domain define section: %s\n", ASCII(node));
818             return -1;
819         }
820         if (ret < 0) return ret;
821     }
822     return ret;
823 }
824
825 int msmFindSWSourceByKey(sw_source_x *sw_source, void *param)
826 {
827     origin_x *origin;
828     keyinfo_x *keyinfo;
829     keyinfo_x *current_keyinfo = (keyinfo_x*)param;
830
831     for (origin = sw_source->origins; origin; origin = origin->prev) {
832             for (keyinfo = origin->keyinfos; keyinfo; keyinfo = keyinfo->prev) {
833                 if (strncmp((const char*)current_keyinfo->keydata, (const char*)keyinfo->keydata, 
834                     strlen((const char*)current_keyinfo->keydata)) == 0
835                    && (current_keyinfo->keylen == keyinfo->keylen))
836                         return 0;
837             }
838     }
839     return 1;
840 }
841
842 int msmFindSWSourceByName(sw_source_x *sw_source, void *param)
843 {
844     const char *name = (const char *)param;
845     return strcmp(sw_source->name, name); 
846 }
847
848 int msmFindSWSourceBySignature(sw_source_x *sw_source, void *param, void* param2)
849 {
850     origin_x *origin;
851     keyinfo_x *keyinfo;
852     pgpDigParams sig = (pgpDigParams)param;
853     DIGEST_CTX ctx = (DIGEST_CTX)param2;
854     pgpDigParams key = NULL;
855
856     for (origin = sw_source->origins; origin; origin = origin->prev) {
857         for (keyinfo = origin->keyinfos; keyinfo; keyinfo = keyinfo->prev) {
858             if (pgpPrtParams(keyinfo->keydata, keyinfo->keylen, PGPTAG_PUBLIC_KEY, &key)) {
859                 rpmlog(RPMLOG_ERR, "invalid sw source key\n");
860                 return -1;
861             }
862             if (pgpVerifySignature(key, sig, ctx) == RPMRC_OK) {
863                 return 0;
864             }
865         }
866     }
867     return 1;
868 }
869
870 static int msmProcessKeyinfo(xmlTextReaderPtr reader, origin_x *origin, sw_source_x *parent) 
871 {
872     const xmlChar *keydata;
873     keyinfo_x *keyinfo;
874     int ret, depth;
875
876     depth = xmlTextReaderDepth(reader);
877     while ((ret = msmNextChildElement(reader, depth))) {
878         keydata = xmlTextReaderConstValue(reader);
879         rpmlog(RPMLOG_DEBUG, "keyinfo %.40s...\n", ASCII(keydata));
880         if (!keydata) return -1;
881         keyinfo = calloc(1, sizeof(keyinfo_x));
882         if (keyinfo) {
883             if ((ret = rpmBase64Decode(ASCII(keydata), (void **)&keyinfo->keydata, &keyinfo->keylen))) {
884                 rpmlog(RPMLOG_ERR, "Failed to decode keyinfo %s, %d\n", keydata, ret);
885                 ret = -1;
886             }
887             if (!ret) {
888                 // check that keys aren't matching
889                 sw_source_x *old = msmSWSourceTreeTraversal(parent, msmFindSWSourceByKey, (void *)keyinfo, NULL);
890                 if (old) {
891                     rpmlog(RPMLOG_ERR, "SW source with this key has already been installed\n");
892                     return -1; 
893                 }
894             }
895             LISTADD(origin->keyinfos, keyinfo);
896         } else return -1;
897
898         if (ret < 0) return ret;
899     }
900     return ret;
901 }
902
903 static access_x *msmProcessAccess(xmlTextReaderPtr reader, origin_x *origin) 
904 {
905     const xmlChar *data, *type;
906
907     data = xmlTextReaderGetAttribute(reader, XMLCHAR("data"));
908     type = xmlTextReaderGetAttribute(reader, XMLCHAR("type"));
909     rpmlog(RPMLOG_DEBUG, "access %s %s\n", ASCII(data), ASCII(type));
910
911     if (data) {
912         access_x *access = calloc(1, sizeof(access_x));
913         if (access) {
914             access->data = ASCII(data);
915             access->type = ASCII(type);
916             return access;
917         }
918     }
919     msmFreePointer((void**)&data);
920     msmFreePointer((void**)&type);
921     return NULL;
922 }
923
924 static int msmProcessOrigin(xmlTextReaderPtr reader, origin_x *origin, sw_source_x *parent)  
925 {
926     const xmlChar *node, *type;
927     int ret, depth;
928
929     type = xmlTextReaderGetAttribute(reader, XMLCHAR("type"));
930     rpmlog(RPMLOG_DEBUG, "origin %s\n", ASCII(type));
931     origin->type = ASCII(type);
932
933     depth = xmlTextReaderDepth(reader);
934     while ((ret = msmNextChildElement(reader, depth))) {
935         node = xmlTextReaderConstName(reader);
936         if (!node) return -1;
937         if (!strcmp(ASCII(node), "keyinfo")) {
938             ret = msmProcessKeyinfo(reader, origin, parent);
939         } else if (!strcmp(ASCII(node), "access")) {
940             access_x *access = msmProcessAccess(reader, origin);
941             if (access) {
942                 LISTADD(origin->accesses, access);
943             } else return -1;
944         } else return -1;
945
946         if (ret < 0) return ret;
947     }
948     return ret;
949 }
950
951 static int msmProcessDeny(xmlTextReaderPtr reader, sw_source_x *sw_source) 
952 {
953     const xmlChar *node;
954     int ret, depth;
955
956     rpmlog(RPMLOG_DEBUG, "deny\n");
957
958     depth = xmlTextReaderDepth(reader);
959     while ((ret = msmNextChildElement(reader, depth))) {
960         node = xmlTextReaderConstName(reader);
961         if (!node) return -1;
962         if (!strcmp(ASCII(node), "ac_domain")) {
963             ac_domain_x *ac_domain = msmProcessACDomain(reader, sw_source, NULL);
964             if (ac_domain) {
965                 if (ac_domain->name) {
966                     HASH_ADD_KEYPTR(hh, sw_source->denys, ac_domain->name, 
967                                     strlen(ac_domain->name), ac_domain);
968                 } else {
969                     LISTADD(sw_source->denymatches, ac_domain);
970                 }
971             } else return -1;
972         } else return -1;
973         if (ret < 0) return ret;
974     }
975     return ret;
976 }
977
978 static int msmProcessAllow(xmlTextReaderPtr reader, sw_source_x *sw_source) 
979 {
980     const xmlChar *node;    
981     int ret, depth;
982
983     rpmlog(RPMLOG_DEBUG, "allow\n");
984
985     depth = xmlTextReaderDepth(reader);
986     while ((ret = msmNextChildElement(reader, depth))) {
987         node = xmlTextReaderConstName(reader);
988         if (!node) return -1;
989         if (!strcmp(ASCII(node), "deny")) {
990             ret = msmProcessDeny(reader, sw_source);
991         } else if (!strcmp(ASCII(node), "ac_domain")) {
992             ac_domain_x *ac_domain = msmProcessACDomain(reader, sw_source, NULL);
993             if (ac_domain) {
994                 if (ac_domain->name) {
995                     HASH_ADD_KEYPTR(hh, sw_source->allows, ac_domain->name, 
996                                     strlen(ac_domain->name), ac_domain);
997                 } else {
998                     LISTADD(sw_source->allowmatches, ac_domain);
999                 }
1000             } else return -1;
1001         } else return -1;
1002         if (ret < 0) return ret;
1003     }
1004     return ret;
1005 }
1006
1007 static int msmProcessSWSource(xmlTextReaderPtr reader, sw_source_x *sw_source, const char *parentkey, manifest_x *mfx) 
1008 {
1009     const xmlChar *name, *node, *rank, *rankkey;
1010     sw_source_x *current;
1011     int ret, depth, len;
1012     int rankval = 0;
1013
1014     /* config processing */
1015     current = sw_source;
1016
1017     name = xmlTextReaderGetAttribute(reader, XMLCHAR("name"));
1018     rank = xmlTextReaderGetAttribute(reader, XMLCHAR("rank"));
1019     rankkey = xmlTextReaderGetAttribute(reader, XMLCHAR("rankkey"));
1020     rpmlog(RPMLOG_DEBUG, "sw source %s rank %s key %s\n", 
1021            ASCII(name), ASCII(rank), ASCII(rankkey));
1022
1023     sw_source->name = ASCII(name);
1024
1025     if (rankkey) {
1026         /* config processing */
1027         sw_source->rankkey = ASCII(rankkey);
1028     } else {
1029         if (rank) {
1030             rankval = atoi(ASCII(rank));
1031             msmFreePointer((void**)&rank); /* rankkey is used from now on */
1032         }
1033     }
1034     if (!sw_source->name) return -1; /* sw source must have name */
1035     if (!mfx && rankkey) return -1; /* manifest cannot set rankkey itself */
1036
1037     if (!mfx) {
1038         sw_source_x *old = msmSWSourceTreeTraversal(sw_source->parent, msmFindSWSourceByName, (void *)sw_source->name, NULL);
1039         if (old && old->parent != sw_source->parent) {
1040             if (!old->parent && old == sw_source->parent) {
1041                 /* root sw source upgrade (it's signed by root) */
1042                 parentkey = "";
1043             } else {
1044                 rpmlog(RPMLOG_ERR, "SW source called %s has already been installed\n", 
1045                        sw_source->name);
1046                 return -1; /* sw_source names are unique (allow upgrade though) */
1047             }
1048         }
1049         /* rank algorithm is copied from harmattan dpkg wrapper */
1050         if (rankval > RANK_LIMIT) rankval = RANK_LIMIT;
1051         if (rankval < -RANK_LIMIT) rankval = -RANK_LIMIT;
1052         rankval += RANK_LIMIT;
1053
1054         len = strlen(parentkey) + 1 + 5 + 1 + 5 + 1 + strlen(sw_source->name) + 1;
1055         if (!(sw_source->rankkey = malloc(len))) return -1;
1056         sprintf((char *)sw_source->rankkey, "%s/%05d/%05d.%s", 
1057                 parentkey, rankval, RANK_LIMIT, sw_source->name);
1058     }
1059
1060     depth = xmlTextReaderDepth(reader);
1061     while ((ret = msmNextChildElement(reader, depth))) {
1062         node = xmlTextReaderConstName(reader);
1063         if (!node) return -1;
1064         if (!strcmp(ASCII(node), "allow")) {
1065             ret = msmProcessAllow(reader, sw_source);
1066         } else if (!strcmp(ASCII(node), "deny")) {
1067             ret = msmProcessDeny(reader, sw_source);
1068         } else if (!strcmp(ASCII(node), "origin")) {
1069             origin_x *origin = calloc(1, sizeof(origin_x));
1070             if (origin) {
1071                 LISTADD(sw_source->origins, origin);
1072                 ret = msmProcessOrigin(reader, origin, sw_source->parent);
1073             } else return -1;
1074         } else if (!strcmp(ASCII(node), "package")) {
1075             /* config processing */
1076             if (!mfx) return -1;
1077             package_x *package = calloc(1, sizeof(package_x));
1078             if (package) {
1079                 LISTADD(sw_source->packages, package);
1080                 ret = msmProcessPackage(reader, package, current);
1081             } else return -1;
1082         } else if (!strcmp(ASCII(node), "sw_source")) {
1083             /* config processing */
1084             if (!mfx) return -1;
1085             sw_source_x *sw_source = calloc(1, sizeof(sw_source_x));
1086             if (sw_source) {
1087                 sw_source->parent = current;
1088                 LISTADD(mfx->sw_sources, sw_source);
1089             } else return -1;
1090             ret = msmProcessSWSource(reader, sw_source, "", mfx);
1091         } else return -1;
1092
1093         if (ret < 0) return ret;
1094     }
1095     return ret;
1096 }
1097
1098 static int msmProcessAttributes(xmlTextReaderPtr reader, manifest_x *mfx) 
1099 {
1100     const xmlChar *node, *type;
1101     int ret, depth, attributePresent = 0;
1102
1103     rpmlog(RPMLOG_DEBUG, "attributes\n");
1104     depth = xmlTextReaderDepth(reader);
1105
1106     while ((ret = msmNextChildElement(reader, depth))) {
1107         node = xmlTextReaderConstName(reader);
1108         if (!node) return -1;
1109         if (!strcmp(ASCII(node), "package")) {
1110             if (attributePresent) {
1111                 rpmlog(RPMLOG_ERR, "Only one attribute is currently allowed per attribute section. Abort installation\n");
1112                 return -1;
1113             }
1114             attributePresent = 1;
1115             type = xmlTextReaderGetAttribute(reader, XMLCHAR("type"));
1116             rpmlog(RPMLOG_DEBUG, "package type is %s\n", ASCII(type));
1117
1118             if (type) { 
1119                 if ((strcmp(type, "system") != 0) &&
1120                     (strcmp(type, "application") != 0)){
1121                     rpmlog(RPMLOG_ERR, "Not allowed attribute name in a package type specification. Abort installation.\n");
1122                     msmFreePointer((void**)&type);
1123                     return -1; 
1124                 }
1125                 mfx->package_type = ASCII(type);            
1126             } else {
1127                 rpmlog(RPMLOG_ERR, "Type name must be defined. Abort installation\n");
1128                 return -1; 
1129             }
1130         } else {
1131             rpmlog(RPMLOG_ERR, "Not allowed element in attribute section: %s\n", ASCII(node));
1132             return -1;
1133         }
1134         if (ret < 0) return ret;
1135     }
1136     return ret;
1137 }
1138
1139 static int msmProcessMsm(xmlTextReaderPtr reader, manifest_x *mfx, sw_source_x *current)
1140 {
1141     const xmlChar *node;
1142     int ret, depth;
1143     int assignPresent = 0, requestPresent = 0, attributesPresent = 0; /* there must be only one section per manifest */
1144     mfx->sw_source = current;
1145
1146     rpmlog(RPMLOG_DEBUG, "manifest\n");
1147
1148     depth = xmlTextReaderDepth(reader);
1149     while ((ret = msmNextChildElement(reader, depth))) {
1150         node = xmlTextReaderConstName(reader);
1151         if (!node) return -1;
1152         if (!strcmp(ASCII(node), "assign")) {
1153             if (assignPresent) {
1154                 rpmlog(RPMLOG_ERR, "A second assign section in manifest isn't allowed. Abort installation.\n");
1155                 return -1; 
1156             }
1157             assignPresent = 1;
1158             provide_x *provide = calloc(1, sizeof(provide_x));
1159             if (provide) {
1160                 LISTADD(mfx->provides, provide);
1161                 ret = msmProcessProvide(reader, provide, current, mfx, NULL);
1162             } else return -1;
1163         } else if (!strcmp(ASCII(node), "attributes")) {
1164             if (attributesPresent) {
1165                 rpmlog(RPMLOG_ERR, "A second attribute section in manifest isn't allowed. Abort installation.\n");
1166                 return -1; 
1167             }
1168             attributesPresent = 1;
1169             ret = msmProcessAttributes(reader, mfx);
1170         } else if (!strcmp(ASCII(node), "define")) {
1171             define_x *define = calloc(1, sizeof(define_x));
1172             if (define) {
1173                 LISTADD(mfx->defines, define);
1174                 ret = msmProcessDefine(reader, define, mfx, current);
1175             } else return -1;
1176         } else if (!strcmp(ASCII(node), "request")) {
1177             if (requestPresent) {
1178                 rpmlog(RPMLOG_ERR, "A second request section in manifest isn't allowed. Abort installation.\n");
1179                 return -1; 
1180             }
1181             requestPresent = 1;
1182             mfx->request = calloc(1, sizeof(request_x));
1183             if (mfx->request) {
1184                 ret = msmProcessRequest(reader, mfx->request);
1185             } else return -1;
1186         } else if (!strcmp(ASCII(node), "sw_source")) {
1187             sw_source_x *sw_source = calloc(1, sizeof(sw_source_x));
1188             if (sw_source) {
1189                 char parentkey[256] = { 0 };
1190                 sw_source->parent = current;
1191                 if (sw_source->parent) {
1192                     snprintf(parentkey, sizeof(parentkey), 
1193                              "%s", sw_source->parent->rankkey);
1194                     char *sep = strrchr(parentkey, '/');
1195                     if (sep) *sep = '\0';
1196                 }
1197                 LISTADD(mfx->sw_sources, sw_source);
1198                 ret = msmProcessSWSource(reader, sw_source, parentkey, NULL);
1199             } else return -1;
1200         } else return -1;
1201         if (ret < 0) return ret;
1202     }
1203     return ret;
1204 }
1205
1206 static int msmProcessConfig(xmlTextReaderPtr reader, manifest_x *mfx)
1207 {
1208     const xmlChar *node;
1209     int ret, depth;
1210
1211     rpmlog(RPMLOG_DEBUG, "config\n");
1212
1213     depth = xmlTextReaderDepth(reader);
1214     if ((ret = msmNextChildElement(reader, depth))) {
1215         node = xmlTextReaderConstName(reader);
1216         if (!node) return -1;
1217         if (!strcmp(ASCII(node), "sw_source")) {
1218             mfx->sw_sources = calloc(1, sizeof(sw_source_x));
1219             if (!mfx->sw_sources) return -1;
1220             ret = msmProcessSWSource(reader, mfx->sw_sources, "", mfx);
1221         } else return -1;
1222     }
1223     return ret;
1224 }
1225
1226 static int msmProcessManifest(xmlTextReaderPtr reader, manifest_x *mfx, sw_source_x *current) 
1227 {
1228     const xmlChar *node;
1229     int ret;
1230
1231     if ((ret = msmNextChildElement(reader, -1))) {
1232         node = xmlTextReaderConstName(reader);
1233         if (!node) return -1;
1234         if (!strcmp(ASCII(node), "manifest")) {
1235             ret = msmProcessMsm(reader, mfx, current);
1236         } else if (!strcmp(ASCII(node), "config")) {
1237             ret = msmProcessConfig(reader, mfx);
1238         } else return -1;
1239     }
1240     return ret;
1241 }
1242
1243 static filesystem_x *msmFreeFilesystem(filesystem_x *filesystem)
1244 {    
1245     if (filesystem) {
1246         filesystem_x *prev = filesystem->prev;
1247         msmFreePointer((void**)&filesystem->path);
1248         msmFreePointer((void**)&filesystem->label);
1249         msmFreePointer((void**)&filesystem->exec_label);
1250         msmFreePointer((void**)&filesystem->type);
1251         msmFreePointer((void**)&filesystem);
1252         return prev;
1253     } else
1254         return NULL;
1255 }
1256
1257 static member_x *msmFreeMember(member_x *member)
1258
1259     if (member) {
1260         member_x *prev = member->prev;
1261         msmFreePointer((void**)&member->name);
1262         if (member->annotation) {
1263             msmFreePointer((void**)&member->annotation->name);
1264             msmFreePointer((void**)&member->annotation->value);
1265             msmFreePointer((void**)&member->annotation);
1266         }
1267         msmFreePointer((void**)&member);
1268         return prev;
1269     } else
1270         return NULL;
1271 }
1272
1273 static interface_x *msmFreeInterface(interface_x *interface)
1274 {
1275     member_x *member;
1276
1277     if (interface) {
1278         interface_x *prev = interface->prev;
1279         msmFreePointer((void**)&interface->name);
1280         if (interface->annotation) {
1281             msmFreePointer((void**)&interface->annotation->name);
1282             msmFreePointer((void**)&interface->annotation->value);
1283             msmFreePointer((void**)&interface->annotation);
1284         }
1285         for (member = interface->members; member; member = msmFreeMember(member));
1286         msmFreePointer((void**)&interface);
1287         return prev;
1288     } else
1289         return NULL;
1290 }
1291
1292 static node_x *msmFreeNode(node_x *node)
1293 {    
1294     member_x *member;
1295     interface_x *interface;
1296
1297     if (node) {
1298         node_x *prev = node->prev;
1299         msmFreePointer((void**)&node->name);
1300         if (node->annotation) {
1301             msmFreePointer((void**)&node->annotation->name);
1302             msmFreePointer((void**)&node->annotation->value);
1303             msmFreePointer((void**)&node->annotation);
1304         }
1305         for (member = node->members; member; member = msmFreeMember(member));
1306         for (interface = node->interfaces; interface; interface = msmFreeInterface(interface));
1307         msmFreePointer((void**)&node);
1308         return prev;
1309     } else
1310         return NULL;
1311 }
1312
1313 static dbus_x *msmFreeDBus(dbus_x *dbus)
1314 {
1315     node_x *node;
1316
1317     if (dbus) {
1318         dbus_x *prev = dbus->prev;
1319         msmFreePointer((void**)&dbus->name);
1320         msmFreePointer((void**)&dbus->own);
1321         msmFreePointer((void**)&dbus->bus);
1322         if (dbus->annotation) {
1323             msmFreePointer((void**)&dbus->annotation->name);
1324             msmFreePointer((void**)&dbus->annotation->value);
1325             msmFreePointer((void**)&dbus->annotation);
1326         }
1327         for (node = dbus->nodes; node; node = msmFreeNode(node));
1328         msmFreePointer((void**)&dbus);
1329         return prev;
1330     } else return NULL;
1331 }
1332
1333 static provide_x *msmFreeProvide(provide_x *provide) 
1334 {
1335     ac_domain_x *ac_domain;
1336     filesystem_x *filesystem;
1337     provide_x *prev = provide->prev;
1338     dbus_x *dbus;
1339
1340     if (provide) {
1341         for (ac_domain = provide->ac_domains; ac_domain; ac_domain = msmFreeACDomain(ac_domain));
1342         if (provide->filesystems)
1343             for (filesystem = provide->filesystems; filesystem; filesystem = msmFreeFilesystem(filesystem));
1344         msmFreePointer((void**)&provide->name);
1345         msmFreePointer((void**)&provide->origin);
1346         for (dbus = provide->dbuss; dbus; dbus = msmFreeDBus(dbus));
1347         msmFreePointer((void**)&provide);
1348     }
1349     return prev;
1350 }
1351
1352 static file_x *msmFreeFile(file_x *file)
1353 {
1354     file_x *prev = file->prev;
1355     msmFreePointer((void**)&file->path);
1356     msmFreePointer((void**)&file);
1357     return prev;
1358 }
1359
1360 package_x *msmFreePackage(package_x *package)
1361 {
1362     provide_x *provide;
1363     package_x *prev = package->prev;
1364     for (provide = package->provides; provide; provide = msmFreeProvide(provide));
1365     msmFreePointer((void**)&package->name);
1366     msmFreePointer((void**)&package->modified);
1367     msmFreePointer((void**)&package);
1368     return prev;
1369 }
1370
1371 static keyinfo_x *msmFreeKeyinfo(keyinfo_x *keyinfo)
1372 {
1373     keyinfo_x *prev = keyinfo->prev;
1374     msmFreePointer((void**)&keyinfo->keydata);
1375     msmFreePointer((void**)&keyinfo);
1376     return prev;
1377 }
1378
1379 static access_x *msmFreeAccess(access_x *access)
1380 {
1381     access_x *prev = access->prev;
1382     msmFreePointer((void**)&access->data);
1383     msmFreePointer((void**)&access->type);
1384     msmFreePointer((void**)&access);
1385     return prev;
1386 }
1387
1388 static origin_x *msmFreeOrigin(origin_x *origin)
1389 {
1390     keyinfo_x *keyinfo;
1391     access_x *access;
1392     origin_x *prev = origin->prev;
1393     for (keyinfo = origin->keyinfos; keyinfo; keyinfo = msmFreeKeyinfo(keyinfo));
1394     for (access = origin->accesses; access; access = msmFreeAccess(access));
1395     msmFreePointer((void**)&origin->type);
1396     msmFreePointer((void**)&origin);
1397     return prev;
1398 }
1399
1400 static sw_source_x *msmFreeSWSource(sw_source_x *sw_source)
1401 {
1402     package_x *package;
1403     ac_domain_x *ac_domain, *temp;
1404     origin_x *origin;
1405     sw_source_x *next = sw_source->next;
1406
1407     rpmlog(RPMLOG_DEBUG, "freeing sw source %s\n", sw_source->name);
1408
1409     for (package = sw_source->packages; package; package = msmFreePackage(package));
1410     for (ac_domain = sw_source->allowmatches; ac_domain; ac_domain = msmFreeACDomain(ac_domain));
1411     if (sw_source->allows) {
1412         HASH_ITER(hh, sw_source->allows, ac_domain, temp) {
1413             HASH_DELETE(hh, sw_source->allows, ac_domain);
1414             msmFreeACDomain(ac_domain);
1415         }
1416     }
1417
1418     for (ac_domain = sw_source->denymatches; ac_domain; ac_domain = msmFreeACDomain(ac_domain));
1419     if (sw_source->denys) {
1420         HASH_ITER(hh, sw_source->denys, ac_domain, temp) {
1421             HASH_DELETE(hh, sw_source->denys, ac_domain);
1422             msmFreeACDomain(ac_domain);
1423         }
1424     }
1425     for (origin = sw_source->origins; origin; origin = msmFreeOrigin(origin));
1426     msmFreePointer((void**)&sw_source->name);
1427     msmFreePointer((void**)&sw_source->rankkey);
1428     msmFreePointer((void**)&sw_source);
1429     return next;
1430 }
1431
1432 static d_request_x *msmFreeDRequest(d_request_x *d_request)
1433 {
1434     d_request_x *next = d_request->next;
1435     rpmlog(RPMLOG_DEBUG, "freeing domain request %s\n", d_request->label_name);
1436     msmFreePointer((void**)&d_request->label_name);
1437     msmFreePointer((void**)&d_request->ac_type);
1438     msmFreePointer((void**)&d_request);
1439     return next;
1440 }
1441
1442 static d_permit_x *msmFreeDPermit(d_permit_x *d_permit)
1443 {
1444     d_permit_x *next = d_permit->next;
1445     rpmlog(RPMLOG_DEBUG, "freeing domain permit %s\n", d_permit->label_name);
1446     msmFreePointer((void**)&d_permit->label_name);
1447     msmFreePointer((void**)&d_permit->to_label_name);
1448     msmFreePointer((void**)&d_permit->ac_type);
1449     msmFreePointer((void**)&d_permit);
1450     return next;
1451 }
1452
1453 static d_provide_x *msmFreeDProvide(d_provide_x *d_provide)
1454 {
1455     d_provide_x *next = d_provide->next;
1456     rpmlog(RPMLOG_DEBUG, "freeing domain provide %s\n", d_provide->label_name);
1457     msmFreePointer((void**)&d_provide->label_name);
1458     msmFreePointer((void**)&d_provide);
1459     return next;
1460 }
1461
1462 static define_x *msmFreeDefine(define_x *define)
1463 {
1464     define_x *next = define->next;
1465     d_request_x *d_request;
1466     d_permit_x *d_permit;
1467     d_provide_x *d_provide;
1468
1469     msmFreePointer((void**)&define->name);
1470     msmFreePointer((void**)&define->policy);
1471     msmFreePointer((void**)&define->plist);
1472
1473     if (define->d_requests) {
1474         LISTHEAD(define->d_requests, d_request);        
1475         for (; d_request; d_request = msmFreeDRequest(d_request));
1476     }
1477     rpmlog(RPMLOG_DEBUG, "after freeing define requests\n");
1478     if (define->d_permits) {
1479         LISTHEAD(define->d_permits, d_permit);  
1480         for (; d_permit; d_permit = msmFreeDPermit(d_permit));
1481     }
1482     rpmlog(RPMLOG_DEBUG, "after freeing define permits\n");
1483     if (define->d_provides) {
1484         LISTHEAD(define->d_provides, d_provide);        
1485         for (; d_provide; d_provide = msmFreeDProvide(d_provide));
1486     }
1487     rpmlog(RPMLOG_DEBUG, "after freeing provides\n");
1488     msmFreePointer((void**)&define); 
1489     return next;
1490 }
1491
1492 manifest_x* msmFreeManifestXml(manifest_x* mfx)
1493 {
1494     provide_x *provide;
1495     file_x *file;
1496     sw_source_x *sw_source;
1497     define_x *define;
1498
1499     rpmlog(RPMLOG_DEBUG, "in msmFreeManifestXml\n");
1500     if (mfx) {
1501         if (mfx->provides)
1502             for (provide = mfx->provides; provide; provide = msmFreeProvide(provide));
1503         rpmlog(RPMLOG_DEBUG, "after freeing provides\n");
1504         if (mfx->request) {
1505             msmFreePointer((void**)&mfx->request->ac_domain);
1506             msmFreePointer((void**)&mfx->request);
1507         }
1508         rpmlog(RPMLOG_DEBUG, "after freeing requests\n");
1509         for (file = mfx->files; file; file = msmFreeFile(file));
1510         rpmlog(RPMLOG_DEBUG, "after freeing files\n");
1511         if (mfx->sw_sources) {
1512             LISTHEAD(mfx->sw_sources, sw_source);       
1513             for (; sw_source; sw_source = msmFreeSWSource(sw_source));
1514         }
1515         msmFreePointer((void**)&mfx->name);
1516         rpmlog(RPMLOG_DEBUG, "after freeing name\n");
1517         if (mfx->defines) {
1518             LISTHEAD(mfx->defines, define);
1519             for (; define; define = msmFreeDefine(define));            
1520         }
1521         rpmlog(RPMLOG_DEBUG, "after freeing defines \n");
1522         msmFreePointer((void**)&mfx);
1523     }
1524     return mfx; 
1525 }
1526
1527 manifest_x *msmProcessManifestXml(const char *buffer, int size, sw_source_x *current, const char *packagename) 
1528 {
1529     xmlTextReaderPtr reader;
1530     manifest_x *mfx = NULL;
1531
1532     reader = xmlReaderForMemory(buffer, size, NULL, NULL, 0);
1533     if (reader) {
1534         mfx = calloc(1, sizeof(manifest_x));
1535         if (mfx) {
1536             mfx->name = strdup(packagename);
1537             if (msmProcessManifest(reader, mfx, current) < 0) {
1538             /* error in parcing. Let's display some hint where we failed */
1539                 rpmlog(RPMLOG_DEBUG, "Syntax error in processing manifest in the above line\n");
1540                 mfx = msmFreeManifestXml(mfx);
1541             }
1542         }
1543         xmlFreeTextReader(reader);
1544     } else {
1545         rpmlog(RPMLOG_ERR, "Unable to create xml reader\n");
1546     }
1547     return mfx;
1548 }
1549
1550 manifest_x *msmProcessDevSecPolicyXml(const char *filename) 
1551 {
1552     xmlTextReaderPtr reader;
1553     manifest_x *mfx = NULL;
1554
1555     reader = xmlReaderForFile(filename, NULL, 0);
1556     if (reader) {
1557         mfx = calloc(1, sizeof(manifest_x));
1558         if (mfx) {
1559             if (msmProcessManifest(reader, mfx, NULL) < 0) {
1560                 mfx = msmFreeManifestXml(mfx);
1561             }
1562         }
1563         xmlFreeTextReader(reader);
1564     } else {
1565         rpmlog(RPMLOG_ERR, "Unable to open device security policy %s\n", filename);
1566     }
1567     return mfx;
1568 }