Add macro %isu_package to generate ISU Package
[platform/upstream/rpm.git] / build / policies.c
1 /** \ingroup rpmbuild
2  * \file build/policies.c
3  *  The post-build, packaging of policies
4  */
5
6 #include "system.h"
7
8 #include <rpm/rpmbuild.h>
9 #include <rpm/argv.h>
10 #include <rpm/rpmlog.h>
11 #include <rpm/rpmpol.h>
12 #include <rpm/rpmbase64.h>
13
14 #include "rpmio/rpmio_internal.h"
15 #include "build/rpmbuild_internal.h"
16
17 #include "debug.h"
18
19 #if WITH_SELINUX
20 typedef struct ModuleRec_s {
21     char *path;
22     char *data;
23     char *name;
24     ARGV_t types;
25     uint32_t flags;
26 } *ModuleRec;
27
28 static rpmRC writeModuleToHeader(ModuleRec mod, Package pkg)
29 {
30     rpmRC rc = RPMRC_FAIL;
31     ARGV_t av;
32     uint32_t count;
33     struct rpmtd_s policies;
34     struct rpmtd_s policynames;
35     struct rpmtd_s policyflags;
36     struct rpmtd_s policytypes;
37     struct rpmtd_s policytypesidx;
38     rpmtdReset(&policies);
39     rpmtdReset(&policynames);
40     rpmtdReset(&policyflags);
41     rpmtdReset(&policytypes);
42     rpmtdReset(&policytypesidx);
43
44     if (!mod || !pkg) {
45         goto exit;
46     }
47
48     /* check for duplicates */
49     if (headerIsEntry(pkg->header, RPMTAG_POLICYNAMES)) {
50         int typeCount;
51         const char *name;
52         char *type;
53         int i;
54         int idx;
55
56         headerGet(pkg->header, RPMTAG_POLICYNAMES, &policynames, HEADERGET_MINMEM);
57         headerGet(pkg->header, RPMTAG_POLICYFLAGS, &policyflags, HEADERGET_ARGV | HEADERGET_MINMEM);
58         headerGet(pkg->header, RPMTAG_POLICYTYPES, &policytypes, HEADERGET_ARGV | HEADERGET_MINMEM);
59         headerGet(pkg->header, RPMTAG_POLICYTYPESINDEXES, &policytypesidx, HEADERGET_ARGV | HEADERGET_MINMEM);
60         typeCount = rpmtdCount(&policytypes);
61
62         while ((name = rpmtdNextString(&policynames))) {
63             int overlappingtypes = 0;
64
65             idx = rpmtdGetIndex(&policynames);
66
67             for (i = 0; i < typeCount; i++) {
68                 if (((int *) policytypesidx.data)[i] != idx) {
69                     continue;
70                 }
71
72                 type = ((char **) policytypes.data)[i];
73
74                 if (rstreq(type, RPMPOL_TYPE_DEFAULT) ||
75                     argvSearch(mod->types, type, NULL) ||
76                     argvSearch(mod->types, RPMPOL_TYPE_DEFAULT, NULL)) {
77                     overlappingtypes = 1;
78                     break;
79                 }
80             }
81
82             if (!overlappingtypes) {
83                 continue;
84             }
85
86             if (rstreq(mod->name, name)) {
87                 rpmlog(RPMLOG_ERR, _("Policy module '%s' duplicated with overlapping types\n"), name);
88                 goto exit;
89             }
90
91             if ((mod->flags && RPMPOL_FLAG_BASE) &&
92                 (((int *) policyflags.data)[idx] & RPMPOL_FLAG_BASE)) {
93                 rpmlog(RPMLOG_ERR, _("Base modules '%s' and '%s' have overlapping types\n"), mod->name, name);
94                 goto exit;
95             }
96         }
97     }
98
99     if (headerIsEntry(pkg->header, RPMTAG_POLICIES)) {
100         if (!headerGet(pkg->header, RPMTAG_POLICIES, &policies, HEADERGET_MINMEM)) {
101             rpmlog(RPMLOG_ERR, _("Failed to get policies from header\n"));
102             goto exit;
103         }
104         count = rpmtdCount(&policies);
105     } else {
106         count = 0;
107     }
108
109     /* save everything to the header */
110     headerPutString(pkg->header, RPMTAG_POLICIES, mod->data);
111     headerPutString(pkg->header, RPMTAG_POLICYNAMES, mod->name);
112     headerPutUint32(pkg->header, RPMTAG_POLICYFLAGS, &mod->flags, 1);
113
114     for (av = mod->types; av && *av; av++) {
115         headerPutString(pkg->header, RPMTAG_POLICYTYPES, *av);
116         headerPutUint32(pkg->header, RPMTAG_POLICYTYPESINDEXES, &count, 1);
117     }
118
119     rc = RPMRC_OK;
120
121   exit:
122
123     rpmtdFreeData(&policies);
124     rpmtdFreeData(&policynames);
125     rpmtdFreeData(&policyflags);
126     rpmtdFreeData(&policytypes);
127     rpmtdFreeData(&policytypesidx);
128
129     return rc;
130 }
131
132 static ModuleRec freeModule(ModuleRec mod)
133 {
134     if (mod) {
135         _free(mod->path);
136         _free(mod->data);
137         _free(mod->name);
138         argvFree(mod->types);
139         _free(mod);
140     }
141
142     return NULL;
143 }
144
145 static ModuleRec newModule(const char *path, const char *name,
146                            const char *types, uint32_t flags)
147 {
148     ModuleRec mod;
149     uint8_t *raw = NULL;
150     ssize_t rawlen = 0;
151     const char *buildDir = "%{_builddir}/%{?buildsubdir}/";
152
153     if (!path) {
154         rpmlog(RPMLOG_ERR, _("%%semodule requires a file path\n"));
155         return NULL;
156     }
157
158     mod = xcalloc(1, sizeof(*mod));
159
160     mod->path = rpmGenPath(buildDir, NULL, path);
161
162     if ((rpmioSlurp(mod->path, &raw, &rawlen)) != 0 || raw == NULL) {
163         rpmlog(RPMLOG_ERR, _("Failed to read  policy file: %s\n"),
164                mod->path);
165         goto err;
166     }
167
168     mod->data = rpmBase64Encode(raw, rawlen, -1);
169     if (!mod->data) {
170         rpmlog(RPMLOG_ERR, _("Failed to encode policy file: %s\n"),
171                mod->path);
172         goto err;
173     }
174
175     if (name) {
176         mod->name = xstrdup(name);
177     } else {
178         /* assume base name (minus extension) if name is not given */
179         char *tmp = xstrdup(mod->path);
180         char *bname = basename(tmp);
181         char *end = strchr(bname, '.');
182         if (end)
183             *end = '\0';
184         if (strlen(bname) > 0) {
185             mod->name = xstrdup(bname);
186         } else {
187             rpmlog(RPMLOG_ERR, _("Failed to determine a policy name: %s\n"),
188                    mod->path);
189             _free(tmp);
190             goto err;
191         }
192         _free(tmp);
193     }
194
195     if (types) {
196         mod->types = argvSplitString(types, ",", ARGV_SKIPEMPTY);
197         argvSort(mod->types, NULL);
198         if (argvSearch(mod->types, RPMPOL_TYPE_DEFAULT, NULL) && argvCount(mod->types) > 1) {
199             rpmlog(RPMLOG_WARNING, _("'%s' type given with other types in %%semodule %s. Compacting types to '%s'.\n"),
200                    RPMPOL_TYPE_DEFAULT, mod->path, RPMPOL_TYPE_DEFAULT);
201             mod->types = argvFree(mod->types);
202             argvAdd(&mod->types, RPMPOL_TYPE_DEFAULT);
203         }
204     } else {
205         argvAdd(&mod->types, RPMPOL_TYPE_DEFAULT);
206     }
207
208     mod->flags = flags;
209
210     return mod;
211
212   err:
213     freeModule(mod);
214     return NULL;
215 }
216
217 static rpmRC processPolicies(rpmSpec spec, Package pkg, int test)
218 {
219     const char *path = NULL;
220     char *name = NULL;
221     char *types = NULL;
222     uint32_t flags = 0;
223     poptContext optCon = NULL;
224
225     rpmRC rc = RPMRC_FAIL;
226
227     struct poptOption optionsTable[] = {
228         {"name",  'n', POPT_ARG_STRING, &name,  'n', NULL, NULL},
229         {"types", 't', POPT_ARG_STRING, &types, 't', NULL, NULL},
230         {"base",  'b', POPT_ARGFLAG_OR, &flags, RPMPOL_FLAG_BASE, NULL, NULL},
231         POPT_TABLEEND
232     };
233
234     if (!spec || !pkg) {
235         goto exit;
236     }
237
238     for (ARGV_const_t pol = pkg->policyList; *pol != NULL; pol++) {
239         ModuleRec mod;
240         const char *line = *pol;
241         const char **argv = NULL;
242         int argc = 0;
243         int err;
244
245         if ((err = poptParseArgvString(line, &argc, &argv))) {
246             rpmlog(RPMLOG_ERR, _("Error parsing %s: %s\n"),
247                    line, poptStrerror(err));
248             goto exit;
249         }
250
251         if (!rstreq(argv[0], "%semodule")) {
252             rpmlog(RPMLOG_ERR, _("Expecting %%semodule tag: %s\n"), line);
253             goto exit;
254         }
255
256         optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
257         while (poptGetNextOpt(optCon) > 0) {
258         }
259
260         path = poptGetArg(optCon);
261         if (!path) {
262             rpmlog(RPMLOG_ERR, _("Missing module path in line: %s\n"),
263                    line);
264             goto exit;
265         }
266
267         if (poptPeekArg(optCon)) {
268             rpmlog(RPMLOG_ERR, _("Too many arguments in line: %s\n"),
269                    line);
270             goto exit;
271         }
272
273         mod = newModule(path, name, types, flags);
274         if (!mod) {
275             goto exit;
276         }
277
278         if (writeModuleToHeader(mod, pkg) != RPMRC_OK) {
279             freeModule(mod);
280             goto exit;
281         }
282
283         freeModule(mod);
284     }
285
286     rc = RPMRC_OK;
287
288   exit:
289
290     return rc;
291 }
292 #endif
293
294 rpmRC processBinaryPolicies(rpmSpec spec, int test)
295 {
296     rpmRC rc = RPMRC_OK;
297 #if WITH_SELINUX
298     Package pkg;
299     char *nvr;
300
301     for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
302         if (pkg->policyList == NULL) {
303             continue;
304         }
305
306         nvr = headerGetAsString(pkg->header, RPMTAG_NVRA);
307         rpmlog(RPMLOG_NOTICE, _("Processing policies: %s\n"), nvr);
308         free(nvr);
309
310         if (processPolicies(spec, pkg, test) != RPMRC_OK) {
311             rc = RPMRC_FAIL;
312             break;
313         }
314     }
315 #endif
316
317     return rc;
318 }