1/* Author: Karl MacMillan <kmacmillan@tresys.com>
2 *         Jason Tang     <jtang@tresys.com>
3 *         Chris PeBenito <cpebenito@tresys.com>
4 *
5 * Copyright (C) 2004-2005 Tresys Technology, LLC
6 *
7 *  This library is free software; you can redistribute it and/or
8 *  modify it under the terms of the GNU Lesser General Public
9 *  License as published by the Free Software Foundation; either
10 *  version 2.1 of the License, or (at your option) any later version.
11 *
12 *  This library is distributed in the hope that it will be useful,
13 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 *  Lesser General Public License for more details.
16 *
17 *  You should have received a copy of the GNU Lesser General Public
18 *  License along with this library; if not, write to the Free Software
19 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 */
21
22#include "policydb_internal.h"
23#include "module_internal.h"
24#include <sepol/policydb/link.h>
25#include <sepol/policydb/expand.h>
26#include <sepol/policydb/module.h>
27#include "debug.h"
28#include "private.h"
29
30#include <stdio.h>
31#include <stdlib.h>
32#include <limits.h>
33
34#define SEPOL_PACKAGE_SECTION_FC 0xf97cff90
35#define SEPOL_PACKAGE_SECTION_SEUSER 0x97cff91
36#define SEPOL_PACKAGE_SECTION_USER_EXTRA 0x97cff92
37#define SEPOL_PACKAGE_SECTION_NETFILTER 0x97cff93
38
39static int policy_file_seek(struct policy_file *fp, size_t offset)
40{
41	switch (fp->type) {
42	case PF_USE_STDIO:
43		if (offset > LONG_MAX) {
44			errno = EFAULT;
45			return -1;
46		}
47		return fseek(fp->fp, (long)offset, SEEK_SET);
48	case PF_USE_MEMORY:
49		if (offset > fp->size) {
50			errno = EFAULT;
51			return -1;
52		}
53		fp->data -= fp->size - fp->len;
54		fp->data += offset;
55		fp->len = fp->size - offset;
56		return 0;
57	default:
58		return 0;
59	}
60}
61
62static size_t policy_file_length(struct policy_file *fp)
63{
64	long prev_offset, end_offset;
65	switch (fp->type) {
66	case PF_USE_STDIO:
67		prev_offset = ftell(fp->fp);
68		fseek(fp->fp, 0L, SEEK_END);
69		end_offset = ftell(fp->fp);
70		fseek(fp->fp, prev_offset, SEEK_SET);
71		return end_offset;
72	case PF_USE_MEMORY:
73		return fp->size;
74	default:
75		return 0;
76	}
77}
78
79static int module_package_init(sepol_module_package_t * p)
80{
81	memset(p, 0, sizeof(sepol_module_package_t));
82	if (sepol_policydb_create(&p->policy))
83		return -1;
84
85	p->version = 1;
86	return 0;
87}
88
89static int set_char(char **field, char *data, size_t len)
90{
91	if (*field) {
92		free(*field);
93		*field = NULL;
94	}
95	if (len) {
96		*field = malloc(len);
97		if (!*field)
98			return -1;
99		memcpy(*field, data, len);
100	}
101	return 0;
102}
103
104int sepol_module_package_create(sepol_module_package_t ** p)
105{
106	*p = calloc(1, sizeof(sepol_module_package_t));
107	if (!(*p))
108		return -1;
109	return module_package_init(*p);
110}
111
112hidden_def(sepol_module_package_create)
113
114/* Deallocates all memory associated with a module package, including
115 * the pointer itself.  Does nothing if p is NULL.
116 */
117void sepol_module_package_free(sepol_module_package_t * p)
118{
119	if (p == NULL)
120		return;
121
122	sepol_policydb_free(p->policy);
123	free(p->file_contexts);
124	free(p->seusers);
125	free(p->user_extra);
126	free(p->netfilter_contexts);
127	free(p);
128}
129
130hidden_def(sepol_module_package_free)
131
132char *sepol_module_package_get_file_contexts(sepol_module_package_t * p)
133{
134	return p->file_contexts;
135}
136
137size_t sepol_module_package_get_file_contexts_len(sepol_module_package_t * p)
138{
139	return p->file_contexts_len;
140}
141
142char *sepol_module_package_get_seusers(sepol_module_package_t * p)
143{
144	return p->seusers;
145}
146
147size_t sepol_module_package_get_seusers_len(sepol_module_package_t * p)
148{
149	return p->seusers_len;
150}
151
152char *sepol_module_package_get_user_extra(sepol_module_package_t * p)
153{
154	return p->user_extra;
155}
156
157size_t sepol_module_package_get_user_extra_len(sepol_module_package_t * p)
158{
159	return p->user_extra_len;
160}
161
162char *sepol_module_package_get_netfilter_contexts(sepol_module_package_t * p)
163{
164	return p->netfilter_contexts;
165}
166
167size_t sepol_module_package_get_netfilter_contexts_len(sepol_module_package_t *
168						       p)
169{
170	return p->netfilter_contexts_len;
171}
172
173int sepol_module_package_set_file_contexts(sepol_module_package_t * p,
174					   char *data, size_t len)
175{
176	if (set_char(&p->file_contexts, data, len))
177		return -1;
178
179	p->file_contexts_len = len;
180	return 0;
181}
182
183int sepol_module_package_set_seusers(sepol_module_package_t * p,
184				     char *data, size_t len)
185{
186	if (set_char(&p->seusers, data, len))
187		return -1;
188
189	p->seusers_len = len;
190	return 0;
191}
192
193int sepol_module_package_set_user_extra(sepol_module_package_t * p,
194					char *data, size_t len)
195{
196	if (set_char(&p->user_extra, data, len))
197		return -1;
198
199	p->user_extra_len = len;
200	return 0;
201}
202
203int sepol_module_package_set_netfilter_contexts(sepol_module_package_t * p,
204						char *data, size_t len)
205{
206	if (set_char(&p->netfilter_contexts, data, len))
207		return -1;
208
209	p->netfilter_contexts_len = len;
210	return 0;
211}
212
213sepol_policydb_t *sepol_module_package_get_policy(sepol_module_package_t * p)
214{
215	return p->policy;
216}
217
218/* Append each of the file contexts from each module to the base
219 * policy's file context.  'base_context' will be reallocated to a
220 * larger size (and thus it is an in/out reference
221 * variable). 'base_fc_len' is the length of base's file context; it
222 * too is a reference variable.  Return 0 on success, -1 if out of
223 * memory. */
224static int link_file_contexts(sepol_module_package_t * base,
225			      sepol_module_package_t ** modules,
226			      int num_modules)
227{
228	size_t fc_len;
229	int i;
230	char *s;
231
232	fc_len = base->file_contexts_len;
233	for (i = 0; i < num_modules; i++) {
234		fc_len += modules[i]->file_contexts_len;
235	}
236
237	if ((s = (char *)realloc(base->file_contexts, fc_len)) == NULL) {
238		return -1;
239	}
240	base->file_contexts = s;
241	for (i = 0; i < num_modules; i++) {
242		memcpy(base->file_contexts + base->file_contexts_len,
243		       modules[i]->file_contexts,
244		       modules[i]->file_contexts_len);
245		base->file_contexts_len += modules[i]->file_contexts_len;
246	}
247	return 0;
248}
249
250/* Append each of the netfilter contexts from each module to the base
251 * policy's netfilter context.  'base_context' will be reallocated to a
252 * larger size (and thus it is an in/out reference
253 * variable). 'base_nc_len' is the length of base's netfilter contexts; it
254 * too is a reference variable.  Return 0 on success, -1 if out of
255 * memory. */
256static int link_netfilter_contexts(sepol_module_package_t * base,
257				   sepol_module_package_t ** modules,
258				   int num_modules)
259{
260	size_t base_nc_len;
261	int i;
262	char *base_context;
263
264	base_nc_len = base->netfilter_contexts_len;
265	for (i = 0; i < num_modules; i++) {
266		base_nc_len += modules[i]->netfilter_contexts_len;
267	}
268
269	if ((base_context =
270	     (char *)realloc(base->netfilter_contexts, base_nc_len)) == NULL) {
271		return -1;
272	}
273	base->netfilter_contexts = base_context;
274	for (i = 0; i < num_modules; i++) {
275		memcpy(base->netfilter_contexts + base->netfilter_contexts_len,
276		       modules[i]->netfilter_contexts,
277		       modules[i]->netfilter_contexts_len);
278		base->netfilter_contexts_len +=
279		    modules[i]->netfilter_contexts_len;
280	}
281	return 0;
282}
283
284/* Links the module packages into the base.  Returns 0 on success, -1
285 * if a requirement was not met, or -2 for all other errors. */
286int sepol_link_packages(sepol_handle_t * handle,
287			sepol_module_package_t * base,
288			sepol_module_package_t ** modules, int num_modules,
289			int verbose)
290{
291	policydb_t **mod_pols = NULL;
292	int i, retval;
293
294	if ((mod_pols = calloc(num_modules, sizeof(*mod_pols))) == NULL) {
295		ERR(handle, "Out of memory!");
296		return -2;
297	}
298	for (i = 0; i < num_modules; i++) {
299		mod_pols[i] = &modules[i]->policy->p;
300	}
301
302	retval = link_modules(handle, &base->policy->p, mod_pols, num_modules,
303			      verbose);
304	free(mod_pols);
305	if (retval == -3) {
306		return -1;
307	} else if (retval < 0) {
308		return -2;
309	}
310
311	if (link_file_contexts(base, modules, num_modules) == -1) {
312		ERR(handle, "Out of memory!");
313		return -2;
314	}
315
316	if (link_netfilter_contexts(base, modules, num_modules) == -1) {
317		ERR(handle, "Out of memory!");
318		return -2;
319	}
320
321	return 0;
322}
323
324/* buf must be large enough - no checks are performed */
325#define _read_helper_bufsize BUFSIZ
326static int read_helper(char *buf, struct policy_file *file, uint32_t bytes)
327{
328	uint32_t offset, nel, read_len;
329	int rc;
330
331	offset = 0;
332	nel = bytes;
333
334	while (nel) {
335		if (nel < _read_helper_bufsize)
336			read_len = nel;
337		else
338			read_len = _read_helper_bufsize;
339		rc = next_entry(&buf[offset], file, read_len);
340		if (rc < 0)
341			return -1;
342		offset += read_len;
343		nel -= read_len;
344	}
345	return 0;
346}
347
348#define MAXSECTIONS 100
349
350/* Get the section offsets from a package file, offsets will be malloc'd to
351 * the appropriate size and the caller must free() them */
352static int module_package_read_offsets(sepol_module_package_t * mod,
353				       struct policy_file *file,
354				       size_t ** offsets, uint32_t * sections)
355{
356	uint32_t *buf = NULL, nsec;
357	unsigned i;
358	size_t *off = NULL;
359	int rc;
360
361	buf = malloc(sizeof(uint32_t)*3);
362	if (!buf) {
363		ERR(file->handle, "out of memory");
364		goto err;
365	}
366
367	rc = next_entry(buf, file, sizeof(uint32_t) * 3);
368	if (rc < 0) {
369		ERR(file->handle, "module package header truncated");
370		goto err;
371	}
372	if (le32_to_cpu(buf[0]) != SEPOL_MODULE_PACKAGE_MAGIC) {
373		ERR(file->handle,
374		    "wrong magic number for module package:  expected %#08x, got %#08x",
375		    SEPOL_MODULE_PACKAGE_MAGIC, le32_to_cpu(buf[0]));
376		goto err;
377	}
378
379	mod->version = le32_to_cpu(buf[1]);
380	nsec = *sections = le32_to_cpu(buf[2]);
381
382	if (nsec > MAXSECTIONS) {
383		ERR(file->handle, "too many sections (%u) in module package",
384		    nsec);
385		goto err;
386	}
387
388	off = (size_t *) malloc((nsec + 1) * sizeof(size_t));
389	if (!off) {
390		ERR(file->handle, "out of memory");
391		goto err;
392	}
393
394	free(buf);
395	buf = malloc(sizeof(uint32_t) * nsec);
396	if (!buf) {
397		ERR(file->handle, "out of memory");
398		goto err;
399	}
400	rc = next_entry(buf, file, sizeof(uint32_t) * nsec);
401	if (rc < 0) {
402		ERR(file->handle, "module package offset array truncated");
403		goto err;
404	}
405
406	for (i = 0; i < nsec; i++) {
407		off[i] = le32_to_cpu(buf[i]);
408		if (i && off[i] < off[i - 1]) {
409			ERR(file->handle, "offsets are not increasing (at %u, "
410			    "offset %zu -> %zu", i, off[i - 1],
411			    off[i]);
412			goto err;
413		}
414	}
415
416	off[nsec] = policy_file_length(file);
417	if (nsec && off[nsec] < off[nsec-1]) {
418		ERR(file->handle, "offset greater than file size (at %u, "
419		    "offset %zu -> %zu", nsec, off[nsec - 1],
420		    off[nsec]);
421		goto err;
422	}
423	*offsets = off;
424	free(buf);
425	return 0;
426
427err:
428	free(buf);
429	free(off);
430	return -1;
431}
432
433/* Flags for which sections have been seen during parsing of module package. */
434#define SEEN_MOD 1
435#define SEEN_FC  2
436#define SEEN_SEUSER 4
437#define SEEN_USER_EXTRA 8
438#define SEEN_NETFILTER 16
439
440int sepol_module_package_read(sepol_module_package_t * mod,
441			      struct sepol_policy_file *spf, int verbose)
442{
443	struct policy_file *file = &spf->pf;
444	uint32_t buf[1], nsec;
445	size_t *offsets, len;
446	int rc;
447	unsigned i, seen = 0;
448
449	if (module_package_read_offsets(mod, file, &offsets, &nsec))
450		return -1;
451
452	/* we know the section offsets, seek to them and read in the data */
453
454	for (i = 0; i < nsec; i++) {
455
456		if (policy_file_seek(file, offsets[i])) {
457			ERR(file->handle, "error seeking to offset %zu for "
458			    "module package section %u", offsets[i], i);
459			goto cleanup;
460		}
461
462		len = offsets[i + 1] - offsets[i];
463
464		if (len < sizeof(uint32_t)) {
465			ERR(file->handle, "module package section %u "
466			    "has too small length %zu", i, len);
467			goto cleanup;
468		}
469
470		/* read the magic number, so that we know which function to call */
471		rc = next_entry(buf, file, sizeof(uint32_t));
472		if (rc < 0) {
473			ERR(file->handle,
474			    "module package section %u truncated, lacks magic number",
475			    i);
476			goto cleanup;
477		}
478
479		switch (le32_to_cpu(buf[0])) {
480		case SEPOL_PACKAGE_SECTION_FC:
481			if (seen & SEEN_FC) {
482				ERR(file->handle,
483				    "found multiple file contexts sections in module package (at section %u)",
484				    i);
485				goto cleanup;
486			}
487
488			mod->file_contexts_len = len - sizeof(uint32_t);
489			mod->file_contexts =
490			    (char *)malloc(mod->file_contexts_len);
491			if (!mod->file_contexts) {
492				ERR(file->handle, "out of memory");
493				goto cleanup;
494			}
495			if (read_helper
496			    (mod->file_contexts, file,
497			     mod->file_contexts_len)) {
498				ERR(file->handle,
499				    "invalid file contexts section at section %u",
500				    i);
501				free(mod->file_contexts);
502				mod->file_contexts = NULL;
503				goto cleanup;
504			}
505			seen |= SEEN_FC;
506			break;
507		case SEPOL_PACKAGE_SECTION_SEUSER:
508			if (seen & SEEN_SEUSER) {
509				ERR(file->handle,
510				    "found multiple seuser sections in module package (at section %u)",
511				    i);
512				goto cleanup;
513			}
514
515			mod->seusers_len = len - sizeof(uint32_t);
516			mod->seusers = (char *)malloc(mod->seusers_len);
517			if (!mod->seusers) {
518				ERR(file->handle, "out of memory");
519				goto cleanup;
520			}
521			if (read_helper(mod->seusers, file, mod->seusers_len)) {
522				ERR(file->handle,
523				    "invalid seuser section at section %u", i);
524				free(mod->seusers);
525				mod->seusers = NULL;
526				goto cleanup;
527			}
528			seen |= SEEN_SEUSER;
529			break;
530		case SEPOL_PACKAGE_SECTION_USER_EXTRA:
531			if (seen & SEEN_USER_EXTRA) {
532				ERR(file->handle,
533				    "found multiple user_extra sections in module package (at section %u)",
534				    i);
535				goto cleanup;
536			}
537
538			mod->user_extra_len = len - sizeof(uint32_t);
539			mod->user_extra = (char *)malloc(mod->user_extra_len);
540			if (!mod->user_extra) {
541				ERR(file->handle, "out of memory");
542				goto cleanup;
543			}
544			if (read_helper
545			    (mod->user_extra, file, mod->user_extra_len)) {
546				ERR(file->handle,
547				    "invalid user_extra section at section %u",
548				    i);
549				free(mod->user_extra);
550				mod->user_extra = NULL;
551				goto cleanup;
552			}
553			seen |= SEEN_USER_EXTRA;
554			break;
555		case SEPOL_PACKAGE_SECTION_NETFILTER:
556			if (seen & SEEN_NETFILTER) {
557				ERR(file->handle,
558				    "found multiple netfilter contexts sections in module package (at section %u)",
559				    i);
560				goto cleanup;
561			}
562
563			mod->netfilter_contexts_len = len - sizeof(uint32_t);
564			mod->netfilter_contexts =
565			    (char *)malloc(mod->netfilter_contexts_len);
566			if (!mod->netfilter_contexts) {
567				ERR(file->handle, "out of memory");
568				goto cleanup;
569			}
570			if (read_helper
571			    (mod->netfilter_contexts, file,
572			     mod->netfilter_contexts_len)) {
573				ERR(file->handle,
574				    "invalid netfilter contexts section at section %u",
575				    i);
576				free(mod->netfilter_contexts);
577				mod->netfilter_contexts = NULL;
578				goto cleanup;
579			}
580			seen |= SEEN_NETFILTER;
581			break;
582		case POLICYDB_MOD_MAGIC:
583			if (seen & SEEN_MOD) {
584				ERR(file->handle,
585				    "found multiple module sections in module package (at section %u)",
586				    i);
587				goto cleanup;
588			}
589
590			/* seek back to where the magic number was */
591			if (policy_file_seek(file, offsets[i]))
592				goto cleanup;
593
594			rc = policydb_read(&mod->policy->p, file, verbose);
595			if (rc < 0) {
596				ERR(file->handle,
597				    "invalid module in module package (at section %u)",
598				    i);
599				goto cleanup;
600			}
601			seen |= SEEN_MOD;
602			break;
603		default:
604			/* unknown section, ignore */
605			ERR(file->handle,
606			    "unknown magic number at section %u, offset: %zx, number: %ux ",
607			    i, offsets[i], le32_to_cpu(buf[0]));
608			break;
609		}
610	}
611
612	if ((seen & SEEN_MOD) == 0) {
613		ERR(file->handle, "missing module in module package");
614		goto cleanup;
615	}
616
617	free(offsets);
618	return 0;
619
620      cleanup:
621	free(offsets);
622	return -1;
623}
624
625int sepol_module_package_info(struct sepol_policy_file *spf, int *type,
626			      char **name, char **version)
627{
628	struct policy_file *file = &spf->pf;
629	sepol_module_package_t *mod = NULL;
630	uint32_t buf[5], len, nsec;
631	size_t *offsets = NULL;
632	unsigned i, seen = 0;
633	char *id;
634	int rc;
635
636	if (sepol_module_package_create(&mod))
637		return -1;
638
639	if (module_package_read_offsets(mod, file, &offsets, &nsec)) {
640		goto cleanup;
641	}
642
643	for (i = 0; i < nsec; i++) {
644
645		if (policy_file_seek(file, offsets[i])) {
646			ERR(file->handle, "error seeking to offset "
647			    "%zu for module package section %u", offsets[i], i);
648			goto cleanup;
649		}
650
651		len = offsets[i + 1] - offsets[i];
652
653		if (len < sizeof(uint32_t)) {
654			ERR(file->handle,
655			    "module package section %u has too small length %u",
656			    i, len);
657			goto cleanup;
658		}
659
660		/* read the magic number, so that we know which function to call */
661		rc = next_entry(buf, file, sizeof(uint32_t) * 2);
662		if (rc < 0) {
663			ERR(file->handle,
664			    "module package section %u truncated, lacks magic number",
665			    i);
666			goto cleanup;
667		}
668
669		switch (le32_to_cpu(buf[0])) {
670		case SEPOL_PACKAGE_SECTION_FC:
671			/* skip file contexts */
672			if (seen & SEEN_FC) {
673				ERR(file->handle,
674				    "found multiple file contexts sections in module package (at section %u)",
675				    i);
676				goto cleanup;
677			}
678			seen |= SEEN_FC;
679			break;
680		case SEPOL_PACKAGE_SECTION_SEUSER:
681			/* skip seuser */
682			if (seen & SEEN_SEUSER) {
683				ERR(file->handle,
684				    "found seuser sections in module package (at section %u)",
685				    i);
686				goto cleanup;
687			}
688			seen |= SEEN_SEUSER;
689			break;
690		case SEPOL_PACKAGE_SECTION_USER_EXTRA:
691			/* skip user_extra */
692			if (seen & SEEN_USER_EXTRA) {
693				ERR(file->handle,
694				    "found user_extra sections in module package (at section %u)",
695				    i);
696				goto cleanup;
697			}
698			seen |= SEEN_USER_EXTRA;
699			break;
700		case SEPOL_PACKAGE_SECTION_NETFILTER:
701			/* skip netfilter contexts */
702			if (seen & SEEN_NETFILTER) {
703				ERR(file->handle,
704				    "found multiple netfilter contexts sections in module package (at section %u)",
705				    i);
706				goto cleanup;
707			}
708			seen |= SEEN_NETFILTER;
709			break;
710		case POLICYDB_MOD_MAGIC:
711			if (seen & SEEN_MOD) {
712				ERR(file->handle,
713				    "found multiple module sections in module package (at section %u)",
714				    i);
715				goto cleanup;
716			}
717			len = le32_to_cpu(buf[1]);
718			if (len != strlen(POLICYDB_MOD_STRING)) {
719				ERR(file->handle,
720				    "module string length is wrong (at section %u)",
721				    i);
722				goto cleanup;
723			}
724
725			/* skip id */
726			id = malloc(len + 1);
727			if (!id) {
728				ERR(file->handle,
729				    "out of memory (at section %u)",
730				    i);
731				goto cleanup;
732			}
733			rc = next_entry(id, file, len);
734			free(id);
735			if (rc < 0) {
736				ERR(file->handle,
737				    "cannot get module string (at section %u)",
738				    i);
739				goto cleanup;
740			}
741
742			rc = next_entry(buf, file, sizeof(uint32_t) * 5);
743			if (rc < 0) {
744				ERR(file->handle,
745				    "cannot get module header (at section %u)",
746				    i);
747				goto cleanup;
748			}
749
750			*type = le32_to_cpu(buf[0]);
751			/* if base - we're done */
752			if (*type == POLICY_BASE) {
753				*name = NULL;
754				*version = NULL;
755				seen |= SEEN_MOD;
756				break;
757			} else if (*type != POLICY_MOD) {
758				ERR(file->handle,
759				    "module has invalid type %d (at section %u)",
760				    *type, i);
761				goto cleanup;
762			}
763
764			/* read the name and version */
765			rc = next_entry(buf, file, sizeof(uint32_t));
766			if (rc < 0) {
767				ERR(file->handle,
768				    "cannot get module name len (at section %u)",
769				    i);
770				goto cleanup;
771			}
772			len = le32_to_cpu(buf[0]);
773			*name = malloc(len + 1);
774			if (!*name) {
775				ERR(file->handle, "out of memory");
776				goto cleanup;
777			}
778			rc = next_entry(*name, file, len);
779			if (rc < 0) {
780				ERR(file->handle,
781				    "cannot get module name string (at section %u)",
782				    i);
783				goto cleanup;
784			}
785			(*name)[len] = '\0';
786			rc = next_entry(buf, file, sizeof(uint32_t));
787			if (rc < 0) {
788				ERR(file->handle,
789				    "cannot get module version len (at section %u)",
790				    i);
791				goto cleanup;
792			}
793			len = le32_to_cpu(buf[0]);
794			*version = malloc(len + 1);
795			if (!*version) {
796				ERR(file->handle, "out of memory");
797				goto cleanup;
798			}
799			rc = next_entry(*version, file, len);
800			if (rc < 0) {
801				ERR(file->handle,
802				    "cannot get module version string (at section %u)",
803				    i);
804				goto cleanup;
805			}
806			(*version)[len] = '\0';
807			seen |= SEEN_MOD;
808			break;
809		default:
810			break;
811		}
812
813	}
814
815	if ((seen & SEEN_MOD) == 0) {
816		ERR(file->handle, "missing module in module package");
817		goto cleanup;
818	}
819
820	sepol_module_package_free(mod);
821	free(offsets);
822	return 0;
823
824      cleanup:
825	sepol_module_package_free(mod);
826	free(offsets);
827	return -1;
828}
829
830static int write_helper(char *data, size_t len, struct policy_file *file)
831{
832	int idx = 0;
833	size_t len2;
834
835	while (len) {
836		if (len > BUFSIZ)
837			len2 = BUFSIZ;
838		else
839			len2 = len;
840
841		if (put_entry(&data[idx], 1, len2, file) != len2) {
842			return -1;
843		}
844		len -= len2;
845		idx += len2;
846	}
847	return 0;
848}
849
850int sepol_module_package_write(sepol_module_package_t * p,
851			       struct sepol_policy_file *spf)
852{
853	struct policy_file *file = &spf->pf;
854	policy_file_t polfile;
855	uint32_t buf[5], offsets[5], len, nsec = 0;
856	int i;
857
858	if (p->policy) {
859		/* compute policy length */
860		policy_file_init(&polfile);
861		polfile.type = PF_LEN;
862		polfile.handle = file->handle;
863		if (policydb_write(&p->policy->p, &polfile))
864			return -1;
865		len = polfile.len;
866		if (!polfile.len)
867			return -1;
868		nsec++;
869
870	} else {
871		/* We don't support writing a package without a module at this point */
872		return -1;
873	}
874
875	/* seusers and user_extra only supported in base at the moment */
876	if ((p->seusers || p->user_extra)
877	    && (p->policy->p.policy_type != SEPOL_POLICY_BASE)) {
878		ERR(file->handle,
879		    "seuser and user_extra sections only supported in base");
880		return -1;
881	}
882
883	if (p->file_contexts)
884		nsec++;
885
886	if (p->seusers)
887		nsec++;
888
889	if (p->user_extra)
890		nsec++;
891
892	if (p->netfilter_contexts)
893		nsec++;
894
895	buf[0] = cpu_to_le32(SEPOL_MODULE_PACKAGE_MAGIC);
896	buf[1] = cpu_to_le32(p->version);
897	buf[2] = cpu_to_le32(nsec);
898	if (put_entry(buf, sizeof(uint32_t), 3, file) != 3)
899		return -1;
900
901	/* calculate offsets */
902	offsets[0] = (nsec + 3) * sizeof(uint32_t);
903	buf[0] = cpu_to_le32(offsets[0]);
904
905	i = 1;
906	if (p->file_contexts) {
907		offsets[i] = offsets[i - 1] + len;
908		buf[i] = cpu_to_le32(offsets[i]);
909		/* add a uint32_t to compensate for the magic number */
910		len = p->file_contexts_len + sizeof(uint32_t);
911		i++;
912	}
913	if (p->seusers) {
914		offsets[i] = offsets[i - 1] + len;
915		buf[i] = cpu_to_le32(offsets[i]);
916		len = p->seusers_len + sizeof(uint32_t);
917		i++;
918	}
919	if (p->user_extra) {
920		offsets[i] = offsets[i - 1] + len;
921		buf[i] = cpu_to_le32(offsets[i]);
922		len = p->user_extra_len + sizeof(uint32_t);
923		i++;
924	}
925	if (p->netfilter_contexts) {
926		offsets[i] = offsets[i - 1] + len;
927		buf[i] = cpu_to_le32(offsets[i]);
928		len = p->netfilter_contexts_len + sizeof(uint32_t);
929		i++;
930	}
931	if (put_entry(buf, sizeof(uint32_t), nsec, file) != nsec)
932		return -1;
933
934	/* write sections */
935
936	if (policydb_write(&p->policy->p, file))
937		return -1;
938
939	if (p->file_contexts) {
940		buf[0] = cpu_to_le32(SEPOL_PACKAGE_SECTION_FC);
941		if (put_entry(buf, sizeof(uint32_t), 1, file) != 1)
942			return -1;
943		if (write_helper(p->file_contexts, p->file_contexts_len, file))
944			return -1;
945	}
946	if (p->seusers) {
947		buf[0] = cpu_to_le32(SEPOL_PACKAGE_SECTION_SEUSER);
948		if (put_entry(buf, sizeof(uint32_t), 1, file) != 1)
949			return -1;
950		if (write_helper(p->seusers, p->seusers_len, file))
951			return -1;
952
953	}
954	if (p->user_extra) {
955		buf[0] = cpu_to_le32(SEPOL_PACKAGE_SECTION_USER_EXTRA);
956		if (put_entry(buf, sizeof(uint32_t), 1, file) != 1)
957			return -1;
958		if (write_helper(p->user_extra, p->user_extra_len, file))
959			return -1;
960	}
961	if (p->netfilter_contexts) {
962		buf[0] = cpu_to_le32(SEPOL_PACKAGE_SECTION_NETFILTER);
963		if (put_entry(buf, sizeof(uint32_t), 1, file) != 1)
964			return -1;
965		if (write_helper
966		    (p->netfilter_contexts, p->netfilter_contexts_len, file))
967			return -1;
968	}
969	return 0;
970}
971
972int sepol_link_modules(sepol_handle_t * handle,
973		       sepol_policydb_t * base,
974		       sepol_policydb_t ** modules, size_t len, int verbose)
975{
976	return link_modules(handle, &base->p, (policydb_t **) modules, len,
977			    verbose);
978}
979
980int sepol_expand_module(sepol_handle_t * handle,
981			sepol_policydb_t * base,
982			sepol_policydb_t * out, int verbose, int check)
983{
984	return expand_module(handle, &base->p, &out->p, verbose, check);
985}
986