xref: /aosp_15_r20/external/selinux/libsemanage/src/semanage_store.c (revision 2d543d20722ada2425b5bdab9d0d1d29470e7bba)
1*2d543d20SAndroid Build Coastguard Worker /* Authors: Karl MacMillan <[email protected]>
2*2d543d20SAndroid Build Coastguard Worker  *	    Joshua Brindle <[email protected]>
3*2d543d20SAndroid Build Coastguard Worker  *	    Jason Tang <[email protected]>
4*2d543d20SAndroid Build Coastguard Worker  *          Christopher Ashworth <[email protected]>
5*2d543d20SAndroid Build Coastguard Worker  *          Chris PeBenito <[email protected]>
6*2d543d20SAndroid Build Coastguard Worker  *	    Caleb Case <[email protected]>
7*2d543d20SAndroid Build Coastguard Worker  *
8*2d543d20SAndroid Build Coastguard Worker  * Copyright (C) 2004-2006,2009 Tresys Technology, LLC
9*2d543d20SAndroid Build Coastguard Worker  * Copyright (C) 2005 Red Hat, Inc.
10*2d543d20SAndroid Build Coastguard Worker  *
11*2d543d20SAndroid Build Coastguard Worker  *  This library is free software; you can redistribute it and/or
12*2d543d20SAndroid Build Coastguard Worker  *  modify it under the terms of the GNU Lesser General Public
13*2d543d20SAndroid Build Coastguard Worker  *  License as published by the Free Software Foundation; either
14*2d543d20SAndroid Build Coastguard Worker  *  version 2.1 of the License, or (at your option) any later version.
15*2d543d20SAndroid Build Coastguard Worker  *
16*2d543d20SAndroid Build Coastguard Worker  *  This library is distributed in the hope that it will be useful,
17*2d543d20SAndroid Build Coastguard Worker  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18*2d543d20SAndroid Build Coastguard Worker  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19*2d543d20SAndroid Build Coastguard Worker  *  Lesser General Public License for more details.
20*2d543d20SAndroid Build Coastguard Worker  *
21*2d543d20SAndroid Build Coastguard Worker  *  You should have received a copy of the GNU Lesser General Public
22*2d543d20SAndroid Build Coastguard Worker  *  License along with this library; if not, write to the Free Software
23*2d543d20SAndroid Build Coastguard Worker  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
24*2d543d20SAndroid Build Coastguard Worker  */
25*2d543d20SAndroid Build Coastguard Worker 
26*2d543d20SAndroid Build Coastguard Worker /* This file contains semanage routines that manipulate the files on a
27*2d543d20SAndroid Build Coastguard Worker  * local module store.	Sandbox routines, used by both source and
28*2d543d20SAndroid Build Coastguard Worker  * direct connections, are here as well.
29*2d543d20SAndroid Build Coastguard Worker  */
30*2d543d20SAndroid Build Coastguard Worker 
31*2d543d20SAndroid Build Coastguard Worker struct dbase_policydb;
32*2d543d20SAndroid Build Coastguard Worker typedef struct dbase_policydb dbase_t;
33*2d543d20SAndroid Build Coastguard Worker #define DBASE_DEFINED
34*2d543d20SAndroid Build Coastguard Worker 
35*2d543d20SAndroid Build Coastguard Worker #include "semanage_store.h"
36*2d543d20SAndroid Build Coastguard Worker #include "database_policydb.h"
37*2d543d20SAndroid Build Coastguard Worker #include "handle.h"
38*2d543d20SAndroid Build Coastguard Worker 
39*2d543d20SAndroid Build Coastguard Worker #include <selinux/restorecon.h>
40*2d543d20SAndroid Build Coastguard Worker #include <selinux/selinux.h>
41*2d543d20SAndroid Build Coastguard Worker #include <sepol/policydb.h>
42*2d543d20SAndroid Build Coastguard Worker #include <sepol/module.h>
43*2d543d20SAndroid Build Coastguard Worker 
44*2d543d20SAndroid Build Coastguard Worker #include <assert.h>
45*2d543d20SAndroid Build Coastguard Worker #include <ctype.h>
46*2d543d20SAndroid Build Coastguard Worker #include <dirent.h>
47*2d543d20SAndroid Build Coastguard Worker #include <errno.h>
48*2d543d20SAndroid Build Coastguard Worker #include <fcntl.h>
49*2d543d20SAndroid Build Coastguard Worker #include <stdio.h>
50*2d543d20SAndroid Build Coastguard Worker #include <stdio_ext.h>
51*2d543d20SAndroid Build Coastguard Worker #include <stdlib.h>
52*2d543d20SAndroid Build Coastguard Worker #include <string.h>
53*2d543d20SAndroid Build Coastguard Worker #include <unistd.h>
54*2d543d20SAndroid Build Coastguard Worker #include <sys/file.h>
55*2d543d20SAndroid Build Coastguard Worker #include <sys/stat.h>
56*2d543d20SAndroid Build Coastguard Worker #include <sys/types.h>
57*2d543d20SAndroid Build Coastguard Worker #include <sys/wait.h>
58*2d543d20SAndroid Build Coastguard Worker #include <limits.h>
59*2d543d20SAndroid Build Coastguard Worker #include <libgen.h>
60*2d543d20SAndroid Build Coastguard Worker 
61*2d543d20SAndroid Build Coastguard Worker #include "debug.h"
62*2d543d20SAndroid Build Coastguard Worker #include "utilities.h"
63*2d543d20SAndroid Build Coastguard Worker #include "compressed_file.h"
64*2d543d20SAndroid Build Coastguard Worker 
65*2d543d20SAndroid Build Coastguard Worker #define SEMANAGE_CONF_FILE "semanage.conf"
66*2d543d20SAndroid Build Coastguard Worker /* relative path names to enum semanage_paths to special files and
67*2d543d20SAndroid Build Coastguard Worker  * directories for the module store */
68*2d543d20SAndroid Build Coastguard Worker 
69*2d543d20SAndroid Build Coastguard Worker #define TRUE 1
70*2d543d20SAndroid Build Coastguard Worker 
71*2d543d20SAndroid Build Coastguard Worker enum semanage_file_defs {
72*2d543d20SAndroid Build Coastguard Worker 	SEMANAGE_ROOT,
73*2d543d20SAndroid Build Coastguard Worker 	SEMANAGE_TRANS_LOCK,
74*2d543d20SAndroid Build Coastguard Worker 	SEMANAGE_READ_LOCK,
75*2d543d20SAndroid Build Coastguard Worker 	SEMANAGE_NUM_FILES
76*2d543d20SAndroid Build Coastguard Worker };
77*2d543d20SAndroid Build Coastguard Worker 
78*2d543d20SAndroid Build Coastguard Worker static char *semanage_paths[SEMANAGE_NUM_STORES][SEMANAGE_STORE_NUM_PATHS];
79*2d543d20SAndroid Build Coastguard Worker static char *semanage_files[SEMANAGE_NUM_FILES] = { NULL };
80*2d543d20SAndroid Build Coastguard Worker static int semanage_paths_initialized = 0;
81*2d543d20SAndroid Build Coastguard Worker 
82*2d543d20SAndroid Build Coastguard Worker /* These are paths relative to the bottom of the module store */
83*2d543d20SAndroid Build Coastguard Worker static const char *semanage_relative_files[SEMANAGE_NUM_FILES] = {
84*2d543d20SAndroid Build Coastguard Worker 	"",
85*2d543d20SAndroid Build Coastguard Worker 	"/semanage.trans.LOCK",
86*2d543d20SAndroid Build Coastguard Worker 	"/semanage.read.LOCK"
87*2d543d20SAndroid Build Coastguard Worker };
88*2d543d20SAndroid Build Coastguard Worker 
89*2d543d20SAndroid Build Coastguard Worker static const char *semanage_store_paths[SEMANAGE_NUM_STORES] = {
90*2d543d20SAndroid Build Coastguard Worker 	"/active",
91*2d543d20SAndroid Build Coastguard Worker 	"/previous",
92*2d543d20SAndroid Build Coastguard Worker 	"/tmp"
93*2d543d20SAndroid Build Coastguard Worker };
94*2d543d20SAndroid Build Coastguard Worker 
95*2d543d20SAndroid Build Coastguard Worker /* relative path names to enum sandbox_paths for special files within
96*2d543d20SAndroid Build Coastguard Worker  * a sandbox */
97*2d543d20SAndroid Build Coastguard Worker static const char *semanage_sandbox_paths[SEMANAGE_STORE_NUM_PATHS] = {
98*2d543d20SAndroid Build Coastguard Worker 	"",
99*2d543d20SAndroid Build Coastguard Worker 	"/modules",
100*2d543d20SAndroid Build Coastguard Worker 	"/policy.linked",
101*2d543d20SAndroid Build Coastguard Worker 	"/homedir_template",
102*2d543d20SAndroid Build Coastguard Worker 	"/file_contexts.template",
103*2d543d20SAndroid Build Coastguard Worker 	"/commit_num",
104*2d543d20SAndroid Build Coastguard Worker 	"/pkeys.local",
105*2d543d20SAndroid Build Coastguard Worker 	"/ibendports.local",
106*2d543d20SAndroid Build Coastguard Worker 	"/ports.local",
107*2d543d20SAndroid Build Coastguard Worker 	"/interfaces.local",
108*2d543d20SAndroid Build Coastguard Worker 	"/nodes.local",
109*2d543d20SAndroid Build Coastguard Worker 	"/booleans.local",
110*2d543d20SAndroid Build Coastguard Worker 	"/seusers.local",
111*2d543d20SAndroid Build Coastguard Worker 	"/seusers.linked",
112*2d543d20SAndroid Build Coastguard Worker 	"/users.local",
113*2d543d20SAndroid Build Coastguard Worker 	"/users_extra.local",
114*2d543d20SAndroid Build Coastguard Worker 	"/users_extra.linked",
115*2d543d20SAndroid Build Coastguard Worker 	"/users_extra",
116*2d543d20SAndroid Build Coastguard Worker 	"/disable_dontaudit",
117*2d543d20SAndroid Build Coastguard Worker 	"/preserve_tunables",
118*2d543d20SAndroid Build Coastguard Worker 	"/modules/disabled",
119*2d543d20SAndroid Build Coastguard Worker 	"/modules_checksum",
120*2d543d20SAndroid Build Coastguard Worker 	"/policy.kern",
121*2d543d20SAndroid Build Coastguard Worker 	"/file_contexts.local",
122*2d543d20SAndroid Build Coastguard Worker 	"/file_contexts.homedirs",
123*2d543d20SAndroid Build Coastguard Worker 	"/file_contexts",
124*2d543d20SAndroid Build Coastguard Worker 	"/seusers"
125*2d543d20SAndroid Build Coastguard Worker };
126*2d543d20SAndroid Build Coastguard Worker 
127*2d543d20SAndroid Build Coastguard Worker static char const * const semanage_final_prefix[SEMANAGE_FINAL_NUM] = {
128*2d543d20SAndroid Build Coastguard Worker 	"/final",
129*2d543d20SAndroid Build Coastguard Worker 	"",
130*2d543d20SAndroid Build Coastguard Worker };
131*2d543d20SAndroid Build Coastguard Worker 
132*2d543d20SAndroid Build Coastguard Worker static char *semanage_final[SEMANAGE_FINAL_NUM] = { NULL };
133*2d543d20SAndroid Build Coastguard Worker static char *semanage_final_suffix[SEMANAGE_FINAL_PATH_NUM] = { NULL };
134*2d543d20SAndroid Build Coastguard Worker static char *semanage_final_paths[SEMANAGE_FINAL_NUM][SEMANAGE_FINAL_PATH_NUM] = {{ NULL }};
135*2d543d20SAndroid Build Coastguard Worker 
136*2d543d20SAndroid Build Coastguard Worker /* A node used in a linked list of file contexts; used for sorting.
137*2d543d20SAndroid Build Coastguard Worker  */
138*2d543d20SAndroid Build Coastguard Worker typedef struct semanage_file_context_node {
139*2d543d20SAndroid Build Coastguard Worker 	char *path;
140*2d543d20SAndroid Build Coastguard Worker 	char *file_type;
141*2d543d20SAndroid Build Coastguard Worker 	char *context;
142*2d543d20SAndroid Build Coastguard Worker 	int path_len;
143*2d543d20SAndroid Build Coastguard Worker 	int effective_len;
144*2d543d20SAndroid Build Coastguard Worker 	int type_len;
145*2d543d20SAndroid Build Coastguard Worker 	int context_len;
146*2d543d20SAndroid Build Coastguard Worker 	int meta;		/* position of first meta char in path, -1 if none */
147*2d543d20SAndroid Build Coastguard Worker 	struct semanage_file_context_node *next;
148*2d543d20SAndroid Build Coastguard Worker } semanage_file_context_node_t;
149*2d543d20SAndroid Build Coastguard Worker 
150*2d543d20SAndroid Build Coastguard Worker /* A node used in a linked list of buckets that contain
151*2d543d20SAndroid Build Coastguard Worker  *  semanage_file_context_node lists.  Used for sorting.
152*2d543d20SAndroid Build Coastguard Worker  */
153*2d543d20SAndroid Build Coastguard Worker typedef struct semanage_file_context_bucket {
154*2d543d20SAndroid Build Coastguard Worker 	semanage_file_context_node_t *data;
155*2d543d20SAndroid Build Coastguard Worker 	struct semanage_file_context_bucket *next;
156*2d543d20SAndroid Build Coastguard Worker } semanage_file_context_bucket_t;
157*2d543d20SAndroid Build Coastguard Worker 
158*2d543d20SAndroid Build Coastguard Worker /* A node used in a linked list of netfilter rules.
159*2d543d20SAndroid Build Coastguard Worker  */
160*2d543d20SAndroid Build Coastguard Worker typedef struct semanage_netfilter_context_node {
161*2d543d20SAndroid Build Coastguard Worker 	char *rule;
162*2d543d20SAndroid Build Coastguard Worker 	size_t rule_len;
163*2d543d20SAndroid Build Coastguard Worker 	struct semanage_netfilter_context_node *next;
164*2d543d20SAndroid Build Coastguard Worker } semanage_netfilter_context_node_t;
165*2d543d20SAndroid Build Coastguard Worker 
166*2d543d20SAndroid Build Coastguard Worker /* Initialize the paths to config file, lock files and store root.
167*2d543d20SAndroid Build Coastguard Worker  */
semanage_init_paths(const char * root)168*2d543d20SAndroid Build Coastguard Worker static int semanage_init_paths(const char *root)
169*2d543d20SAndroid Build Coastguard Worker {
170*2d543d20SAndroid Build Coastguard Worker 	size_t len, prefix_len;
171*2d543d20SAndroid Build Coastguard Worker 	int i;
172*2d543d20SAndroid Build Coastguard Worker 
173*2d543d20SAndroid Build Coastguard Worker 	if (!root)
174*2d543d20SAndroid Build Coastguard Worker 		return -1;
175*2d543d20SAndroid Build Coastguard Worker 
176*2d543d20SAndroid Build Coastguard Worker 	prefix_len = strlen(root);
177*2d543d20SAndroid Build Coastguard Worker 
178*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < SEMANAGE_NUM_FILES; i++) {
179*2d543d20SAndroid Build Coastguard Worker 		len = (strlen(semanage_relative_files[i]) + prefix_len);
180*2d543d20SAndroid Build Coastguard Worker 		semanage_files[i] = calloc(len + 1, sizeof(char));
181*2d543d20SAndroid Build Coastguard Worker 		if (!semanage_files[i])
182*2d543d20SAndroid Build Coastguard Worker 			return -1;
183*2d543d20SAndroid Build Coastguard Worker 		sprintf(semanage_files[i], "%s%s", root,
184*2d543d20SAndroid Build Coastguard Worker 			semanage_relative_files[i]);
185*2d543d20SAndroid Build Coastguard Worker 	}
186*2d543d20SAndroid Build Coastguard Worker 
187*2d543d20SAndroid Build Coastguard Worker 	return 0;
188*2d543d20SAndroid Build Coastguard Worker }
189*2d543d20SAndroid Build Coastguard Worker 
190*2d543d20SAndroid Build Coastguard Worker /* This initializes the paths inside the stores, this is only necessary
191*2d543d20SAndroid Build Coastguard Worker  * when directly accessing the store
192*2d543d20SAndroid Build Coastguard Worker  */
semanage_init_store_paths(const char * root)193*2d543d20SAndroid Build Coastguard Worker static int semanage_init_store_paths(const char *root)
194*2d543d20SAndroid Build Coastguard Worker {
195*2d543d20SAndroid Build Coastguard Worker 	int i, j;
196*2d543d20SAndroid Build Coastguard Worker 	size_t len;
197*2d543d20SAndroid Build Coastguard Worker 	size_t prefix_len;
198*2d543d20SAndroid Build Coastguard Worker 
199*2d543d20SAndroid Build Coastguard Worker 	if (!root)
200*2d543d20SAndroid Build Coastguard Worker 		return -1;
201*2d543d20SAndroid Build Coastguard Worker 
202*2d543d20SAndroid Build Coastguard Worker 	prefix_len = strlen(root);
203*2d543d20SAndroid Build Coastguard Worker 
204*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < SEMANAGE_NUM_STORES; i++) {
205*2d543d20SAndroid Build Coastguard Worker 		for (j = 0; j < SEMANAGE_STORE_NUM_PATHS; j++) {
206*2d543d20SAndroid Build Coastguard Worker 			len = prefix_len + strlen(semanage_store_paths[i])
207*2d543d20SAndroid Build Coastguard Worker 			    + strlen(semanage_sandbox_paths[j]);
208*2d543d20SAndroid Build Coastguard Worker 			semanage_paths[i][j] = calloc(len + 1, sizeof(char));
209*2d543d20SAndroid Build Coastguard Worker 			if (!semanage_paths[i][j])
210*2d543d20SAndroid Build Coastguard Worker 				goto cleanup;
211*2d543d20SAndroid Build Coastguard Worker 			sprintf(semanage_paths[i][j], "%s%s%s", root,
212*2d543d20SAndroid Build Coastguard Worker 				semanage_store_paths[i],
213*2d543d20SAndroid Build Coastguard Worker 				semanage_sandbox_paths[j]);
214*2d543d20SAndroid Build Coastguard Worker 		}
215*2d543d20SAndroid Build Coastguard Worker 	}
216*2d543d20SAndroid Build Coastguard Worker 
217*2d543d20SAndroid Build Coastguard Worker       cleanup:
218*2d543d20SAndroid Build Coastguard Worker 	return 0;
219*2d543d20SAndroid Build Coastguard Worker }
220*2d543d20SAndroid Build Coastguard Worker 
semanage_init_final(semanage_handle_t * sh,const char * prefix)221*2d543d20SAndroid Build Coastguard Worker static int semanage_init_final(semanage_handle_t *sh, const char *prefix)
222*2d543d20SAndroid Build Coastguard Worker {
223*2d543d20SAndroid Build Coastguard Worker 	assert(sh);
224*2d543d20SAndroid Build Coastguard Worker 	assert(prefix);
225*2d543d20SAndroid Build Coastguard Worker 
226*2d543d20SAndroid Build Coastguard Worker 	int status = 0;
227*2d543d20SAndroid Build Coastguard Worker 	size_t len;
228*2d543d20SAndroid Build Coastguard Worker 	const char *store_path = sh->conf->store_path;
229*2d543d20SAndroid Build Coastguard Worker 	size_t store_len = strlen(store_path);
230*2d543d20SAndroid Build Coastguard Worker 
231*2d543d20SAndroid Build Coastguard Worker 	/* SEMANAGE_FINAL_TMP */
232*2d543d20SAndroid Build Coastguard Worker 	len = strlen(semanage_root()) +
233*2d543d20SAndroid Build Coastguard Worker 	      strlen(prefix) +
234*2d543d20SAndroid Build Coastguard Worker 	      strlen("/") +
235*2d543d20SAndroid Build Coastguard Worker 	      strlen(semanage_final_prefix[SEMANAGE_FINAL_TMP]) +
236*2d543d20SAndroid Build Coastguard Worker 	      store_len;
237*2d543d20SAndroid Build Coastguard Worker 	semanage_final[SEMANAGE_FINAL_TMP] = malloc(len + 1);
238*2d543d20SAndroid Build Coastguard Worker 	if (semanage_final[SEMANAGE_FINAL_TMP] == NULL) {
239*2d543d20SAndroid Build Coastguard Worker 		status = -1;
240*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
241*2d543d20SAndroid Build Coastguard Worker 	}
242*2d543d20SAndroid Build Coastguard Worker 
243*2d543d20SAndroid Build Coastguard Worker 	sprintf(semanage_final[SEMANAGE_FINAL_TMP],
244*2d543d20SAndroid Build Coastguard Worker 		"%s%s%s/%s",
245*2d543d20SAndroid Build Coastguard Worker 		semanage_root(),
246*2d543d20SAndroid Build Coastguard Worker 		prefix,
247*2d543d20SAndroid Build Coastguard Worker 		semanage_final_prefix[SEMANAGE_FINAL_TMP],
248*2d543d20SAndroid Build Coastguard Worker 		store_path);
249*2d543d20SAndroid Build Coastguard Worker 
250*2d543d20SAndroid Build Coastguard Worker 	/* SEMANAGE_FINAL_SELINUX */
251*2d543d20SAndroid Build Coastguard Worker 	const char *selinux_root = selinux_path();
252*2d543d20SAndroid Build Coastguard Worker 	len = strlen(semanage_root()) +
253*2d543d20SAndroid Build Coastguard Worker 	      strlen(selinux_root) +
254*2d543d20SAndroid Build Coastguard Worker 	      strlen(semanage_final_prefix[SEMANAGE_FINAL_SELINUX]) +
255*2d543d20SAndroid Build Coastguard Worker 	      store_len;
256*2d543d20SAndroid Build Coastguard Worker 	semanage_final[SEMANAGE_FINAL_SELINUX] = malloc(len + 1);
257*2d543d20SAndroid Build Coastguard Worker 	if (semanage_final[SEMANAGE_FINAL_SELINUX] == NULL) {
258*2d543d20SAndroid Build Coastguard Worker 		status = -1;
259*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
260*2d543d20SAndroid Build Coastguard Worker 	}
261*2d543d20SAndroid Build Coastguard Worker 
262*2d543d20SAndroid Build Coastguard Worker 	sprintf(semanage_final[SEMANAGE_FINAL_SELINUX],
263*2d543d20SAndroid Build Coastguard Worker 		"%s%s%s%s",
264*2d543d20SAndroid Build Coastguard Worker 		semanage_root(),
265*2d543d20SAndroid Build Coastguard Worker 		selinux_root,
266*2d543d20SAndroid Build Coastguard Worker 		semanage_final_prefix[SEMANAGE_FINAL_SELINUX],
267*2d543d20SAndroid Build Coastguard Worker 		store_path);
268*2d543d20SAndroid Build Coastguard Worker 
269*2d543d20SAndroid Build Coastguard Worker cleanup:
270*2d543d20SAndroid Build Coastguard Worker 	if (status != 0) {
271*2d543d20SAndroid Build Coastguard Worker 		int i;
272*2d543d20SAndroid Build Coastguard Worker 		for (i = 0; i < SEMANAGE_FINAL_NUM; i++) {
273*2d543d20SAndroid Build Coastguard Worker 			free(semanage_final[i]);
274*2d543d20SAndroid Build Coastguard Worker 			semanage_final[i] = NULL;
275*2d543d20SAndroid Build Coastguard Worker 		}
276*2d543d20SAndroid Build Coastguard Worker 	}
277*2d543d20SAndroid Build Coastguard Worker 
278*2d543d20SAndroid Build Coastguard Worker 	return status;
279*2d543d20SAndroid Build Coastguard Worker }
280*2d543d20SAndroid Build Coastguard Worker 
semanage_init_final_suffix(semanage_handle_t * sh)281*2d543d20SAndroid Build Coastguard Worker static int semanage_init_final_suffix(semanage_handle_t *sh)
282*2d543d20SAndroid Build Coastguard Worker {
283*2d543d20SAndroid Build Coastguard Worker 	int ret = 0;
284*2d543d20SAndroid Build Coastguard Worker 	int status = 0;
285*2d543d20SAndroid Build Coastguard Worker 	char path[PATH_MAX];
286*2d543d20SAndroid Build Coastguard Worker 	size_t offset = strlen(selinux_policy_root());
287*2d543d20SAndroid Build Coastguard Worker 
288*2d543d20SAndroid Build Coastguard Worker 	semanage_final_suffix[SEMANAGE_FINAL_TOPLEVEL] = strdup("");
289*2d543d20SAndroid Build Coastguard Worker 	if (semanage_final_suffix[SEMANAGE_FINAL_TOPLEVEL] == NULL) {
290*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Unable to allocate space for policy top level path.");
291*2d543d20SAndroid Build Coastguard Worker 		status = -1;
292*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
293*2d543d20SAndroid Build Coastguard Worker 	}
294*2d543d20SAndroid Build Coastguard Worker 
295*2d543d20SAndroid Build Coastguard Worker 	semanage_final_suffix[SEMANAGE_FC] =
296*2d543d20SAndroid Build Coastguard Worker 		strdup(selinux_file_context_path() + offset);
297*2d543d20SAndroid Build Coastguard Worker 	if (semanage_final_suffix[SEMANAGE_FC] == NULL) {
298*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Unable to allocate space for file context path.");
299*2d543d20SAndroid Build Coastguard Worker 		status = -1;
300*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
301*2d543d20SAndroid Build Coastguard Worker 	}
302*2d543d20SAndroid Build Coastguard Worker 
303*2d543d20SAndroid Build Coastguard Worker 	if (asprintf(&semanage_final_suffix[SEMANAGE_FC_BIN], "%s.bin",
304*2d543d20SAndroid Build Coastguard Worker 		     semanage_final_suffix[SEMANAGE_FC]) < 0) {
305*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Unable to allocate space for file context path.");
306*2d543d20SAndroid Build Coastguard Worker 		status = -1;
307*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
308*2d543d20SAndroid Build Coastguard Worker 	}
309*2d543d20SAndroid Build Coastguard Worker 
310*2d543d20SAndroid Build Coastguard Worker 	semanage_final_suffix[SEMANAGE_FC_HOMEDIRS] =
311*2d543d20SAndroid Build Coastguard Worker 		strdup(selinux_file_context_homedir_path() + offset);
312*2d543d20SAndroid Build Coastguard Worker 	if (semanage_final_suffix[SEMANAGE_FC_HOMEDIRS] == NULL) {
313*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Unable to allocate space for file context home directory path.");
314*2d543d20SAndroid Build Coastguard Worker 		status = -1;
315*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
316*2d543d20SAndroid Build Coastguard Worker 	}
317*2d543d20SAndroid Build Coastguard Worker 
318*2d543d20SAndroid Build Coastguard Worker 	if (asprintf(&semanage_final_suffix[SEMANAGE_FC_HOMEDIRS_BIN], "%s.bin",
319*2d543d20SAndroid Build Coastguard Worker 		     semanage_final_suffix[SEMANAGE_FC_HOMEDIRS]) < 0) {
320*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Unable to allocate space for file context home directory path.");
321*2d543d20SAndroid Build Coastguard Worker 		status = -1;
322*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
323*2d543d20SAndroid Build Coastguard Worker 	}
324*2d543d20SAndroid Build Coastguard Worker 
325*2d543d20SAndroid Build Coastguard Worker 	semanage_final_suffix[SEMANAGE_FC_LOCAL] =
326*2d543d20SAndroid Build Coastguard Worker 		strdup(selinux_file_context_local_path() + offset);
327*2d543d20SAndroid Build Coastguard Worker 	if (semanage_final_suffix[SEMANAGE_FC_LOCAL] == NULL) {
328*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Unable to allocate space for local file context path.");
329*2d543d20SAndroid Build Coastguard Worker 		status = -1;
330*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
331*2d543d20SAndroid Build Coastguard Worker 	}
332*2d543d20SAndroid Build Coastguard Worker 
333*2d543d20SAndroid Build Coastguard Worker 	if (asprintf(&semanage_final_suffix[SEMANAGE_FC_LOCAL_BIN], "%s.bin",
334*2d543d20SAndroid Build Coastguard Worker 		     semanage_final_suffix[SEMANAGE_FC_LOCAL]) < 0) {
335*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Unable to allocate space for local file context path.");
336*2d543d20SAndroid Build Coastguard Worker 		status = -1;
337*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
338*2d543d20SAndroid Build Coastguard Worker 	}
339*2d543d20SAndroid Build Coastguard Worker 
340*2d543d20SAndroid Build Coastguard Worker 	semanage_final_suffix[SEMANAGE_NC] =
341*2d543d20SAndroid Build Coastguard Worker 		strdup(selinux_netfilter_context_path() + offset);
342*2d543d20SAndroid Build Coastguard Worker 	if (semanage_final_suffix[SEMANAGE_NC] == NULL) {
343*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Unable to allocate space for netfilter context path.");
344*2d543d20SAndroid Build Coastguard Worker 		status = -1;
345*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
346*2d543d20SAndroid Build Coastguard Worker 	}
347*2d543d20SAndroid Build Coastguard Worker 
348*2d543d20SAndroid Build Coastguard Worker 	semanage_final_suffix[SEMANAGE_SEUSERS] =
349*2d543d20SAndroid Build Coastguard Worker 		strdup(selinux_usersconf_path() + offset);
350*2d543d20SAndroid Build Coastguard Worker 	if (semanage_final_suffix[SEMANAGE_SEUSERS] == NULL) {
351*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Unable to allocate space for userconf path.");
352*2d543d20SAndroid Build Coastguard Worker 		status = -1;
353*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
354*2d543d20SAndroid Build Coastguard Worker 	}
355*2d543d20SAndroid Build Coastguard Worker 
356*2d543d20SAndroid Build Coastguard Worker 	ret = snprintf(path,
357*2d543d20SAndroid Build Coastguard Worker 		       sizeof(path),
358*2d543d20SAndroid Build Coastguard Worker 		       "%s.%d",
359*2d543d20SAndroid Build Coastguard Worker 		       selinux_binary_policy_path() + offset,
360*2d543d20SAndroid Build Coastguard Worker 		       sh->conf->policyvers);
361*2d543d20SAndroid Build Coastguard Worker 	if (ret < 0 || ret >= (int)sizeof(path)) {
362*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Unable to compose policy binary path.");
363*2d543d20SAndroid Build Coastguard Worker 		status = -1;
364*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
365*2d543d20SAndroid Build Coastguard Worker 	}
366*2d543d20SAndroid Build Coastguard Worker 
367*2d543d20SAndroid Build Coastguard Worker 	semanage_final_suffix[SEMANAGE_KERNEL] = strdup(path);
368*2d543d20SAndroid Build Coastguard Worker 	if (semanage_final_suffix[SEMANAGE_KERNEL] == NULL) {
369*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Unable to allocate space for policy binary path.");
370*2d543d20SAndroid Build Coastguard Worker 		status = -1;
371*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
372*2d543d20SAndroid Build Coastguard Worker 	}
373*2d543d20SAndroid Build Coastguard Worker 
374*2d543d20SAndroid Build Coastguard Worker cleanup:
375*2d543d20SAndroid Build Coastguard Worker 	if (status != 0) {
376*2d543d20SAndroid Build Coastguard Worker 		int i;
377*2d543d20SAndroid Build Coastguard Worker 		for (i = 0; i < SEMANAGE_FINAL_PATH_NUM; i++) {
378*2d543d20SAndroid Build Coastguard Worker 			free(semanage_final_suffix[i]);
379*2d543d20SAndroid Build Coastguard Worker 			semanage_final_suffix[i] = NULL;
380*2d543d20SAndroid Build Coastguard Worker 		}
381*2d543d20SAndroid Build Coastguard Worker 	}
382*2d543d20SAndroid Build Coastguard Worker 
383*2d543d20SAndroid Build Coastguard Worker 	return status;
384*2d543d20SAndroid Build Coastguard Worker }
385*2d543d20SAndroid Build Coastguard Worker 
386*2d543d20SAndroid Build Coastguard Worker /* Initialize final paths. */
semanage_init_final_paths(semanage_handle_t * sh)387*2d543d20SAndroid Build Coastguard Worker static int semanage_init_final_paths(semanage_handle_t *sh)
388*2d543d20SAndroid Build Coastguard Worker {
389*2d543d20SAndroid Build Coastguard Worker 	int status = 0;
390*2d543d20SAndroid Build Coastguard Worker 	int i, j;
391*2d543d20SAndroid Build Coastguard Worker 	size_t len;
392*2d543d20SAndroid Build Coastguard Worker 
393*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < SEMANAGE_FINAL_NUM; i++) {
394*2d543d20SAndroid Build Coastguard Worker 		for (j = 0; j < SEMANAGE_FINAL_PATH_NUM; j++) {
395*2d543d20SAndroid Build Coastguard Worker 			len = 	  strlen(semanage_final[i])
396*2d543d20SAndroid Build Coastguard Worker 				+ strlen(semanage_final_suffix[j]);
397*2d543d20SAndroid Build Coastguard Worker 
398*2d543d20SAndroid Build Coastguard Worker 			semanage_final_paths[i][j] = malloc(len + 1);
399*2d543d20SAndroid Build Coastguard Worker 			if (semanage_final_paths[i][j] == NULL) {
400*2d543d20SAndroid Build Coastguard Worker 				ERR(sh, "Unable to allocate space for policy final path.");
401*2d543d20SAndroid Build Coastguard Worker 				status = -1;
402*2d543d20SAndroid Build Coastguard Worker 				goto cleanup;
403*2d543d20SAndroid Build Coastguard Worker 			}
404*2d543d20SAndroid Build Coastguard Worker 
405*2d543d20SAndroid Build Coastguard Worker 			sprintf(semanage_final_paths[i][j],
406*2d543d20SAndroid Build Coastguard Worker 				"%s%s",
407*2d543d20SAndroid Build Coastguard Worker 				semanage_final[i],
408*2d543d20SAndroid Build Coastguard Worker 				semanage_final_suffix[j]);
409*2d543d20SAndroid Build Coastguard Worker 		}
410*2d543d20SAndroid Build Coastguard Worker 	}
411*2d543d20SAndroid Build Coastguard Worker 
412*2d543d20SAndroid Build Coastguard Worker cleanup:
413*2d543d20SAndroid Build Coastguard Worker 	if (status != 0) {
414*2d543d20SAndroid Build Coastguard Worker 		for (i = 0; i < SEMANAGE_FINAL_NUM; i++) {
415*2d543d20SAndroid Build Coastguard Worker 			for (j = 0; j < SEMANAGE_FINAL_PATH_NUM; j++) {
416*2d543d20SAndroid Build Coastguard Worker 				free(semanage_final_paths[i][j]);
417*2d543d20SAndroid Build Coastguard Worker 				semanage_final_paths[i][j] = NULL;
418*2d543d20SAndroid Build Coastguard Worker 			}
419*2d543d20SAndroid Build Coastguard Worker 		}
420*2d543d20SAndroid Build Coastguard Worker 	}
421*2d543d20SAndroid Build Coastguard Worker 
422*2d543d20SAndroid Build Coastguard Worker 	return status;
423*2d543d20SAndroid Build Coastguard Worker }
424*2d543d20SAndroid Build Coastguard Worker 
425*2d543d20SAndroid Build Coastguard Worker /* THIS MUST BE THE FIRST FUNCTION CALLED IN THIS LIBRARY.  If the
426*2d543d20SAndroid Build Coastguard Worker  * library has nnot been initialized yet then call the functions that
427*2d543d20SAndroid Build Coastguard Worker  * initialize the path variables.  This function does nothing if it
428*2d543d20SAndroid Build Coastguard Worker  * was previously called and that call was successful.  Return 0 on
429*2d543d20SAndroid Build Coastguard Worker  * success, -1 on error.
430*2d543d20SAndroid Build Coastguard Worker  *
431*2d543d20SAndroid Build Coastguard Worker  * Note that this function is NOT thread-safe.
432*2d543d20SAndroid Build Coastguard Worker  */
semanage_check_init(semanage_handle_t * sh,const char * prefix)433*2d543d20SAndroid Build Coastguard Worker int semanage_check_init(semanage_handle_t *sh, const char *prefix)
434*2d543d20SAndroid Build Coastguard Worker {
435*2d543d20SAndroid Build Coastguard Worker 	int rc;
436*2d543d20SAndroid Build Coastguard Worker 	if (semanage_paths_initialized == 0) {
437*2d543d20SAndroid Build Coastguard Worker 		char root[PATH_MAX];
438*2d543d20SAndroid Build Coastguard Worker 
439*2d543d20SAndroid Build Coastguard Worker 		rc = snprintf(root,
440*2d543d20SAndroid Build Coastguard Worker 			      sizeof(root),
441*2d543d20SAndroid Build Coastguard Worker 			      "%s%s/%s",
442*2d543d20SAndroid Build Coastguard Worker 			      semanage_root(),
443*2d543d20SAndroid Build Coastguard Worker 			      prefix,
444*2d543d20SAndroid Build Coastguard Worker 			      sh->conf->store_path);
445*2d543d20SAndroid Build Coastguard Worker 		if (rc < 0 || rc >= (int)sizeof(root))
446*2d543d20SAndroid Build Coastguard Worker 			return -1;
447*2d543d20SAndroid Build Coastguard Worker 
448*2d543d20SAndroid Build Coastguard Worker 		rc = semanage_init_paths(root);
449*2d543d20SAndroid Build Coastguard Worker 		if (rc)
450*2d543d20SAndroid Build Coastguard Worker 			return rc;
451*2d543d20SAndroid Build Coastguard Worker 
452*2d543d20SAndroid Build Coastguard Worker 		rc = semanage_init_store_paths(root);
453*2d543d20SAndroid Build Coastguard Worker 		if (rc)
454*2d543d20SAndroid Build Coastguard Worker 			return rc;
455*2d543d20SAndroid Build Coastguard Worker 
456*2d543d20SAndroid Build Coastguard Worker 		rc = semanage_init_final(sh, prefix);
457*2d543d20SAndroid Build Coastguard Worker 		if (rc)
458*2d543d20SAndroid Build Coastguard Worker 			return rc;
459*2d543d20SAndroid Build Coastguard Worker 
460*2d543d20SAndroid Build Coastguard Worker 		rc = semanage_init_final_suffix(sh);
461*2d543d20SAndroid Build Coastguard Worker 		if (rc)
462*2d543d20SAndroid Build Coastguard Worker 			return rc;
463*2d543d20SAndroid Build Coastguard Worker 
464*2d543d20SAndroid Build Coastguard Worker 		rc = semanage_init_final_paths(sh);
465*2d543d20SAndroid Build Coastguard Worker 		if (rc)
466*2d543d20SAndroid Build Coastguard Worker 			return rc;
467*2d543d20SAndroid Build Coastguard Worker 
468*2d543d20SAndroid Build Coastguard Worker 		semanage_paths_initialized = 1;
469*2d543d20SAndroid Build Coastguard Worker 	}
470*2d543d20SAndroid Build Coastguard Worker 	return 0;
471*2d543d20SAndroid Build Coastguard Worker }
472*2d543d20SAndroid Build Coastguard Worker 
473*2d543d20SAndroid Build Coastguard Worker /* Given a definition number, return a file name from the paths array */
semanage_fname(enum semanage_sandbox_defs file_enum)474*2d543d20SAndroid Build Coastguard Worker const char *semanage_fname(enum semanage_sandbox_defs file_enum)
475*2d543d20SAndroid Build Coastguard Worker {
476*2d543d20SAndroid Build Coastguard Worker 	return semanage_sandbox_paths[file_enum];
477*2d543d20SAndroid Build Coastguard Worker }
478*2d543d20SAndroid Build Coastguard Worker 
479*2d543d20SAndroid Build Coastguard Worker /* Given a store location (active/previous/tmp) and a definition
480*2d543d20SAndroid Build Coastguard Worker  * number, return a fully-qualified path to that file or directory.
481*2d543d20SAndroid Build Coastguard Worker  * The caller must not alter the string returned (and hence why this
482*2d543d20SAndroid Build Coastguard Worker  * function return type is const).
483*2d543d20SAndroid Build Coastguard Worker  *
484*2d543d20SAndroid Build Coastguard Worker  * This function shall never return a NULL, assuming that
485*2d543d20SAndroid Build Coastguard Worker  * semanage_check_init() was previously called.
486*2d543d20SAndroid Build Coastguard Worker  */
semanage_path(enum semanage_store_defs store,enum semanage_sandbox_defs path_name)487*2d543d20SAndroid Build Coastguard Worker const char *semanage_path(enum semanage_store_defs store,
488*2d543d20SAndroid Build Coastguard Worker 			  enum semanage_sandbox_defs path_name)
489*2d543d20SAndroid Build Coastguard Worker {
490*2d543d20SAndroid Build Coastguard Worker 	assert(semanage_paths[store][path_name]);
491*2d543d20SAndroid Build Coastguard Worker 	return semanage_paths[store][path_name];
492*2d543d20SAndroid Build Coastguard Worker }
493*2d543d20SAndroid Build Coastguard Worker 
494*2d543d20SAndroid Build Coastguard Worker /* Given a store location (tmp or selinux) and a definition
495*2d543d20SAndroid Build Coastguard Worker  * number, return a fully-qualified path to that file or directory.
496*2d543d20SAndroid Build Coastguard Worker  * The caller must not alter the string returned (and hence why this
497*2d543d20SAndroid Build Coastguard Worker  * function return type is const).
498*2d543d20SAndroid Build Coastguard Worker  *
499*2d543d20SAndroid Build Coastguard Worker  * This function shall never return a NULL, assuming that
500*2d543d20SAndroid Build Coastguard Worker  * semanage_check_init() was previously called.
501*2d543d20SAndroid Build Coastguard Worker  */
semanage_final_path(enum semanage_final_defs store,enum semanage_final_path_defs path_name)502*2d543d20SAndroid Build Coastguard Worker const char *semanage_final_path(enum semanage_final_defs store,
503*2d543d20SAndroid Build Coastguard Worker 				enum semanage_final_path_defs path_name)
504*2d543d20SAndroid Build Coastguard Worker {
505*2d543d20SAndroid Build Coastguard Worker 	assert(semanage_final_paths[store][path_name]);
506*2d543d20SAndroid Build Coastguard Worker 	return semanage_final_paths[store][path_name];
507*2d543d20SAndroid Build Coastguard Worker }
508*2d543d20SAndroid Build Coastguard Worker 
509*2d543d20SAndroid Build Coastguard Worker /* Return a fully-qualified path + filename to the semanage
510*2d543d20SAndroid Build Coastguard Worker  * configuration file. If semanage.conf file in the semanage
511*2d543d20SAndroid Build Coastguard Worker  * root is cannot be read, use the default semanage.conf as a
512*2d543d20SAndroid Build Coastguard Worker  * fallback.
513*2d543d20SAndroid Build Coastguard Worker  *
514*2d543d20SAndroid Build Coastguard Worker  * The caller is responsible for freeing the returned string.
515*2d543d20SAndroid Build Coastguard Worker  */
semanage_conf_path(void)516*2d543d20SAndroid Build Coastguard Worker char *semanage_conf_path(void)
517*2d543d20SAndroid Build Coastguard Worker {
518*2d543d20SAndroid Build Coastguard Worker 	char *semanage_conf = NULL;
519*2d543d20SAndroid Build Coastguard Worker 	int len;
520*2d543d20SAndroid Build Coastguard Worker 	struct stat sb;
521*2d543d20SAndroid Build Coastguard Worker 
522*2d543d20SAndroid Build Coastguard Worker 	len = strlen(semanage_root()) + strlen(selinux_path()) + strlen(SEMANAGE_CONF_FILE);
523*2d543d20SAndroid Build Coastguard Worker 	semanage_conf = calloc(len + 1, sizeof(char));
524*2d543d20SAndroid Build Coastguard Worker 	if (!semanage_conf)
525*2d543d20SAndroid Build Coastguard Worker 		return NULL;
526*2d543d20SAndroid Build Coastguard Worker 	snprintf(semanage_conf, len + 1, "%s%s%s", semanage_root(), selinux_path(),
527*2d543d20SAndroid Build Coastguard Worker 		 SEMANAGE_CONF_FILE);
528*2d543d20SAndroid Build Coastguard Worker 
529*2d543d20SAndroid Build Coastguard Worker 	if (stat(semanage_conf, &sb) != 0 && errno == ENOENT) {
530*2d543d20SAndroid Build Coastguard Worker 		snprintf(semanage_conf, len + 1, "%s%s", selinux_path(), SEMANAGE_CONF_FILE);
531*2d543d20SAndroid Build Coastguard Worker 	}
532*2d543d20SAndroid Build Coastguard Worker 
533*2d543d20SAndroid Build Coastguard Worker 	return semanage_conf;
534*2d543d20SAndroid Build Coastguard Worker }
535*2d543d20SAndroid Build Coastguard Worker 
536*2d543d20SAndroid Build Coastguard Worker /**************** functions that create module store ***************/
537*2d543d20SAndroid Build Coastguard Worker 
538*2d543d20SAndroid Build Coastguard Worker /* Check that the semanage store exists.  If 'create' is non-zero then
539*2d543d20SAndroid Build Coastguard Worker  * create the directories.  Returns 0 if module store exists (either
540*2d543d20SAndroid Build Coastguard Worker  * already or just created), -1 if does not exist or could not be
541*2d543d20SAndroid Build Coastguard Worker  * read, or -2 if it could not create the store. */
semanage_create_store(semanage_handle_t * sh,int create)542*2d543d20SAndroid Build Coastguard Worker int semanage_create_store(semanage_handle_t * sh, int create)
543*2d543d20SAndroid Build Coastguard Worker {
544*2d543d20SAndroid Build Coastguard Worker 	struct stat sb;
545*2d543d20SAndroid Build Coastguard Worker 	const char *path = semanage_files[SEMANAGE_ROOT];
546*2d543d20SAndroid Build Coastguard Worker 	int fd;
547*2d543d20SAndroid Build Coastguard Worker 	mode_t mask;
548*2d543d20SAndroid Build Coastguard Worker 
549*2d543d20SAndroid Build Coastguard Worker 	if (stat(path, &sb) == -1) {
550*2d543d20SAndroid Build Coastguard Worker 		if (errno == ENOENT && create) {
551*2d543d20SAndroid Build Coastguard Worker 			mask = umask(0077);
552*2d543d20SAndroid Build Coastguard Worker 			if (mkdir(path, S_IRWXU) == -1) {
553*2d543d20SAndroid Build Coastguard Worker 				umask(mask);
554*2d543d20SAndroid Build Coastguard Worker 				ERR(sh, "Could not create module store at %s.",
555*2d543d20SAndroid Build Coastguard Worker 				    path);
556*2d543d20SAndroid Build Coastguard Worker 				return -2;
557*2d543d20SAndroid Build Coastguard Worker 			}
558*2d543d20SAndroid Build Coastguard Worker 			umask(mask);
559*2d543d20SAndroid Build Coastguard Worker 		} else {
560*2d543d20SAndroid Build Coastguard Worker 			if (create)
561*2d543d20SAndroid Build Coastguard Worker 				ERR(sh,
562*2d543d20SAndroid Build Coastguard Worker 				    "Could not read from module store at %s.",
563*2d543d20SAndroid Build Coastguard Worker 				    path);
564*2d543d20SAndroid Build Coastguard Worker 			return -1;
565*2d543d20SAndroid Build Coastguard Worker 		}
566*2d543d20SAndroid Build Coastguard Worker 	} else {
567*2d543d20SAndroid Build Coastguard Worker 		if (!S_ISDIR(sb.st_mode)) {
568*2d543d20SAndroid Build Coastguard Worker 			ERR(sh,
569*2d543d20SAndroid Build Coastguard Worker 			    "Module store at %s is not a directory.",
570*2d543d20SAndroid Build Coastguard Worker 			    path);
571*2d543d20SAndroid Build Coastguard Worker 			return -1;
572*2d543d20SAndroid Build Coastguard Worker 		}
573*2d543d20SAndroid Build Coastguard Worker 	}
574*2d543d20SAndroid Build Coastguard Worker 	path = semanage_path(SEMANAGE_ACTIVE, SEMANAGE_TOPLEVEL);
575*2d543d20SAndroid Build Coastguard Worker 	if (stat(path, &sb) == -1) {
576*2d543d20SAndroid Build Coastguard Worker 		if (errno == ENOENT && create) {
577*2d543d20SAndroid Build Coastguard Worker 			mask = umask(0077);
578*2d543d20SAndroid Build Coastguard Worker 			if (mkdir(path, S_IRWXU) == -1) {
579*2d543d20SAndroid Build Coastguard Worker 				umask(mask);
580*2d543d20SAndroid Build Coastguard Worker 				ERR(sh,
581*2d543d20SAndroid Build Coastguard Worker 				    "Could not create module store, active subdirectory at %s.",
582*2d543d20SAndroid Build Coastguard Worker 				    path);
583*2d543d20SAndroid Build Coastguard Worker 				return -2;
584*2d543d20SAndroid Build Coastguard Worker 			}
585*2d543d20SAndroid Build Coastguard Worker 			umask(mask);
586*2d543d20SAndroid Build Coastguard Worker 		} else {
587*2d543d20SAndroid Build Coastguard Worker 			ERR(sh,
588*2d543d20SAndroid Build Coastguard Worker 			    "Could not read from module store, active subdirectory at %s.",
589*2d543d20SAndroid Build Coastguard Worker 			    path);
590*2d543d20SAndroid Build Coastguard Worker 			return -1;
591*2d543d20SAndroid Build Coastguard Worker 		}
592*2d543d20SAndroid Build Coastguard Worker 	} else {
593*2d543d20SAndroid Build Coastguard Worker 		if (!S_ISDIR(sb.st_mode)) {
594*2d543d20SAndroid Build Coastguard Worker 			ERR(sh,
595*2d543d20SAndroid Build Coastguard Worker 			    "Module store active subdirectory at %s is not a directory.",
596*2d543d20SAndroid Build Coastguard Worker 			    path);
597*2d543d20SAndroid Build Coastguard Worker 			return -1;
598*2d543d20SAndroid Build Coastguard Worker 		}
599*2d543d20SAndroid Build Coastguard Worker 	}
600*2d543d20SAndroid Build Coastguard Worker 	path = semanage_path(SEMANAGE_ACTIVE, SEMANAGE_MODULES);
601*2d543d20SAndroid Build Coastguard Worker 	if (stat(path, &sb) == -1) {
602*2d543d20SAndroid Build Coastguard Worker 		if (errno == ENOENT && create) {
603*2d543d20SAndroid Build Coastguard Worker 			mask = umask(0077);
604*2d543d20SAndroid Build Coastguard Worker 			if (mkdir(path, S_IRWXU) == -1) {
605*2d543d20SAndroid Build Coastguard Worker 				umask(mask);
606*2d543d20SAndroid Build Coastguard Worker 				ERR(sh,
607*2d543d20SAndroid Build Coastguard Worker 				    "Could not create module store, active modules subdirectory at %s.",
608*2d543d20SAndroid Build Coastguard Worker 				    path);
609*2d543d20SAndroid Build Coastguard Worker 				return -2;
610*2d543d20SAndroid Build Coastguard Worker 			}
611*2d543d20SAndroid Build Coastguard Worker 			umask(mask);
612*2d543d20SAndroid Build Coastguard Worker 		} else {
613*2d543d20SAndroid Build Coastguard Worker 			ERR(sh,
614*2d543d20SAndroid Build Coastguard Worker 			    "Could not read from module store, active modules subdirectory at %s.",
615*2d543d20SAndroid Build Coastguard Worker 			    path);
616*2d543d20SAndroid Build Coastguard Worker 			return -1;
617*2d543d20SAndroid Build Coastguard Worker 		}
618*2d543d20SAndroid Build Coastguard Worker 	} else {
619*2d543d20SAndroid Build Coastguard Worker 		if (!S_ISDIR(sb.st_mode)) {
620*2d543d20SAndroid Build Coastguard Worker 			ERR(sh,
621*2d543d20SAndroid Build Coastguard Worker 			    "Module store active modules subdirectory at %s is not a directory.",
622*2d543d20SAndroid Build Coastguard Worker 			    path);
623*2d543d20SAndroid Build Coastguard Worker 			return -1;
624*2d543d20SAndroid Build Coastguard Worker 		}
625*2d543d20SAndroid Build Coastguard Worker 	}
626*2d543d20SAndroid Build Coastguard Worker 	path = semanage_files[SEMANAGE_READ_LOCK];
627*2d543d20SAndroid Build Coastguard Worker 	if (stat(path, &sb) == -1) {
628*2d543d20SAndroid Build Coastguard Worker 		if (errno == ENOENT && create) {
629*2d543d20SAndroid Build Coastguard Worker 			mask = umask(0077);
630*2d543d20SAndroid Build Coastguard Worker 			if ((fd = creat(path, S_IRUSR | S_IWUSR)) == -1) {
631*2d543d20SAndroid Build Coastguard Worker 				umask(mask);
632*2d543d20SAndroid Build Coastguard Worker 				ERR(sh, "Could not create lock file at %s.",
633*2d543d20SAndroid Build Coastguard Worker 				    path);
634*2d543d20SAndroid Build Coastguard Worker 				return -2;
635*2d543d20SAndroid Build Coastguard Worker 			}
636*2d543d20SAndroid Build Coastguard Worker 			umask(mask);
637*2d543d20SAndroid Build Coastguard Worker 			close(fd);
638*2d543d20SAndroid Build Coastguard Worker 		} else {
639*2d543d20SAndroid Build Coastguard Worker 			ERR(sh, "Could not read lock file at %s.", path);
640*2d543d20SAndroid Build Coastguard Worker 			return -1;
641*2d543d20SAndroid Build Coastguard Worker 		}
642*2d543d20SAndroid Build Coastguard Worker 	} else {
643*2d543d20SAndroid Build Coastguard Worker 		if (!S_ISREG(sb.st_mode)) {
644*2d543d20SAndroid Build Coastguard Worker 			ERR(sh, "Object at %s is not a lock file.", path);
645*2d543d20SAndroid Build Coastguard Worker 			return -1;
646*2d543d20SAndroid Build Coastguard Worker 		}
647*2d543d20SAndroid Build Coastguard Worker 	}
648*2d543d20SAndroid Build Coastguard Worker 	return 0;
649*2d543d20SAndroid Build Coastguard Worker }
650*2d543d20SAndroid Build Coastguard Worker 
651*2d543d20SAndroid Build Coastguard Worker /* returns <0 if the active store cannot be read or doesn't exist
652*2d543d20SAndroid Build Coastguard Worker  * 0 if the store exists but the lock file cannot be accessed
653*2d543d20SAndroid Build Coastguard Worker  * SEMANAGE_CAN_READ if the store can be read and the lock file used
654*2d543d20SAndroid Build Coastguard Worker  * SEMANAGE_CAN_WRITE if the modules directory and binary policy dir can be written to
655*2d543d20SAndroid Build Coastguard Worker  */
semanage_store_access_check(void)656*2d543d20SAndroid Build Coastguard Worker int semanage_store_access_check(void)
657*2d543d20SAndroid Build Coastguard Worker {
658*2d543d20SAndroid Build Coastguard Worker 	const char *path;
659*2d543d20SAndroid Build Coastguard Worker 	int rc = -1;
660*2d543d20SAndroid Build Coastguard Worker 
661*2d543d20SAndroid Build Coastguard Worker 	/* read access on active store */
662*2d543d20SAndroid Build Coastguard Worker 	path = semanage_path(SEMANAGE_ACTIVE, SEMANAGE_TOPLEVEL);
663*2d543d20SAndroid Build Coastguard Worker 	if (access(path, R_OK | X_OK) != 0)
664*2d543d20SAndroid Build Coastguard Worker 		goto out;
665*2d543d20SAndroid Build Coastguard Worker 
666*2d543d20SAndroid Build Coastguard Worker 	/* we can read the active store meaning it is managed
667*2d543d20SAndroid Build Coastguard Worker 	 * so now we return 0 to indicate no error */
668*2d543d20SAndroid Build Coastguard Worker 	rc = 0;
669*2d543d20SAndroid Build Coastguard Worker 
670*2d543d20SAndroid Build Coastguard Worker 	/* read access on lock file required for locking
671*2d543d20SAndroid Build Coastguard Worker 	 * write access necessary if the lock file does not exist
672*2d543d20SAndroid Build Coastguard Worker 	 */
673*2d543d20SAndroid Build Coastguard Worker 	path = semanage_files[SEMANAGE_READ_LOCK];
674*2d543d20SAndroid Build Coastguard Worker 	if (access(path, R_OK) != 0) {
675*2d543d20SAndroid Build Coastguard Worker 		if (access(path, F_OK) == 0) {
676*2d543d20SAndroid Build Coastguard Worker 			goto out;
677*2d543d20SAndroid Build Coastguard Worker 		}
678*2d543d20SAndroid Build Coastguard Worker 
679*2d543d20SAndroid Build Coastguard Worker 		path = semanage_files[SEMANAGE_ROOT];
680*2d543d20SAndroid Build Coastguard Worker 		if (access(path, R_OK | W_OK | X_OK) != 0) {
681*2d543d20SAndroid Build Coastguard Worker 			goto out;
682*2d543d20SAndroid Build Coastguard Worker 		}
683*2d543d20SAndroid Build Coastguard Worker 	}
684*2d543d20SAndroid Build Coastguard Worker 
685*2d543d20SAndroid Build Coastguard Worker 	/* everything needed for reading has been checked */
686*2d543d20SAndroid Build Coastguard Worker 	rc = SEMANAGE_CAN_READ;
687*2d543d20SAndroid Build Coastguard Worker 
688*2d543d20SAndroid Build Coastguard Worker 	/* check the modules directory */
689*2d543d20SAndroid Build Coastguard Worker 	path = semanage_path(SEMANAGE_ACTIVE, SEMANAGE_MODULES);
690*2d543d20SAndroid Build Coastguard Worker 	if (access(path, R_OK | W_OK | X_OK) != 0)
691*2d543d20SAndroid Build Coastguard Worker 		goto out;
692*2d543d20SAndroid Build Coastguard Worker 
693*2d543d20SAndroid Build Coastguard Worker 	rc = SEMANAGE_CAN_WRITE;
694*2d543d20SAndroid Build Coastguard Worker 
695*2d543d20SAndroid Build Coastguard Worker       out:
696*2d543d20SAndroid Build Coastguard Worker 	return rc;
697*2d543d20SAndroid Build Coastguard Worker }
698*2d543d20SAndroid Build Coastguard Worker 
699*2d543d20SAndroid Build Coastguard Worker /********************* other I/O functions *********************/
700*2d543d20SAndroid Build Coastguard Worker 
701*2d543d20SAndroid Build Coastguard Worker static int semanage_rename(semanage_handle_t * sh, const char *tmp, const char *dst);
702*2d543d20SAndroid Build Coastguard Worker int semanage_remove_directory(const char *path);
703*2d543d20SAndroid Build Coastguard Worker static int semanage_copy_dir_flags(const char *src, const char *dst, int flag);
704*2d543d20SAndroid Build Coastguard Worker 
705*2d543d20SAndroid Build Coastguard Worker /* Callback used by scandir() to select files. */
semanage_filename_select(const struct dirent * d)706*2d543d20SAndroid Build Coastguard Worker static int semanage_filename_select(const struct dirent *d)
707*2d543d20SAndroid Build Coastguard Worker {
708*2d543d20SAndroid Build Coastguard Worker 	if (d->d_name[0] == '.'
709*2d543d20SAndroid Build Coastguard Worker 	    && (d->d_name[1] == '\0'
710*2d543d20SAndroid Build Coastguard Worker 		|| (d->d_name[1] == '.' && d->d_name[2] == '\0')))
711*2d543d20SAndroid Build Coastguard Worker 		return 0;
712*2d543d20SAndroid Build Coastguard Worker 	return 1;
713*2d543d20SAndroid Build Coastguard Worker }
714*2d543d20SAndroid Build Coastguard Worker 
715*2d543d20SAndroid Build Coastguard Worker /* Copies a file from src to dst.  If dst already exists then
716*2d543d20SAndroid Build Coastguard Worker  * overwrite it.  Returns 0 on success, -1 on error. */
semanage_copy_file(const char * src,const char * dst,mode_t mode,bool syncrequired)717*2d543d20SAndroid Build Coastguard Worker int semanage_copy_file(const char *src, const char *dst, mode_t mode,
718*2d543d20SAndroid Build Coastguard Worker 		bool syncrequired)
719*2d543d20SAndroid Build Coastguard Worker {
720*2d543d20SAndroid Build Coastguard Worker 	int in, out, retval = 0, amount_read, n, errsv = errno;
721*2d543d20SAndroid Build Coastguard Worker 	char tmp[PATH_MAX];
722*2d543d20SAndroid Build Coastguard Worker 	char buf[4192];
723*2d543d20SAndroid Build Coastguard Worker 	mode_t mask;
724*2d543d20SAndroid Build Coastguard Worker 
725*2d543d20SAndroid Build Coastguard Worker 	n = snprintf(tmp, PATH_MAX, "%s.tmp", dst);
726*2d543d20SAndroid Build Coastguard Worker 	if (n < 0 || n >= PATH_MAX)
727*2d543d20SAndroid Build Coastguard Worker 		return -1;
728*2d543d20SAndroid Build Coastguard Worker 
729*2d543d20SAndroid Build Coastguard Worker 	if ((in = open(src, O_RDONLY)) == -1) {
730*2d543d20SAndroid Build Coastguard Worker 		return -1;
731*2d543d20SAndroid Build Coastguard Worker 	}
732*2d543d20SAndroid Build Coastguard Worker 
733*2d543d20SAndroid Build Coastguard Worker 	if (!mode)
734*2d543d20SAndroid Build Coastguard Worker 		mode = S_IRUSR | S_IWUSR;
735*2d543d20SAndroid Build Coastguard Worker 
736*2d543d20SAndroid Build Coastguard Worker 	mask = umask(0);
737*2d543d20SAndroid Build Coastguard Worker 	if ((out = open(tmp, O_WRONLY | O_CREAT | O_TRUNC, mode)) == -1) {
738*2d543d20SAndroid Build Coastguard Worker 		umask(mask);
739*2d543d20SAndroid Build Coastguard Worker 		errsv = errno;
740*2d543d20SAndroid Build Coastguard Worker 		close(in);
741*2d543d20SAndroid Build Coastguard Worker 		retval = -1;
742*2d543d20SAndroid Build Coastguard Worker 		goto out;
743*2d543d20SAndroid Build Coastguard Worker 	}
744*2d543d20SAndroid Build Coastguard Worker 	umask(mask);
745*2d543d20SAndroid Build Coastguard Worker 	while (retval == 0 && (amount_read = read(in, buf, sizeof(buf))) > 0) {
746*2d543d20SAndroid Build Coastguard Worker 		if (write(out, buf, amount_read) != amount_read) {
747*2d543d20SAndroid Build Coastguard Worker 			if (errno)
748*2d543d20SAndroid Build Coastguard Worker 				errsv = errno;
749*2d543d20SAndroid Build Coastguard Worker 			else
750*2d543d20SAndroid Build Coastguard Worker 				errsv = EIO;
751*2d543d20SAndroid Build Coastguard Worker 			retval = -1;
752*2d543d20SAndroid Build Coastguard Worker 		}
753*2d543d20SAndroid Build Coastguard Worker 	}
754*2d543d20SAndroid Build Coastguard Worker 	if (amount_read < 0) {
755*2d543d20SAndroid Build Coastguard Worker 		errsv = errno;
756*2d543d20SAndroid Build Coastguard Worker 		retval = -1;
757*2d543d20SAndroid Build Coastguard Worker 	}
758*2d543d20SAndroid Build Coastguard Worker 	close(in);
759*2d543d20SAndroid Build Coastguard Worker 	if (syncrequired && fsync(out) < 0) {
760*2d543d20SAndroid Build Coastguard Worker 		errsv = errno;
761*2d543d20SAndroid Build Coastguard Worker 		retval = -1;
762*2d543d20SAndroid Build Coastguard Worker 	}
763*2d543d20SAndroid Build Coastguard Worker 	if (close(out) < 0) {
764*2d543d20SAndroid Build Coastguard Worker 		errsv = errno;
765*2d543d20SAndroid Build Coastguard Worker 		retval = -1;
766*2d543d20SAndroid Build Coastguard Worker 	}
767*2d543d20SAndroid Build Coastguard Worker 
768*2d543d20SAndroid Build Coastguard Worker 	if (!retval && rename(tmp, dst) == -1)
769*2d543d20SAndroid Build Coastguard Worker 		return -1;
770*2d543d20SAndroid Build Coastguard Worker 
771*2d543d20SAndroid Build Coastguard Worker 	semanage_setfiles(dst);
772*2d543d20SAndroid Build Coastguard Worker out:
773*2d543d20SAndroid Build Coastguard Worker 	errno = errsv;
774*2d543d20SAndroid Build Coastguard Worker 	return retval;
775*2d543d20SAndroid Build Coastguard Worker }
776*2d543d20SAndroid Build Coastguard Worker 
semanage_rename(semanage_handle_t * sh,const char * src,const char * dst)777*2d543d20SAndroid Build Coastguard Worker static int semanage_rename(semanage_handle_t * sh, const char *src, const char *dst) {
778*2d543d20SAndroid Build Coastguard Worker 	int retval;
779*2d543d20SAndroid Build Coastguard Worker 
780*2d543d20SAndroid Build Coastguard Worker 	retval = rename(src, dst);
781*2d543d20SAndroid Build Coastguard Worker 	if (retval == 0 || errno != EXDEV)
782*2d543d20SAndroid Build Coastguard Worker 		return retval;
783*2d543d20SAndroid Build Coastguard Worker 
784*2d543d20SAndroid Build Coastguard Worker 	/* we can't use rename() due to filesystem limitation, lets try to copy files manually */
785*2d543d20SAndroid Build Coastguard Worker 	WARN(sh, "WARNING: rename(%s, %s) failed: %s, fall back to non-atomic semanage_copy_dir_flags()",
786*2d543d20SAndroid Build Coastguard Worker 		 src, dst, strerror(errno));
787*2d543d20SAndroid Build Coastguard Worker 	if (semanage_copy_dir_flags(src, dst, 1) == -1) {
788*2d543d20SAndroid Build Coastguard Worker 		return -1;
789*2d543d20SAndroid Build Coastguard Worker 	}
790*2d543d20SAndroid Build Coastguard Worker 	return semanage_remove_directory(src);
791*2d543d20SAndroid Build Coastguard Worker }
792*2d543d20SAndroid Build Coastguard Worker 
793*2d543d20SAndroid Build Coastguard Worker /* Copies all of the files from src to dst, recursing into
794*2d543d20SAndroid Build Coastguard Worker  * subdirectories.  Returns 0 on success, -1 on error. */
semanage_copy_dir(const char * src,const char * dst)795*2d543d20SAndroid Build Coastguard Worker static int semanage_copy_dir(const char *src, const char *dst)
796*2d543d20SAndroid Build Coastguard Worker {
797*2d543d20SAndroid Build Coastguard Worker 	return semanage_copy_dir_flags(src, dst, 1);
798*2d543d20SAndroid Build Coastguard Worker }
799*2d543d20SAndroid Build Coastguard Worker 
800*2d543d20SAndroid Build Coastguard Worker /* Copies all of the dirs from src to dst, recursing into
801*2d543d20SAndroid Build Coastguard Worker  * subdirectories. If flag == 1, then copy regular files as
802*2d543d20SAndroid Build Coastguard Worker  * well. Returns 0 on success, -1 on error. */
semanage_copy_dir_flags(const char * src,const char * dst,int flag)803*2d543d20SAndroid Build Coastguard Worker static int semanage_copy_dir_flags(const char *src, const char *dst, int flag)
804*2d543d20SAndroid Build Coastguard Worker {
805*2d543d20SAndroid Build Coastguard Worker 	int i, len = 0, retval = -1;
806*2d543d20SAndroid Build Coastguard Worker 	struct stat sb;
807*2d543d20SAndroid Build Coastguard Worker 	struct dirent **names = NULL;
808*2d543d20SAndroid Build Coastguard Worker 	char path[PATH_MAX], path2[PATH_MAX];
809*2d543d20SAndroid Build Coastguard Worker 	mode_t mask;
810*2d543d20SAndroid Build Coastguard Worker 
811*2d543d20SAndroid Build Coastguard Worker 	if ((len = scandir(src, &names, semanage_filename_select, NULL)) == -1) {
812*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, "Could not read the contents of %s: %s\n", src, strerror(errno));
813*2d543d20SAndroid Build Coastguard Worker 		return -1;
814*2d543d20SAndroid Build Coastguard Worker 	}
815*2d543d20SAndroid Build Coastguard Worker 
816*2d543d20SAndroid Build Coastguard Worker 	if (stat(dst, &sb) != 0) {
817*2d543d20SAndroid Build Coastguard Worker 		mask = umask(0077);
818*2d543d20SAndroid Build Coastguard Worker 		if (mkdir(dst, S_IRWXU) != 0) {
819*2d543d20SAndroid Build Coastguard Worker 			umask(mask);
820*2d543d20SAndroid Build Coastguard Worker 			fprintf(stderr, "Could not create %s: %s\n", dst, strerror(errno));
821*2d543d20SAndroid Build Coastguard Worker 			goto cleanup;
822*2d543d20SAndroid Build Coastguard Worker 		}
823*2d543d20SAndroid Build Coastguard Worker 		umask(mask);
824*2d543d20SAndroid Build Coastguard Worker 
825*2d543d20SAndroid Build Coastguard Worker 		semanage_setfiles(dst);
826*2d543d20SAndroid Build Coastguard Worker 	}
827*2d543d20SAndroid Build Coastguard Worker 
828*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < len; i++) {
829*2d543d20SAndroid Build Coastguard Worker 		snprintf(path, sizeof(path), "%s/%s", src, names[i]->d_name);
830*2d543d20SAndroid Build Coastguard Worker 		/* stat() to see if this entry is a file or not since
831*2d543d20SAndroid Build Coastguard Worker 		 * d_type isn't set properly on XFS */
832*2d543d20SAndroid Build Coastguard Worker 		if (stat(path, &sb)) {
833*2d543d20SAndroid Build Coastguard Worker 			goto cleanup;
834*2d543d20SAndroid Build Coastguard Worker 		}
835*2d543d20SAndroid Build Coastguard Worker 		snprintf(path2, sizeof(path2), "%s/%s", dst, names[i]->d_name);
836*2d543d20SAndroid Build Coastguard Worker 		if (S_ISDIR(sb.st_mode)) {
837*2d543d20SAndroid Build Coastguard Worker 			mask = umask(0077);
838*2d543d20SAndroid Build Coastguard Worker 			if (mkdir(path2, 0700) == -1 ||
839*2d543d20SAndroid Build Coastguard Worker 			    semanage_copy_dir_flags(path, path2, flag) == -1) {
840*2d543d20SAndroid Build Coastguard Worker 				umask(mask);
841*2d543d20SAndroid Build Coastguard Worker 				goto cleanup;
842*2d543d20SAndroid Build Coastguard Worker 			}
843*2d543d20SAndroid Build Coastguard Worker 			umask(mask);
844*2d543d20SAndroid Build Coastguard Worker 			semanage_setfiles(path2);
845*2d543d20SAndroid Build Coastguard Worker 		} else if (S_ISREG(sb.st_mode) && flag == 1) {
846*2d543d20SAndroid Build Coastguard Worker 			mask = umask(0077);
847*2d543d20SAndroid Build Coastguard Worker 			if (semanage_copy_file(path, path2, sb.st_mode,
848*2d543d20SAndroid Build Coastguard Worker 						false) < 0) {
849*2d543d20SAndroid Build Coastguard Worker 				umask(mask);
850*2d543d20SAndroid Build Coastguard Worker 				goto cleanup;
851*2d543d20SAndroid Build Coastguard Worker 			}
852*2d543d20SAndroid Build Coastguard Worker 			umask(mask);
853*2d543d20SAndroid Build Coastguard Worker 		}
854*2d543d20SAndroid Build Coastguard Worker 	}
855*2d543d20SAndroid Build Coastguard Worker 	retval = 0;
856*2d543d20SAndroid Build Coastguard Worker       cleanup:
857*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; names != NULL && i < len; i++) {
858*2d543d20SAndroid Build Coastguard Worker 		free(names[i]);
859*2d543d20SAndroid Build Coastguard Worker 	}
860*2d543d20SAndroid Build Coastguard Worker 	free(names);
861*2d543d20SAndroid Build Coastguard Worker 	return retval;
862*2d543d20SAndroid Build Coastguard Worker }
863*2d543d20SAndroid Build Coastguard Worker 
864*2d543d20SAndroid Build Coastguard Worker /* Recursively removes the contents of a directory along with the
865*2d543d20SAndroid Build Coastguard Worker  * directory itself.  Returns 0 on success, non-zero on error. */
semanage_remove_directory(const char * path)866*2d543d20SAndroid Build Coastguard Worker int semanage_remove_directory(const char *path)
867*2d543d20SAndroid Build Coastguard Worker {
868*2d543d20SAndroid Build Coastguard Worker 	struct dirent **namelist = NULL;
869*2d543d20SAndroid Build Coastguard Worker 	int num_entries, i;
870*2d543d20SAndroid Build Coastguard Worker 	if ((num_entries = scandir(path, &namelist, semanage_filename_select,
871*2d543d20SAndroid Build Coastguard Worker 				   NULL)) == -1) {
872*2d543d20SAndroid Build Coastguard Worker 		return -1;
873*2d543d20SAndroid Build Coastguard Worker 	}
874*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < num_entries; i++) {
875*2d543d20SAndroid Build Coastguard Worker 		char s[PATH_MAX];
876*2d543d20SAndroid Build Coastguard Worker 		struct stat buf;
877*2d543d20SAndroid Build Coastguard Worker 		snprintf(s, sizeof(s), "%s/%s", path, namelist[i]->d_name);
878*2d543d20SAndroid Build Coastguard Worker 		if (stat(s, &buf) == -1) {
879*2d543d20SAndroid Build Coastguard Worker 			return -2;
880*2d543d20SAndroid Build Coastguard Worker 		}
881*2d543d20SAndroid Build Coastguard Worker 		if (S_ISDIR(buf.st_mode)) {
882*2d543d20SAndroid Build Coastguard Worker 			int retval;
883*2d543d20SAndroid Build Coastguard Worker 			if ((retval = semanage_remove_directory(s)) != 0) {
884*2d543d20SAndroid Build Coastguard Worker 				return retval;
885*2d543d20SAndroid Build Coastguard Worker 			}
886*2d543d20SAndroid Build Coastguard Worker 		} else {
887*2d543d20SAndroid Build Coastguard Worker 			if (remove(s) == -1) {
888*2d543d20SAndroid Build Coastguard Worker 				return -3;
889*2d543d20SAndroid Build Coastguard Worker 			}
890*2d543d20SAndroid Build Coastguard Worker 		}
891*2d543d20SAndroid Build Coastguard Worker 		free(namelist[i]);
892*2d543d20SAndroid Build Coastguard Worker 	}
893*2d543d20SAndroid Build Coastguard Worker 	free(namelist);
894*2d543d20SAndroid Build Coastguard Worker 	if (rmdir(path) == -1) {
895*2d543d20SAndroid Build Coastguard Worker 		return -4;
896*2d543d20SAndroid Build Coastguard Worker 	}
897*2d543d20SAndroid Build Coastguard Worker 	return 0;
898*2d543d20SAndroid Build Coastguard Worker }
899*2d543d20SAndroid Build Coastguard Worker 
semanage_mkpath(semanage_handle_t * sh,const char * path)900*2d543d20SAndroid Build Coastguard Worker int semanage_mkpath(semanage_handle_t *sh, const char *path)
901*2d543d20SAndroid Build Coastguard Worker {
902*2d543d20SAndroid Build Coastguard Worker 	char fn[PATH_MAX];
903*2d543d20SAndroid Build Coastguard Worker 	char *c;
904*2d543d20SAndroid Build Coastguard Worker 	int rc = 0;
905*2d543d20SAndroid Build Coastguard Worker 
906*2d543d20SAndroid Build Coastguard Worker 	if (strlen(path) >= PATH_MAX) {
907*2d543d20SAndroid Build Coastguard Worker 		return -1;
908*2d543d20SAndroid Build Coastguard Worker 	}
909*2d543d20SAndroid Build Coastguard Worker 
910*2d543d20SAndroid Build Coastguard Worker 	for (c = strcpy(fn, path) + 1; *c != '\0'; c++) {
911*2d543d20SAndroid Build Coastguard Worker 		if (*c != '/') {
912*2d543d20SAndroid Build Coastguard Worker 			continue;
913*2d543d20SAndroid Build Coastguard Worker 		}
914*2d543d20SAndroid Build Coastguard Worker 
915*2d543d20SAndroid Build Coastguard Worker 		*c = '\0';
916*2d543d20SAndroid Build Coastguard Worker 		rc = semanage_mkdir(sh, fn);
917*2d543d20SAndroid Build Coastguard Worker 		if (rc < 0) {
918*2d543d20SAndroid Build Coastguard Worker 			goto cleanup;
919*2d543d20SAndroid Build Coastguard Worker 		}
920*2d543d20SAndroid Build Coastguard Worker 		*c = '/';
921*2d543d20SAndroid Build Coastguard Worker 	}
922*2d543d20SAndroid Build Coastguard Worker 	rc = semanage_mkdir(sh, fn);
923*2d543d20SAndroid Build Coastguard Worker 
924*2d543d20SAndroid Build Coastguard Worker cleanup:
925*2d543d20SAndroid Build Coastguard Worker 	return rc;
926*2d543d20SAndroid Build Coastguard Worker }
927*2d543d20SAndroid Build Coastguard Worker 
semanage_mkdir(semanage_handle_t * sh,const char * path)928*2d543d20SAndroid Build Coastguard Worker int semanage_mkdir(semanage_handle_t *sh, const char *path)
929*2d543d20SAndroid Build Coastguard Worker {
930*2d543d20SAndroid Build Coastguard Worker 	int status = 0;
931*2d543d20SAndroid Build Coastguard Worker 	struct stat sb;
932*2d543d20SAndroid Build Coastguard Worker 	mode_t mask;
933*2d543d20SAndroid Build Coastguard Worker 
934*2d543d20SAndroid Build Coastguard Worker 	/* check if directory already exists */
935*2d543d20SAndroid Build Coastguard Worker 	if (stat(path, &sb) != 0) {
936*2d543d20SAndroid Build Coastguard Worker 		/* make the modules directory */
937*2d543d20SAndroid Build Coastguard Worker 		mask = umask(0077);
938*2d543d20SAndroid Build Coastguard Worker 		if (mkdir(path, S_IRWXU) != 0) {
939*2d543d20SAndroid Build Coastguard Worker 			umask(mask);
940*2d543d20SAndroid Build Coastguard Worker 			ERR(sh, "Cannot make directory at %s", path);
941*2d543d20SAndroid Build Coastguard Worker 			status = -1;
942*2d543d20SAndroid Build Coastguard Worker 			goto cleanup;
943*2d543d20SAndroid Build Coastguard Worker 
944*2d543d20SAndroid Build Coastguard Worker 		}
945*2d543d20SAndroid Build Coastguard Worker 		umask(mask);
946*2d543d20SAndroid Build Coastguard Worker 		semanage_setfiles(path);
947*2d543d20SAndroid Build Coastguard Worker 	}
948*2d543d20SAndroid Build Coastguard Worker 	else {
949*2d543d20SAndroid Build Coastguard Worker 		/* check that it really is a directory */
950*2d543d20SAndroid Build Coastguard Worker 		if (!S_ISDIR(sb.st_mode)) {
951*2d543d20SAndroid Build Coastguard Worker 			ERR(sh, "Directory path taken by non-directory file at %s.", path);
952*2d543d20SAndroid Build Coastguard Worker 			status = -1;
953*2d543d20SAndroid Build Coastguard Worker 			goto cleanup;
954*2d543d20SAndroid Build Coastguard Worker 		}
955*2d543d20SAndroid Build Coastguard Worker 	}
956*2d543d20SAndroid Build Coastguard Worker 
957*2d543d20SAndroid Build Coastguard Worker cleanup:
958*2d543d20SAndroid Build Coastguard Worker 	return status;
959*2d543d20SAndroid Build Coastguard Worker }
960*2d543d20SAndroid Build Coastguard Worker 
961*2d543d20SAndroid Build Coastguard Worker /********************* sandbox management routines *********************/
962*2d543d20SAndroid Build Coastguard Worker 
963*2d543d20SAndroid Build Coastguard Worker /* Creates a sandbox for a single client. Returns 0 if a
964*2d543d20SAndroid Build Coastguard Worker  * sandbox was created, -1 on error.
965*2d543d20SAndroid Build Coastguard Worker  */
semanage_make_sandbox(semanage_handle_t * sh)966*2d543d20SAndroid Build Coastguard Worker int semanage_make_sandbox(semanage_handle_t * sh)
967*2d543d20SAndroid Build Coastguard Worker {
968*2d543d20SAndroid Build Coastguard Worker 	const char *sandbox = semanage_path(SEMANAGE_TMP, SEMANAGE_TOPLEVEL);
969*2d543d20SAndroid Build Coastguard Worker 	struct stat buf;
970*2d543d20SAndroid Build Coastguard Worker 	int errsv;
971*2d543d20SAndroid Build Coastguard Worker 	mode_t mask;
972*2d543d20SAndroid Build Coastguard Worker 
973*2d543d20SAndroid Build Coastguard Worker 	if (stat(sandbox, &buf) == -1) {
974*2d543d20SAndroid Build Coastguard Worker 		if (errno != ENOENT) {
975*2d543d20SAndroid Build Coastguard Worker 			ERR(sh, "Error scanning directory %s.", sandbox);
976*2d543d20SAndroid Build Coastguard Worker 			return -1;
977*2d543d20SAndroid Build Coastguard Worker 		}
978*2d543d20SAndroid Build Coastguard Worker 		errno = 0;
979*2d543d20SAndroid Build Coastguard Worker 	} else {
980*2d543d20SAndroid Build Coastguard Worker 		/* remove the old sandbox */
981*2d543d20SAndroid Build Coastguard Worker 		if (semanage_remove_directory(sandbox) != 0) {
982*2d543d20SAndroid Build Coastguard Worker 			ERR(sh, "Error removing old sandbox directory %s.",
983*2d543d20SAndroid Build Coastguard Worker 			    sandbox);
984*2d543d20SAndroid Build Coastguard Worker 			return -1;
985*2d543d20SAndroid Build Coastguard Worker 		}
986*2d543d20SAndroid Build Coastguard Worker 	}
987*2d543d20SAndroid Build Coastguard Worker 
988*2d543d20SAndroid Build Coastguard Worker 	mask = umask(0077);
989*2d543d20SAndroid Build Coastguard Worker 	if (mkdir(sandbox, S_IRWXU) == -1 ||
990*2d543d20SAndroid Build Coastguard Worker 	    semanage_copy_dir(semanage_path(SEMANAGE_ACTIVE, SEMANAGE_TOPLEVEL),
991*2d543d20SAndroid Build Coastguard Worker 			      sandbox) == -1) {
992*2d543d20SAndroid Build Coastguard Worker 		umask(mask);
993*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Could not copy files to sandbox %s.", sandbox);
994*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
995*2d543d20SAndroid Build Coastguard Worker 	}
996*2d543d20SAndroid Build Coastguard Worker 	umask(mask);
997*2d543d20SAndroid Build Coastguard Worker 	return 0;
998*2d543d20SAndroid Build Coastguard Worker 
999*2d543d20SAndroid Build Coastguard Worker       cleanup:
1000*2d543d20SAndroid Build Coastguard Worker 	errsv = errno;
1001*2d543d20SAndroid Build Coastguard Worker 	semanage_remove_directory(sandbox);
1002*2d543d20SAndroid Build Coastguard Worker 	errno = errsv;
1003*2d543d20SAndroid Build Coastguard Worker 	return -1;
1004*2d543d20SAndroid Build Coastguard Worker }
1005*2d543d20SAndroid Build Coastguard Worker 
1006*2d543d20SAndroid Build Coastguard Worker /* Create final temporary space. Returns -1 on error 0 on success. */
semanage_make_final(semanage_handle_t * sh)1007*2d543d20SAndroid Build Coastguard Worker int semanage_make_final(semanage_handle_t *sh)
1008*2d543d20SAndroid Build Coastguard Worker {
1009*2d543d20SAndroid Build Coastguard Worker 	int status = 0;
1010*2d543d20SAndroid Build Coastguard Worker 	int ret = 0;
1011*2d543d20SAndroid Build Coastguard Worker 	char fn[PATH_MAX];
1012*2d543d20SAndroid Build Coastguard Worker 
1013*2d543d20SAndroid Build Coastguard Worker 	/* Create tmp dir if it does not exist. */
1014*2d543d20SAndroid Build Coastguard Worker 	ret = snprintf(fn,
1015*2d543d20SAndroid Build Coastguard Worker 		       sizeof(fn),
1016*2d543d20SAndroid Build Coastguard Worker 		       "%s%s%s",
1017*2d543d20SAndroid Build Coastguard Worker 		       semanage_root(),
1018*2d543d20SAndroid Build Coastguard Worker 		       sh->conf->store_root_path,
1019*2d543d20SAndroid Build Coastguard Worker 		       semanage_final_prefix[SEMANAGE_FINAL_TMP]);
1020*2d543d20SAndroid Build Coastguard Worker 	if (ret < 0 || ret >= (int)sizeof(fn)) {
1021*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Unable to compose the final tmp path.");
1022*2d543d20SAndroid Build Coastguard Worker 		status = -1;
1023*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
1024*2d543d20SAndroid Build Coastguard Worker 	}
1025*2d543d20SAndroid Build Coastguard Worker 
1026*2d543d20SAndroid Build Coastguard Worker 	ret = semanage_mkdir(sh, fn);
1027*2d543d20SAndroid Build Coastguard Worker 	if (ret != 0) {
1028*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Unable to create temporary directory for final files at %s", fn);
1029*2d543d20SAndroid Build Coastguard Worker 		status = -1;
1030*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
1031*2d543d20SAndroid Build Coastguard Worker 	}
1032*2d543d20SAndroid Build Coastguard Worker 
1033*2d543d20SAndroid Build Coastguard Worker 	/* Delete store specific dir if it exists. */
1034*2d543d20SAndroid Build Coastguard Worker 	ret = semanage_remove_directory(
1035*2d543d20SAndroid Build Coastguard Worker 		semanage_final_path(SEMANAGE_FINAL_TMP,
1036*2d543d20SAndroid Build Coastguard Worker 				    SEMANAGE_FINAL_TOPLEVEL));
1037*2d543d20SAndroid Build Coastguard Worker 	if (ret < -1) {
1038*2d543d20SAndroid Build Coastguard Worker 		status = -1;
1039*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
1040*2d543d20SAndroid Build Coastguard Worker 	}
1041*2d543d20SAndroid Build Coastguard Worker 
1042*2d543d20SAndroid Build Coastguard Worker 	// Build final directory structure
1043*2d543d20SAndroid Build Coastguard Worker 	int i;
1044*2d543d20SAndroid Build Coastguard Worker 	for (i = 1; i < SEMANAGE_FINAL_PATH_NUM; i++) {
1045*2d543d20SAndroid Build Coastguard Worker 		if (strlen(semanage_final_path(SEMANAGE_FINAL_TMP, i)) >= sizeof(fn)) {
1046*2d543d20SAndroid Build Coastguard Worker 			ERR(sh, "Unable to compose the final paths.");
1047*2d543d20SAndroid Build Coastguard Worker 			status = -1;
1048*2d543d20SAndroid Build Coastguard Worker 			goto cleanup;
1049*2d543d20SAndroid Build Coastguard Worker 		}
1050*2d543d20SAndroid Build Coastguard Worker 		strcpy(fn, semanage_final_path(SEMANAGE_FINAL_TMP, i));
1051*2d543d20SAndroid Build Coastguard Worker 		ret = semanage_mkpath(sh, dirname(fn));
1052*2d543d20SAndroid Build Coastguard Worker 		if (ret < 0) {
1053*2d543d20SAndroid Build Coastguard Worker 			status = -1;
1054*2d543d20SAndroid Build Coastguard Worker 			goto cleanup;
1055*2d543d20SAndroid Build Coastguard Worker 		}
1056*2d543d20SAndroid Build Coastguard Worker 	}
1057*2d543d20SAndroid Build Coastguard Worker 
1058*2d543d20SAndroid Build Coastguard Worker cleanup:
1059*2d543d20SAndroid Build Coastguard Worker 	return status;
1060*2d543d20SAndroid Build Coastguard Worker }
1061*2d543d20SAndroid Build Coastguard Worker 
1062*2d543d20SAndroid Build Coastguard Worker /* qsort comparison function for semanage_get_active_modules. */
semanage_get_active_modules_cmp(const void * a,const void * b)1063*2d543d20SAndroid Build Coastguard Worker static int semanage_get_active_modules_cmp(const void *a, const void *b)
1064*2d543d20SAndroid Build Coastguard Worker {
1065*2d543d20SAndroid Build Coastguard Worker 	semanage_module_info_t *aa = (semanage_module_info_t *)a;
1066*2d543d20SAndroid Build Coastguard Worker 	semanage_module_info_t *bb = (semanage_module_info_t *)b;
1067*2d543d20SAndroid Build Coastguard Worker 
1068*2d543d20SAndroid Build Coastguard Worker 	return strcmp(aa->name, bb->name);
1069*2d543d20SAndroid Build Coastguard Worker }
1070*2d543d20SAndroid Build Coastguard Worker 
semanage_get_cil_paths(semanage_handle_t * sh,semanage_module_info_t * modinfos,int num_modinfos,char *** filenames)1071*2d543d20SAndroid Build Coastguard Worker int semanage_get_cil_paths(semanage_handle_t * sh,
1072*2d543d20SAndroid Build Coastguard Worker 				semanage_module_info_t *modinfos,
1073*2d543d20SAndroid Build Coastguard Worker 				int num_modinfos,
1074*2d543d20SAndroid Build Coastguard Worker 				char *** filenames)
1075*2d543d20SAndroid Build Coastguard Worker {
1076*2d543d20SAndroid Build Coastguard Worker 	char path[PATH_MAX];
1077*2d543d20SAndroid Build Coastguard Worker 	char **names = NULL;
1078*2d543d20SAndroid Build Coastguard Worker 
1079*2d543d20SAndroid Build Coastguard Worker 	int ret;
1080*2d543d20SAndroid Build Coastguard Worker 	int status = 0;
1081*2d543d20SAndroid Build Coastguard Worker 	int i = 0;
1082*2d543d20SAndroid Build Coastguard Worker 
1083*2d543d20SAndroid Build Coastguard Worker 	names = calloc(num_modinfos, sizeof(*names));
1084*2d543d20SAndroid Build Coastguard Worker 	if (names == NULL) {
1085*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Error allocating space for filenames.");
1086*2d543d20SAndroid Build Coastguard Worker 		return -1;
1087*2d543d20SAndroid Build Coastguard Worker 	}
1088*2d543d20SAndroid Build Coastguard Worker 
1089*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < num_modinfos; i++) {
1090*2d543d20SAndroid Build Coastguard Worker 		ret = semanage_module_get_path(
1091*2d543d20SAndroid Build Coastguard Worker 				sh,
1092*2d543d20SAndroid Build Coastguard Worker 				&modinfos[i],
1093*2d543d20SAndroid Build Coastguard Worker 				SEMANAGE_MODULE_PATH_CIL,
1094*2d543d20SAndroid Build Coastguard Worker 				path,
1095*2d543d20SAndroid Build Coastguard Worker 				sizeof(path));
1096*2d543d20SAndroid Build Coastguard Worker 		if (ret != 0) {
1097*2d543d20SAndroid Build Coastguard Worker 			status = -1;
1098*2d543d20SAndroid Build Coastguard Worker 			goto cleanup;
1099*2d543d20SAndroid Build Coastguard Worker 		}
1100*2d543d20SAndroid Build Coastguard Worker 
1101*2d543d20SAndroid Build Coastguard Worker 		names[i] = strdup(path);
1102*2d543d20SAndroid Build Coastguard Worker 
1103*2d543d20SAndroid Build Coastguard Worker 		if (names[i] == NULL) {
1104*2d543d20SAndroid Build Coastguard Worker 			status = -1;
1105*2d543d20SAndroid Build Coastguard Worker 			goto cleanup;
1106*2d543d20SAndroid Build Coastguard Worker 		}
1107*2d543d20SAndroid Build Coastguard Worker 	}
1108*2d543d20SAndroid Build Coastguard Worker 
1109*2d543d20SAndroid Build Coastguard Worker cleanup:
1110*2d543d20SAndroid Build Coastguard Worker 	if (status != 0) {
1111*2d543d20SAndroid Build Coastguard Worker 		for (i = 0; i < num_modinfos; i++) {
1112*2d543d20SAndroid Build Coastguard Worker 			free(names[i]);
1113*2d543d20SAndroid Build Coastguard Worker 		}
1114*2d543d20SAndroid Build Coastguard Worker 		free(names);
1115*2d543d20SAndroid Build Coastguard Worker 	} else {
1116*2d543d20SAndroid Build Coastguard Worker 		*filenames = names;
1117*2d543d20SAndroid Build Coastguard Worker 	}
1118*2d543d20SAndroid Build Coastguard Worker 
1119*2d543d20SAndroid Build Coastguard Worker 	return status;
1120*2d543d20SAndroid Build Coastguard Worker }
1121*2d543d20SAndroid Build Coastguard Worker 
1122*2d543d20SAndroid Build Coastguard Worker /* Scans the modules directory for the current semanage handler.  This
1123*2d543d20SAndroid Build Coastguard Worker  * might be the active directory or sandbox, depending upon if the
1124*2d543d20SAndroid Build Coastguard Worker  * handler has a transaction lock.  Allocates and fills in *modinfos
1125*2d543d20SAndroid Build Coastguard Worker  * with an array of module infos; length of array is stored in
1126*2d543d20SAndroid Build Coastguard Worker  * *num_modules. The caller is responsible for free()ing *modinfos and its
1127*2d543d20SAndroid Build Coastguard Worker  * individual elements.	 Upon success returns 0, -1 on error.
1128*2d543d20SAndroid Build Coastguard Worker  */
semanage_get_active_modules(semanage_handle_t * sh,semanage_module_info_t ** modinfo,int * num_modules)1129*2d543d20SAndroid Build Coastguard Worker int semanage_get_active_modules(semanage_handle_t * sh,
1130*2d543d20SAndroid Build Coastguard Worker 				semanage_module_info_t ** modinfo,
1131*2d543d20SAndroid Build Coastguard Worker 				int *num_modules)
1132*2d543d20SAndroid Build Coastguard Worker {
1133*2d543d20SAndroid Build Coastguard Worker 	assert(sh);
1134*2d543d20SAndroid Build Coastguard Worker 	assert(modinfo);
1135*2d543d20SAndroid Build Coastguard Worker 	assert(num_modules);
1136*2d543d20SAndroid Build Coastguard Worker 	*modinfo = NULL;
1137*2d543d20SAndroid Build Coastguard Worker 	*num_modules = 0;
1138*2d543d20SAndroid Build Coastguard Worker 
1139*2d543d20SAndroid Build Coastguard Worker 	int status = 0;
1140*2d543d20SAndroid Build Coastguard Worker 	int ret = 0;
1141*2d543d20SAndroid Build Coastguard Worker 
1142*2d543d20SAndroid Build Coastguard Worker 	int i = 0;
1143*2d543d20SAndroid Build Coastguard Worker 	int j = 0;
1144*2d543d20SAndroid Build Coastguard Worker 
1145*2d543d20SAndroid Build Coastguard Worker 	semanage_list_t *list = NULL;
1146*2d543d20SAndroid Build Coastguard Worker 	semanage_list_t *found = NULL;
1147*2d543d20SAndroid Build Coastguard Worker 
1148*2d543d20SAndroid Build Coastguard Worker 	semanage_module_info_t *all_modinfos = NULL;
1149*2d543d20SAndroid Build Coastguard Worker 	int all_modinfos_len = 0;
1150*2d543d20SAndroid Build Coastguard Worker 
1151*2d543d20SAndroid Build Coastguard Worker 	void *tmp = NULL;
1152*2d543d20SAndroid Build Coastguard Worker 
1153*2d543d20SAndroid Build Coastguard Worker 	/* get all modules */
1154*2d543d20SAndroid Build Coastguard Worker 	ret = semanage_module_list_all(sh, &all_modinfos, &all_modinfos_len);
1155*2d543d20SAndroid Build Coastguard Worker 	if (ret != 0) {
1156*2d543d20SAndroid Build Coastguard Worker 		status = -1;
1157*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
1158*2d543d20SAndroid Build Coastguard Worker 	}
1159*2d543d20SAndroid Build Coastguard Worker 
1160*2d543d20SAndroid Build Coastguard Worker 	if (all_modinfos_len == 0) {
1161*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
1162*2d543d20SAndroid Build Coastguard Worker 	}
1163*2d543d20SAndroid Build Coastguard Worker 
1164*2d543d20SAndroid Build Coastguard Worker 	/* allocate enough for worst case */
1165*2d543d20SAndroid Build Coastguard Worker 	(*modinfo) = calloc(all_modinfos_len, sizeof(**modinfo));
1166*2d543d20SAndroid Build Coastguard Worker 	if ((*modinfo) == NULL) {
1167*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Error allocating space for module information.");
1168*2d543d20SAndroid Build Coastguard Worker 		status = -1;
1169*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
1170*2d543d20SAndroid Build Coastguard Worker 	}
1171*2d543d20SAndroid Build Coastguard Worker 
1172*2d543d20SAndroid Build Coastguard Worker 	/* for each highest priority, enabled module get its path */
1173*2d543d20SAndroid Build Coastguard Worker 	semanage_list_destroy(&list);
1174*2d543d20SAndroid Build Coastguard Worker 	j = 0;
1175*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < all_modinfos_len; i++) {
1176*2d543d20SAndroid Build Coastguard Worker 		/* check if enabled */
1177*2d543d20SAndroid Build Coastguard Worker 		if (all_modinfos[i].enabled != 1) continue;
1178*2d543d20SAndroid Build Coastguard Worker 
1179*2d543d20SAndroid Build Coastguard Worker 		/* check if we've seen this before (i.e. highest priority) */
1180*2d543d20SAndroid Build Coastguard Worker 		found = semanage_list_find(list, all_modinfos[i].name);
1181*2d543d20SAndroid Build Coastguard Worker 		if (found == NULL) {
1182*2d543d20SAndroid Build Coastguard Worker 			ret = semanage_list_push(&list, all_modinfos[i].name);
1183*2d543d20SAndroid Build Coastguard Worker 			if (ret != 0) {
1184*2d543d20SAndroid Build Coastguard Worker 				ERR(sh, "Failed to add module name to list of known names.");
1185*2d543d20SAndroid Build Coastguard Worker 				status = -1;
1186*2d543d20SAndroid Build Coastguard Worker 				goto cleanup;
1187*2d543d20SAndroid Build Coastguard Worker 			}
1188*2d543d20SAndroid Build Coastguard Worker 		}
1189*2d543d20SAndroid Build Coastguard Worker 		else continue;
1190*2d543d20SAndroid Build Coastguard Worker 
1191*2d543d20SAndroid Build Coastguard Worker 		if (semanage_module_info_clone(sh, &all_modinfos[i], &(*modinfo)[j]) != 0) {
1192*2d543d20SAndroid Build Coastguard Worker 			status = -1;
1193*2d543d20SAndroid Build Coastguard Worker 			goto cleanup;
1194*2d543d20SAndroid Build Coastguard Worker 		}
1195*2d543d20SAndroid Build Coastguard Worker 
1196*2d543d20SAndroid Build Coastguard Worker 		j += 1;
1197*2d543d20SAndroid Build Coastguard Worker 	}
1198*2d543d20SAndroid Build Coastguard Worker 
1199*2d543d20SAndroid Build Coastguard Worker 	*num_modules = j;
1200*2d543d20SAndroid Build Coastguard Worker 
1201*2d543d20SAndroid Build Coastguard Worker 	if (j == 0) {
1202*2d543d20SAndroid Build Coastguard Worker 		free(*modinfo);
1203*2d543d20SAndroid Build Coastguard Worker 		*modinfo = NULL;
1204*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
1205*2d543d20SAndroid Build Coastguard Worker 	}
1206*2d543d20SAndroid Build Coastguard Worker 
1207*2d543d20SAndroid Build Coastguard Worker 	/* realloc the array to its min size */
1208*2d543d20SAndroid Build Coastguard Worker 	tmp = realloc(*modinfo, j * sizeof(**modinfo));
1209*2d543d20SAndroid Build Coastguard Worker 	if (tmp == NULL) {
1210*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Error allocating space for filenames.");
1211*2d543d20SAndroid Build Coastguard Worker 		status = -1;
1212*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
1213*2d543d20SAndroid Build Coastguard Worker 	}
1214*2d543d20SAndroid Build Coastguard Worker 	*modinfo = tmp;
1215*2d543d20SAndroid Build Coastguard Worker 
1216*2d543d20SAndroid Build Coastguard Worker 	/* sort array on module name */
1217*2d543d20SAndroid Build Coastguard Worker 	qsort(*modinfo,
1218*2d543d20SAndroid Build Coastguard Worker 	      *num_modules,
1219*2d543d20SAndroid Build Coastguard Worker 	      sizeof(**modinfo),
1220*2d543d20SAndroid Build Coastguard Worker 	      semanage_get_active_modules_cmp);
1221*2d543d20SAndroid Build Coastguard Worker 
1222*2d543d20SAndroid Build Coastguard Worker cleanup:
1223*2d543d20SAndroid Build Coastguard Worker 	semanage_list_destroy(&list);
1224*2d543d20SAndroid Build Coastguard Worker 
1225*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < all_modinfos_len; i++) {
1226*2d543d20SAndroid Build Coastguard Worker 		semanage_module_info_destroy(sh, &all_modinfos[i]);
1227*2d543d20SAndroid Build Coastguard Worker 	}
1228*2d543d20SAndroid Build Coastguard Worker 	free(all_modinfos);
1229*2d543d20SAndroid Build Coastguard Worker 
1230*2d543d20SAndroid Build Coastguard Worker 	if (status != 0) {
1231*2d543d20SAndroid Build Coastguard Worker 		for (i = 0; i < j; i++) {
1232*2d543d20SAndroid Build Coastguard Worker 			semanage_module_info_destroy(sh, &(*modinfo)[i]);
1233*2d543d20SAndroid Build Coastguard Worker 		}
1234*2d543d20SAndroid Build Coastguard Worker 		free(*modinfo);
1235*2d543d20SAndroid Build Coastguard Worker 	}
1236*2d543d20SAndroid Build Coastguard Worker 
1237*2d543d20SAndroid Build Coastguard Worker 	return status;
1238*2d543d20SAndroid Build Coastguard Worker }
1239*2d543d20SAndroid Build Coastguard Worker 
1240*2d543d20SAndroid Build Coastguard Worker /******************* routines that run external programs *******************/
1241*2d543d20SAndroid Build Coastguard Worker 
1242*2d543d20SAndroid Build Coastguard Worker /* Appends a single character to a string.  Returns a pointer to the
1243*2d543d20SAndroid Build Coastguard Worker  * realloc()ated string.  If out of memory return NULL; original
1244*2d543d20SAndroid Build Coastguard Worker  * string will remain untouched.
1245*2d543d20SAndroid Build Coastguard Worker  */
append(char * s,char c)1246*2d543d20SAndroid Build Coastguard Worker static char *append(char *s, char c)
1247*2d543d20SAndroid Build Coastguard Worker {
1248*2d543d20SAndroid Build Coastguard Worker 	size_t len = (s == NULL ? 0 : strlen(s));
1249*2d543d20SAndroid Build Coastguard Worker 	char *new_s = realloc(s, len + 2);
1250*2d543d20SAndroid Build Coastguard Worker 	if (new_s == NULL) {
1251*2d543d20SAndroid Build Coastguard Worker 		return NULL;
1252*2d543d20SAndroid Build Coastguard Worker 	}
1253*2d543d20SAndroid Build Coastguard Worker 	s = new_s;
1254*2d543d20SAndroid Build Coastguard Worker 	s[len] = c;
1255*2d543d20SAndroid Build Coastguard Worker 	s[len + 1] = '\0';
1256*2d543d20SAndroid Build Coastguard Worker 	return s;
1257*2d543d20SAndroid Build Coastguard Worker }
1258*2d543d20SAndroid Build Coastguard Worker 
1259*2d543d20SAndroid Build Coastguard Worker /* Append string 't' to string 's', realloc()ating 's' as needed.  't'
1260*2d543d20SAndroid Build Coastguard Worker  * may be safely free()d afterwards.  Returns a pointer to the
1261*2d543d20SAndroid Build Coastguard Worker  * realloc()ated 's'.  If out of memory return NULL; original strings
1262*2d543d20SAndroid Build Coastguard Worker  * will remain untouched.
1263*2d543d20SAndroid Build Coastguard Worker  */
append_str(char * s,const char * t)1264*2d543d20SAndroid Build Coastguard Worker static char *append_str(char *s, const char *t)
1265*2d543d20SAndroid Build Coastguard Worker {
1266*2d543d20SAndroid Build Coastguard Worker 	size_t s_len = (s == NULL ? 0 : strlen(s));
1267*2d543d20SAndroid Build Coastguard Worker 	size_t t_len;
1268*2d543d20SAndroid Build Coastguard Worker 	char *new_s;
1269*2d543d20SAndroid Build Coastguard Worker 
1270*2d543d20SAndroid Build Coastguard Worker 	if (t == NULL) {
1271*2d543d20SAndroid Build Coastguard Worker 		return s;
1272*2d543d20SAndroid Build Coastguard Worker 	}
1273*2d543d20SAndroid Build Coastguard Worker 	t_len = strlen(t);
1274*2d543d20SAndroid Build Coastguard Worker 	new_s = realloc(s, s_len + t_len + 1);
1275*2d543d20SAndroid Build Coastguard Worker 	if (new_s == NULL) {
1276*2d543d20SAndroid Build Coastguard Worker 		return NULL;
1277*2d543d20SAndroid Build Coastguard Worker 	}
1278*2d543d20SAndroid Build Coastguard Worker 	s = new_s;
1279*2d543d20SAndroid Build Coastguard Worker 	memcpy(s + s_len, t, t_len);
1280*2d543d20SAndroid Build Coastguard Worker 	s[s_len + t_len] = '\0';
1281*2d543d20SAndroid Build Coastguard Worker 	return s;
1282*2d543d20SAndroid Build Coastguard Worker }
1283*2d543d20SAndroid Build Coastguard Worker 
1284*2d543d20SAndroid Build Coastguard Worker /*
1285*2d543d20SAndroid Build Coastguard Worker  * Append an argument string to an argument vector.  Replaces the
1286*2d543d20SAndroid Build Coastguard Worker  * argument pointer passed in.  Returns -1 on error.  Increments
1287*2d543d20SAndroid Build Coastguard Worker  * 'num_args' on success.
1288*2d543d20SAndroid Build Coastguard Worker  */
append_arg(char *** argv,int * num_args,const char * arg)1289*2d543d20SAndroid Build Coastguard Worker static int append_arg(char ***argv, int *num_args, const char *arg)
1290*2d543d20SAndroid Build Coastguard Worker {
1291*2d543d20SAndroid Build Coastguard Worker 	char **a;
1292*2d543d20SAndroid Build Coastguard Worker 
1293*2d543d20SAndroid Build Coastguard Worker 	a = realloc(*argv, sizeof(**argv) * (*num_args + 1));
1294*2d543d20SAndroid Build Coastguard Worker 	if (a == NULL)
1295*2d543d20SAndroid Build Coastguard Worker 		return -1;
1296*2d543d20SAndroid Build Coastguard Worker 
1297*2d543d20SAndroid Build Coastguard Worker 	*argv = a;
1298*2d543d20SAndroid Build Coastguard Worker 	a[*num_args] = NULL;
1299*2d543d20SAndroid Build Coastguard Worker 
1300*2d543d20SAndroid Build Coastguard Worker 	if (arg) {
1301*2d543d20SAndroid Build Coastguard Worker 		a[*num_args] = strdup(arg);
1302*2d543d20SAndroid Build Coastguard Worker 		if (!a[*num_args])
1303*2d543d20SAndroid Build Coastguard Worker 			return -1;
1304*2d543d20SAndroid Build Coastguard Worker 	}
1305*2d543d20SAndroid Build Coastguard Worker 	(*num_args)++;
1306*2d543d20SAndroid Build Coastguard Worker 	return 0;
1307*2d543d20SAndroid Build Coastguard Worker }
1308*2d543d20SAndroid Build Coastguard Worker 
1309*2d543d20SAndroid Build Coastguard Worker /* free()s all strings within a null-terminated argument vector, as
1310*2d543d20SAndroid Build Coastguard Worker  * well as the pointer itself. */
free_argv(char ** argv)1311*2d543d20SAndroid Build Coastguard Worker static void free_argv(char **argv)
1312*2d543d20SAndroid Build Coastguard Worker {
1313*2d543d20SAndroid Build Coastguard Worker 	int i;
1314*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; argv != NULL && argv[i] != NULL; i++) {
1315*2d543d20SAndroid Build Coastguard Worker 		free(argv[i]);
1316*2d543d20SAndroid Build Coastguard Worker 	}
1317*2d543d20SAndroid Build Coastguard Worker 	free(argv);
1318*2d543d20SAndroid Build Coastguard Worker }
1319*2d543d20SAndroid Build Coastguard Worker 
1320*2d543d20SAndroid Build Coastguard Worker /* Take an argument string and split and place into an argument
1321*2d543d20SAndroid Build Coastguard Worker  * vector.  Respect normal quoting, double-quoting, and backslash
1322*2d543d20SAndroid Build Coastguard Worker  * conventions.	 Perform substitutions on $@ and $< symbols.  Returns
1323*2d543d20SAndroid Build Coastguard Worker  * a NULL-terminated argument vector; caller is responsible for
1324*2d543d20SAndroid Build Coastguard Worker  * free()ing the vector and its elements. */
split_args(const char * arg0,char * arg_string,const char * new_name,const char * old_name)1325*2d543d20SAndroid Build Coastguard Worker static char **split_args(const char *arg0, char *arg_string,
1326*2d543d20SAndroid Build Coastguard Worker 			 const char *new_name, const char *old_name)
1327*2d543d20SAndroid Build Coastguard Worker {
1328*2d543d20SAndroid Build Coastguard Worker 	char **argv = NULL, *s, *arg = NULL, *targ;
1329*2d543d20SAndroid Build Coastguard Worker 	int num_args = 0, in_quote = 0, in_dquote = 0, rc;
1330*2d543d20SAndroid Build Coastguard Worker 
1331*2d543d20SAndroid Build Coastguard Worker 	rc = append_arg(&argv, &num_args, arg0);
1332*2d543d20SAndroid Build Coastguard Worker 	if (rc)
1333*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
1334*2d543d20SAndroid Build Coastguard Worker 	s = arg_string;
1335*2d543d20SAndroid Build Coastguard Worker 	/* parse the argument string one character at a time,
1336*2d543d20SAndroid Build Coastguard Worker 	 * respecting quotes and other special characters */
1337*2d543d20SAndroid Build Coastguard Worker 	while (s != NULL && *s != '\0') {
1338*2d543d20SAndroid Build Coastguard Worker 		switch (*s) {
1339*2d543d20SAndroid Build Coastguard Worker 		case '\\':{
1340*2d543d20SAndroid Build Coastguard Worker 				if (*(s + 1) == '\0') {
1341*2d543d20SAndroid Build Coastguard Worker 					targ = append(arg, '\\');
1342*2d543d20SAndroid Build Coastguard Worker 					if (targ == NULL)
1343*2d543d20SAndroid Build Coastguard Worker 						goto cleanup;
1344*2d543d20SAndroid Build Coastguard Worker 					arg = targ;
1345*2d543d20SAndroid Build Coastguard Worker 				} else {
1346*2d543d20SAndroid Build Coastguard Worker 					targ = append(arg, *(s + 1));
1347*2d543d20SAndroid Build Coastguard Worker 					if (targ == NULL)
1348*2d543d20SAndroid Build Coastguard Worker 						goto cleanup;
1349*2d543d20SAndroid Build Coastguard Worker 					arg = targ;
1350*2d543d20SAndroid Build Coastguard Worker 					s++;
1351*2d543d20SAndroid Build Coastguard Worker 				}
1352*2d543d20SAndroid Build Coastguard Worker 				break;
1353*2d543d20SAndroid Build Coastguard Worker 			}
1354*2d543d20SAndroid Build Coastguard Worker 		case '\'':{
1355*2d543d20SAndroid Build Coastguard Worker 				if (in_dquote) {
1356*2d543d20SAndroid Build Coastguard Worker 					targ = append(arg, *s);
1357*2d543d20SAndroid Build Coastguard Worker 					if (targ == NULL)
1358*2d543d20SAndroid Build Coastguard Worker 						goto cleanup;
1359*2d543d20SAndroid Build Coastguard Worker 					arg = targ;
1360*2d543d20SAndroid Build Coastguard Worker 				} else if (in_quote) {
1361*2d543d20SAndroid Build Coastguard Worker 					in_quote = 0;
1362*2d543d20SAndroid Build Coastguard Worker 				} else {
1363*2d543d20SAndroid Build Coastguard Worker 					in_quote = 1;
1364*2d543d20SAndroid Build Coastguard Worker 					targ = append(arg, '\0');
1365*2d543d20SAndroid Build Coastguard Worker 					if (targ == NULL)
1366*2d543d20SAndroid Build Coastguard Worker 						goto cleanup;
1367*2d543d20SAndroid Build Coastguard Worker 					arg = targ;
1368*2d543d20SAndroid Build Coastguard Worker 				}
1369*2d543d20SAndroid Build Coastguard Worker 				break;
1370*2d543d20SAndroid Build Coastguard Worker 			}
1371*2d543d20SAndroid Build Coastguard Worker 		case '\"':{
1372*2d543d20SAndroid Build Coastguard Worker 				if (in_quote) {
1373*2d543d20SAndroid Build Coastguard Worker 					targ = append(arg, *s);
1374*2d543d20SAndroid Build Coastguard Worker 					if (targ == NULL)
1375*2d543d20SAndroid Build Coastguard Worker 						goto cleanup;
1376*2d543d20SAndroid Build Coastguard Worker 					arg = targ;
1377*2d543d20SAndroid Build Coastguard Worker 				} else if (in_dquote) {
1378*2d543d20SAndroid Build Coastguard Worker 					in_dquote = 0;
1379*2d543d20SAndroid Build Coastguard Worker 				} else {
1380*2d543d20SAndroid Build Coastguard Worker 					in_dquote = 1;
1381*2d543d20SAndroid Build Coastguard Worker 					targ = append(arg, '\0');
1382*2d543d20SAndroid Build Coastguard Worker 					if (targ == NULL)
1383*2d543d20SAndroid Build Coastguard Worker 						goto cleanup;
1384*2d543d20SAndroid Build Coastguard Worker 					arg = targ;
1385*2d543d20SAndroid Build Coastguard Worker 				}
1386*2d543d20SAndroid Build Coastguard Worker 				break;
1387*2d543d20SAndroid Build Coastguard Worker 			}
1388*2d543d20SAndroid Build Coastguard Worker 		case '$':{
1389*2d543d20SAndroid Build Coastguard Worker 				switch (*(s + 1)) {
1390*2d543d20SAndroid Build Coastguard Worker 				case '@':{
1391*2d543d20SAndroid Build Coastguard Worker 						targ = append_str(arg, new_name);
1392*2d543d20SAndroid Build Coastguard Worker 						if (targ == NULL)
1393*2d543d20SAndroid Build Coastguard Worker 							goto cleanup;
1394*2d543d20SAndroid Build Coastguard Worker 						arg = targ;
1395*2d543d20SAndroid Build Coastguard Worker 						s++;
1396*2d543d20SAndroid Build Coastguard Worker 						break;
1397*2d543d20SAndroid Build Coastguard Worker 					}
1398*2d543d20SAndroid Build Coastguard Worker 				case '<':{
1399*2d543d20SAndroid Build Coastguard Worker 						targ = append_str(arg, old_name);
1400*2d543d20SAndroid Build Coastguard Worker 						if (targ == NULL)
1401*2d543d20SAndroid Build Coastguard Worker 							goto cleanup;
1402*2d543d20SAndroid Build Coastguard Worker 						arg = targ;
1403*2d543d20SAndroid Build Coastguard Worker 						s++;
1404*2d543d20SAndroid Build Coastguard Worker 						break;
1405*2d543d20SAndroid Build Coastguard Worker 					}
1406*2d543d20SAndroid Build Coastguard Worker 				default:{
1407*2d543d20SAndroid Build Coastguard Worker 						targ = append(arg, *s);
1408*2d543d20SAndroid Build Coastguard Worker 						if (targ == NULL)
1409*2d543d20SAndroid Build Coastguard Worker 							goto cleanup;
1410*2d543d20SAndroid Build Coastguard Worker 						arg = targ;
1411*2d543d20SAndroid Build Coastguard Worker 					}
1412*2d543d20SAndroid Build Coastguard Worker 				}
1413*2d543d20SAndroid Build Coastguard Worker 				break;
1414*2d543d20SAndroid Build Coastguard Worker 			}
1415*2d543d20SAndroid Build Coastguard Worker 		default:{
1416*2d543d20SAndroid Build Coastguard Worker 				if (isspace(*s) && !in_quote && !in_dquote) {
1417*2d543d20SAndroid Build Coastguard Worker 					if (arg != NULL) {
1418*2d543d20SAndroid Build Coastguard Worker 						rc = append_arg(&argv, &num_args, arg);
1419*2d543d20SAndroid Build Coastguard Worker 						if (rc)
1420*2d543d20SAndroid Build Coastguard Worker 							goto cleanup;
1421*2d543d20SAndroid Build Coastguard Worker 						free(arg);
1422*2d543d20SAndroid Build Coastguard Worker 						arg = NULL;
1423*2d543d20SAndroid Build Coastguard Worker 					}
1424*2d543d20SAndroid Build Coastguard Worker 				} else {
1425*2d543d20SAndroid Build Coastguard Worker 					if ((targ = append(arg, *s)) == NULL) {
1426*2d543d20SAndroid Build Coastguard Worker 						goto cleanup;
1427*2d543d20SAndroid Build Coastguard Worker 					} else {
1428*2d543d20SAndroid Build Coastguard Worker 						arg = targ;
1429*2d543d20SAndroid Build Coastguard Worker 					}
1430*2d543d20SAndroid Build Coastguard Worker 				}
1431*2d543d20SAndroid Build Coastguard Worker 			}
1432*2d543d20SAndroid Build Coastguard Worker 		}
1433*2d543d20SAndroid Build Coastguard Worker 		s++;
1434*2d543d20SAndroid Build Coastguard Worker 	}
1435*2d543d20SAndroid Build Coastguard Worker 	if (arg != NULL) {
1436*2d543d20SAndroid Build Coastguard Worker 		rc = append_arg(&argv, &num_args, arg);
1437*2d543d20SAndroid Build Coastguard Worker 		if (rc)
1438*2d543d20SAndroid Build Coastguard Worker 			goto cleanup;
1439*2d543d20SAndroid Build Coastguard Worker 		free(arg);
1440*2d543d20SAndroid Build Coastguard Worker 		arg = NULL;
1441*2d543d20SAndroid Build Coastguard Worker 	}
1442*2d543d20SAndroid Build Coastguard Worker 	/* explicitly add a NULL at the end */
1443*2d543d20SAndroid Build Coastguard Worker 	rc = append_arg(&argv, &num_args, NULL);
1444*2d543d20SAndroid Build Coastguard Worker 	if (rc)
1445*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
1446*2d543d20SAndroid Build Coastguard Worker 	return argv;
1447*2d543d20SAndroid Build Coastguard Worker       cleanup:
1448*2d543d20SAndroid Build Coastguard Worker 	free_argv(argv);
1449*2d543d20SAndroid Build Coastguard Worker 	free(arg);
1450*2d543d20SAndroid Build Coastguard Worker 	return NULL;
1451*2d543d20SAndroid Build Coastguard Worker }
1452*2d543d20SAndroid Build Coastguard Worker 
1453*2d543d20SAndroid Build Coastguard Worker /* Take the arguments given in v->args and expand any $ macros within.
1454*2d543d20SAndroid Build Coastguard Worker  * Split the arguments into different strings (argv).  Next fork and
1455*2d543d20SAndroid Build Coastguard Worker  * execute the process.	 BE SURE THAT ALL FILE DESCRIPTORS ARE SET TO
1456*2d543d20SAndroid Build Coastguard Worker  * CLOSE-ON-EXEC.  Take the return value of the child process and
1457*2d543d20SAndroid Build Coastguard Worker  * return it, -1 on error.
1458*2d543d20SAndroid Build Coastguard Worker  */
semanage_exec_prog(semanage_handle_t * sh,external_prog_t * e,const char * new_name,const char * old_name)1459*2d543d20SAndroid Build Coastguard Worker static int semanage_exec_prog(semanage_handle_t * sh,
1460*2d543d20SAndroid Build Coastguard Worker 			      external_prog_t * e, const char *new_name,
1461*2d543d20SAndroid Build Coastguard Worker 			      const char *old_name)
1462*2d543d20SAndroid Build Coastguard Worker {
1463*2d543d20SAndroid Build Coastguard Worker 	char **argv;
1464*2d543d20SAndroid Build Coastguard Worker 	pid_t forkval;
1465*2d543d20SAndroid Build Coastguard Worker 	int status = 0;
1466*2d543d20SAndroid Build Coastguard Worker 
1467*2d543d20SAndroid Build Coastguard Worker 	argv = split_args(e->path, e->args, new_name, old_name);
1468*2d543d20SAndroid Build Coastguard Worker 	if (argv == NULL) {
1469*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Out of memory!");
1470*2d543d20SAndroid Build Coastguard Worker 		return -1;
1471*2d543d20SAndroid Build Coastguard Worker 	}
1472*2d543d20SAndroid Build Coastguard Worker 
1473*2d543d20SAndroid Build Coastguard Worker 	/* no need to use pthread_atfork() -- child will not be using
1474*2d543d20SAndroid Build Coastguard Worker 	 * any mutexes. */
1475*2d543d20SAndroid Build Coastguard Worker 	forkval = vfork();
1476*2d543d20SAndroid Build Coastguard Worker 	if (forkval == 0) {
1477*2d543d20SAndroid Build Coastguard Worker 		/* child process.  file descriptors will be closed
1478*2d543d20SAndroid Build Coastguard Worker 		 * because they were set as close-on-exec. */
1479*2d543d20SAndroid Build Coastguard Worker 		execve(e->path, argv, NULL);
1480*2d543d20SAndroid Build Coastguard Worker 		_exit(EXIT_FAILURE);	/* if execve() failed */
1481*2d543d20SAndroid Build Coastguard Worker 	}
1482*2d543d20SAndroid Build Coastguard Worker 
1483*2d543d20SAndroid Build Coastguard Worker 	free_argv(argv);
1484*2d543d20SAndroid Build Coastguard Worker 
1485*2d543d20SAndroid Build Coastguard Worker 	if (forkval == -1) {
1486*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Error while forking process.");
1487*2d543d20SAndroid Build Coastguard Worker 		return -1;
1488*2d543d20SAndroid Build Coastguard Worker 	}
1489*2d543d20SAndroid Build Coastguard Worker 
1490*2d543d20SAndroid Build Coastguard Worker 	/* parent process.  wait for child to finish */
1491*2d543d20SAndroid Build Coastguard Worker 	if (waitpid(forkval, &status, 0) == -1 || !WIFEXITED(status)) {
1492*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Child process %s did not exit cleanly.",
1493*2d543d20SAndroid Build Coastguard Worker 		    e->path);
1494*2d543d20SAndroid Build Coastguard Worker 		return -1;
1495*2d543d20SAndroid Build Coastguard Worker 	}
1496*2d543d20SAndroid Build Coastguard Worker 	return WEXITSTATUS(status);
1497*2d543d20SAndroid Build Coastguard Worker }
1498*2d543d20SAndroid Build Coastguard Worker 
1499*2d543d20SAndroid Build Coastguard Worker /* reloads the policy pointed to by the handle, used locally by install
1500*2d543d20SAndroid Build Coastguard Worker  * and exported for user reload requests */
semanage_reload_policy(semanage_handle_t * sh)1501*2d543d20SAndroid Build Coastguard Worker int semanage_reload_policy(semanage_handle_t * sh)
1502*2d543d20SAndroid Build Coastguard Worker {
1503*2d543d20SAndroid Build Coastguard Worker 	int r = 0;
1504*2d543d20SAndroid Build Coastguard Worker 
1505*2d543d20SAndroid Build Coastguard Worker 	if (!sh)
1506*2d543d20SAndroid Build Coastguard Worker 		return -1;
1507*2d543d20SAndroid Build Coastguard Worker 
1508*2d543d20SAndroid Build Coastguard Worker 	if ((r = semanage_exec_prog(sh, sh->conf->load_policy, "", "")) != 0) {
1509*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "load_policy returned error code %d.", r);
1510*2d543d20SAndroid Build Coastguard Worker 	}
1511*2d543d20SAndroid Build Coastguard Worker 	return r;
1512*2d543d20SAndroid Build Coastguard Worker }
1513*2d543d20SAndroid Build Coastguard Worker 
1514*2d543d20SAndroid Build Coastguard Worker 
1515*2d543d20SAndroid Build Coastguard Worker /* This expands the file_context.tmpl file to file_context and homedirs.template */
semanage_split_fc(semanage_handle_t * sh)1516*2d543d20SAndroid Build Coastguard Worker int semanage_split_fc(semanage_handle_t * sh)
1517*2d543d20SAndroid Build Coastguard Worker {
1518*2d543d20SAndroid Build Coastguard Worker 	FILE *file_con = NULL;
1519*2d543d20SAndroid Build Coastguard Worker 	int fc = -1, hd = -1, retval = -1;
1520*2d543d20SAndroid Build Coastguard Worker 	char buf[PATH_MAX] = { 0 };
1521*2d543d20SAndroid Build Coastguard Worker 
1522*2d543d20SAndroid Build Coastguard Worker 	/* I use fopen here instead of open so that I can use fgets which only reads a single line */
1523*2d543d20SAndroid Build Coastguard Worker 	file_con = fopen(semanage_path(SEMANAGE_TMP, SEMANAGE_FC_TMPL), "r");
1524*2d543d20SAndroid Build Coastguard Worker 	if (!file_con) {
1525*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Could not open %s for reading.",
1526*2d543d20SAndroid Build Coastguard Worker 		    semanage_path(SEMANAGE_TMP, SEMANAGE_FC_TMPL));
1527*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
1528*2d543d20SAndroid Build Coastguard Worker 	}
1529*2d543d20SAndroid Build Coastguard Worker 
1530*2d543d20SAndroid Build Coastguard Worker 	fc = open(semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC),
1531*2d543d20SAndroid Build Coastguard Worker 		  O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
1532*2d543d20SAndroid Build Coastguard Worker 	if (fc < 0) {
1533*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Could not open %s for writing.",
1534*2d543d20SAndroid Build Coastguard Worker 		    semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC));
1535*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
1536*2d543d20SAndroid Build Coastguard Worker 	}
1537*2d543d20SAndroid Build Coastguard Worker 	hd = open(semanage_path(SEMANAGE_TMP, SEMANAGE_HOMEDIR_TMPL),
1538*2d543d20SAndroid Build Coastguard Worker 		  O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
1539*2d543d20SAndroid Build Coastguard Worker 	if (hd < 0) {
1540*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Could not open %s for writing.",
1541*2d543d20SAndroid Build Coastguard Worker 		    semanage_path(SEMANAGE_TMP, SEMANAGE_HOMEDIR_TMPL));
1542*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
1543*2d543d20SAndroid Build Coastguard Worker 	}
1544*2d543d20SAndroid Build Coastguard Worker 
1545*2d543d20SAndroid Build Coastguard Worker 	while (fgets_unlocked(buf, PATH_MAX, file_con)) {
1546*2d543d20SAndroid Build Coastguard Worker 		if (!strncmp(buf, "HOME_DIR", 8) ||
1547*2d543d20SAndroid Build Coastguard Worker 		    !strncmp(buf, "HOME_ROOT", 9) || strstr(buf, "ROLE") ||
1548*2d543d20SAndroid Build Coastguard Worker 		    strstr(buf, "USER")) {
1549*2d543d20SAndroid Build Coastguard Worker 			/* This contains one of the template variables, write it to homedir.template */
1550*2d543d20SAndroid Build Coastguard Worker 			if (write(hd, buf, strlen(buf)) < 0) {
1551*2d543d20SAndroid Build Coastguard Worker 				ERR(sh, "Write to %s failed.",
1552*2d543d20SAndroid Build Coastguard Worker 				    semanage_path(SEMANAGE_TMP,
1553*2d543d20SAndroid Build Coastguard Worker 						  SEMANAGE_HOMEDIR_TMPL));
1554*2d543d20SAndroid Build Coastguard Worker 				goto cleanup;
1555*2d543d20SAndroid Build Coastguard Worker 			}
1556*2d543d20SAndroid Build Coastguard Worker 		} else {
1557*2d543d20SAndroid Build Coastguard Worker 			if (write(fc, buf, strlen(buf)) < 0) {
1558*2d543d20SAndroid Build Coastguard Worker 				ERR(sh, "Write to %s failed.",
1559*2d543d20SAndroid Build Coastguard Worker 				    semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC));
1560*2d543d20SAndroid Build Coastguard Worker 				goto cleanup;
1561*2d543d20SAndroid Build Coastguard Worker 			}
1562*2d543d20SAndroid Build Coastguard Worker 		}
1563*2d543d20SAndroid Build Coastguard Worker 	}
1564*2d543d20SAndroid Build Coastguard Worker 
1565*2d543d20SAndroid Build Coastguard Worker 	retval = 0;
1566*2d543d20SAndroid Build Coastguard Worker       cleanup:
1567*2d543d20SAndroid Build Coastguard Worker 	if (file_con)
1568*2d543d20SAndroid Build Coastguard Worker 		fclose(file_con);
1569*2d543d20SAndroid Build Coastguard Worker 	if (fc >= 0)
1570*2d543d20SAndroid Build Coastguard Worker 		close(fc);
1571*2d543d20SAndroid Build Coastguard Worker 	if (hd >= 0)
1572*2d543d20SAndroid Build Coastguard Worker 		close(hd);
1573*2d543d20SAndroid Build Coastguard Worker 
1574*2d543d20SAndroid Build Coastguard Worker 	return retval;
1575*2d543d20SAndroid Build Coastguard Worker 
1576*2d543d20SAndroid Build Coastguard Worker }
1577*2d543d20SAndroid Build Coastguard Worker 
sefcontext_compile(semanage_handle_t * sh,const char * path)1578*2d543d20SAndroid Build Coastguard Worker static int sefcontext_compile(semanage_handle_t * sh, const char *path) {
1579*2d543d20SAndroid Build Coastguard Worker 
1580*2d543d20SAndroid Build Coastguard Worker 	int r;
1581*2d543d20SAndroid Build Coastguard Worker 	struct stat sb;
1582*2d543d20SAndroid Build Coastguard Worker 
1583*2d543d20SAndroid Build Coastguard Worker 	if (stat(path, &sb) < 0) {
1584*2d543d20SAndroid Build Coastguard Worker 		if (errno != ENOENT) {
1585*2d543d20SAndroid Build Coastguard Worker 			ERR(sh, "Unable to access %s: %s\n", path, strerror(errno));
1586*2d543d20SAndroid Build Coastguard Worker 			return -1;
1587*2d543d20SAndroid Build Coastguard Worker 		}
1588*2d543d20SAndroid Build Coastguard Worker 
1589*2d543d20SAndroid Build Coastguard Worker 		return 0;
1590*2d543d20SAndroid Build Coastguard Worker 	}
1591*2d543d20SAndroid Build Coastguard Worker 
1592*2d543d20SAndroid Build Coastguard Worker 	if ((r = semanage_exec_prog(sh, sh->conf->sefcontext_compile, path, "")) != 0) {
1593*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "sefcontext_compile returned error code %d. Compiling %s", r, path);
1594*2d543d20SAndroid Build Coastguard Worker 		return -1;
1595*2d543d20SAndroid Build Coastguard Worker 	}
1596*2d543d20SAndroid Build Coastguard Worker 
1597*2d543d20SAndroid Build Coastguard Worker 	return 0;
1598*2d543d20SAndroid Build Coastguard Worker }
1599*2d543d20SAndroid Build Coastguard Worker 
semanage_validate_and_compile_fcontexts(semanage_handle_t * sh)1600*2d543d20SAndroid Build Coastguard Worker static int semanage_validate_and_compile_fcontexts(semanage_handle_t * sh)
1601*2d543d20SAndroid Build Coastguard Worker {
1602*2d543d20SAndroid Build Coastguard Worker 	int status = -1;
1603*2d543d20SAndroid Build Coastguard Worker 
1604*2d543d20SAndroid Build Coastguard Worker 	if (sh->do_check_contexts) {
1605*2d543d20SAndroid Build Coastguard Worker 		int ret;
1606*2d543d20SAndroid Build Coastguard Worker 		ret = semanage_exec_prog(
1607*2d543d20SAndroid Build Coastguard Worker 			sh,
1608*2d543d20SAndroid Build Coastguard Worker 			sh->conf->setfiles,
1609*2d543d20SAndroid Build Coastguard Worker 			semanage_final_path(SEMANAGE_FINAL_TMP,
1610*2d543d20SAndroid Build Coastguard Worker 					    SEMANAGE_KERNEL),
1611*2d543d20SAndroid Build Coastguard Worker 			semanage_final_path(SEMANAGE_FINAL_TMP,
1612*2d543d20SAndroid Build Coastguard Worker 					    SEMANAGE_FC));
1613*2d543d20SAndroid Build Coastguard Worker 		if (ret != 0) {
1614*2d543d20SAndroid Build Coastguard Worker 			ERR(sh, "setfiles returned error code %d.", ret);
1615*2d543d20SAndroid Build Coastguard Worker 			goto cleanup;
1616*2d543d20SAndroid Build Coastguard Worker 		}
1617*2d543d20SAndroid Build Coastguard Worker 	}
1618*2d543d20SAndroid Build Coastguard Worker 
1619*2d543d20SAndroid Build Coastguard Worker 	if (sefcontext_compile(sh,
1620*2d543d20SAndroid Build Coastguard Worker 		    semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC)) != 0) {
1621*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
1622*2d543d20SAndroid Build Coastguard Worker 	}
1623*2d543d20SAndroid Build Coastguard Worker 	semanage_setfiles(semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC_BIN));
1624*2d543d20SAndroid Build Coastguard Worker 
1625*2d543d20SAndroid Build Coastguard Worker 	if (sefcontext_compile(sh,
1626*2d543d20SAndroid Build Coastguard Worker 		    semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC_LOCAL)) != 0) {
1627*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
1628*2d543d20SAndroid Build Coastguard Worker 	}
1629*2d543d20SAndroid Build Coastguard Worker 	semanage_setfiles(semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC_LOCAL_BIN));
1630*2d543d20SAndroid Build Coastguard Worker 
1631*2d543d20SAndroid Build Coastguard Worker 	if (sefcontext_compile(sh,
1632*2d543d20SAndroid Build Coastguard Worker 		    semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC_HOMEDIRS)) != 0) {
1633*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
1634*2d543d20SAndroid Build Coastguard Worker 	}
1635*2d543d20SAndroid Build Coastguard Worker 	semanage_setfiles(semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC_HOMEDIRS_BIN));
1636*2d543d20SAndroid Build Coastguard Worker 
1637*2d543d20SAndroid Build Coastguard Worker 	status = 0;
1638*2d543d20SAndroid Build Coastguard Worker cleanup:
1639*2d543d20SAndroid Build Coastguard Worker 	return status;
1640*2d543d20SAndroid Build Coastguard Worker }
1641*2d543d20SAndroid Build Coastguard Worker 
1642*2d543d20SAndroid Build Coastguard Worker /* Load the contexts of the final tmp into the final selinux directory.
1643*2d543d20SAndroid Build Coastguard Worker  * Return 0 on success, -3 on error.
1644*2d543d20SAndroid Build Coastguard Worker  */
semanage_install_final_tmp(semanage_handle_t * sh)1645*2d543d20SAndroid Build Coastguard Worker static int semanage_install_final_tmp(semanage_handle_t * sh)
1646*2d543d20SAndroid Build Coastguard Worker {
1647*2d543d20SAndroid Build Coastguard Worker 	int status = -3;
1648*2d543d20SAndroid Build Coastguard Worker 	int ret = 0;
1649*2d543d20SAndroid Build Coastguard Worker 	int i = 0;
1650*2d543d20SAndroid Build Coastguard Worker 	const char *src = NULL;
1651*2d543d20SAndroid Build Coastguard Worker 	const char *dst = NULL;
1652*2d543d20SAndroid Build Coastguard Worker 	struct stat sb;
1653*2d543d20SAndroid Build Coastguard Worker 	char fn[PATH_MAX];
1654*2d543d20SAndroid Build Coastguard Worker 
1655*2d543d20SAndroid Build Coastguard Worker 	/* For each of the final files install it if it exists.
1656*2d543d20SAndroid Build Coastguard Worker 	 * i = 1 to avoid copying the top level directory.
1657*2d543d20SAndroid Build Coastguard Worker 	 */
1658*2d543d20SAndroid Build Coastguard Worker 	for (i = 1; i < SEMANAGE_FINAL_PATH_NUM; i++) {
1659*2d543d20SAndroid Build Coastguard Worker 		src = semanage_final_path(SEMANAGE_FINAL_TMP, i);
1660*2d543d20SAndroid Build Coastguard Worker 		dst = semanage_final_path(SEMANAGE_FINAL_SELINUX, i);
1661*2d543d20SAndroid Build Coastguard Worker 
1662*2d543d20SAndroid Build Coastguard Worker 		/* skip file if src doesn't exist */
1663*2d543d20SAndroid Build Coastguard Worker 		if (stat(src, &sb) != 0) continue;
1664*2d543d20SAndroid Build Coastguard Worker 
1665*2d543d20SAndroid Build Coastguard Worker 		/* skip genhomedircon if configured */
1666*2d543d20SAndroid Build Coastguard Worker 		if (sh->conf->disable_genhomedircon &&
1667*2d543d20SAndroid Build Coastguard Worker 		    i == SEMANAGE_FC_HOMEDIRS) continue;
1668*2d543d20SAndroid Build Coastguard Worker 
1669*2d543d20SAndroid Build Coastguard Worker 		if (strlen(dst) >= sizeof(fn)) {
1670*2d543d20SAndroid Build Coastguard Worker 			ERR(sh, "Unable to compose the final paths.");
1671*2d543d20SAndroid Build Coastguard Worker 			status = -1;
1672*2d543d20SAndroid Build Coastguard Worker 			goto cleanup;
1673*2d543d20SAndroid Build Coastguard Worker 		}
1674*2d543d20SAndroid Build Coastguard Worker 		strcpy(fn, dst);
1675*2d543d20SAndroid Build Coastguard Worker 		ret = semanage_mkpath(sh, dirname(fn));
1676*2d543d20SAndroid Build Coastguard Worker 		if (ret < 0) {
1677*2d543d20SAndroid Build Coastguard Worker 			goto cleanup;
1678*2d543d20SAndroid Build Coastguard Worker 		}
1679*2d543d20SAndroid Build Coastguard Worker 
1680*2d543d20SAndroid Build Coastguard Worker 		ret = semanage_copy_file(src, dst, sh->conf->file_mode,
1681*2d543d20SAndroid Build Coastguard Worker 					true);
1682*2d543d20SAndroid Build Coastguard Worker 		if (ret < 0) {
1683*2d543d20SAndroid Build Coastguard Worker 			ERR(sh, "Could not copy %s to %s.", src, dst);
1684*2d543d20SAndroid Build Coastguard Worker 			goto cleanup;
1685*2d543d20SAndroid Build Coastguard Worker 		}
1686*2d543d20SAndroid Build Coastguard Worker 	}
1687*2d543d20SAndroid Build Coastguard Worker 
1688*2d543d20SAndroid Build Coastguard Worker 	if (!sh->do_reload)
1689*2d543d20SAndroid Build Coastguard Worker 		goto skip_reload;
1690*2d543d20SAndroid Build Coastguard Worker 
1691*2d543d20SAndroid Build Coastguard Worker 	/* This stats what libselinux says the active store is (according to config)
1692*2d543d20SAndroid Build Coastguard Worker 	 * and what we are installing to, to decide if they are the same store. If
1693*2d543d20SAndroid Build Coastguard Worker 	 * they are not then we do not reload policy.
1694*2d543d20SAndroid Build Coastguard Worker 	 */
1695*2d543d20SAndroid Build Coastguard Worker 	const char *really_active_store = selinux_policy_root();
1696*2d543d20SAndroid Build Coastguard Worker 	struct stat astore;
1697*2d543d20SAndroid Build Coastguard Worker 	struct stat istore;
1698*2d543d20SAndroid Build Coastguard Worker 	const char *storepath = semanage_final_path(SEMANAGE_FINAL_SELINUX,
1699*2d543d20SAndroid Build Coastguard Worker 						    SEMANAGE_FINAL_TOPLEVEL);
1700*2d543d20SAndroid Build Coastguard Worker 
1701*2d543d20SAndroid Build Coastguard Worker 	if (stat(really_active_store, &astore) == 0) {
1702*2d543d20SAndroid Build Coastguard Worker 		if (stat(storepath, &istore)) {
1703*2d543d20SAndroid Build Coastguard Worker 			ERR(sh, "Could not stat store path %s.", storepath);
1704*2d543d20SAndroid Build Coastguard Worker 			goto cleanup;
1705*2d543d20SAndroid Build Coastguard Worker 		}
1706*2d543d20SAndroid Build Coastguard Worker 
1707*2d543d20SAndroid Build Coastguard Worker 		if (!(astore.st_ino == istore.st_ino &&
1708*2d543d20SAndroid Build Coastguard Worker 		      astore.st_dev == istore.st_dev)) {
1709*2d543d20SAndroid Build Coastguard Worker 			/* They are not the same store */
1710*2d543d20SAndroid Build Coastguard Worker 			goto skip_reload;
1711*2d543d20SAndroid Build Coastguard Worker 		}
1712*2d543d20SAndroid Build Coastguard Worker 	} else if (errno == ENOENT &&
1713*2d543d20SAndroid Build Coastguard Worker 		   strcmp(really_active_store, storepath) != 0) {
1714*2d543d20SAndroid Build Coastguard Worker 		errno = 0;
1715*2d543d20SAndroid Build Coastguard Worker 		goto skip_reload;
1716*2d543d20SAndroid Build Coastguard Worker 	}
1717*2d543d20SAndroid Build Coastguard Worker 
1718*2d543d20SAndroid Build Coastguard Worker 	if (semanage_reload_policy(sh)) {
1719*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
1720*2d543d20SAndroid Build Coastguard Worker 	}
1721*2d543d20SAndroid Build Coastguard Worker 
1722*2d543d20SAndroid Build Coastguard Worker skip_reload:
1723*2d543d20SAndroid Build Coastguard Worker 	status = 0;
1724*2d543d20SAndroid Build Coastguard Worker cleanup:
1725*2d543d20SAndroid Build Coastguard Worker 	return status;
1726*2d543d20SAndroid Build Coastguard Worker }
1727*2d543d20SAndroid Build Coastguard Worker 
1728*2d543d20SAndroid Build Coastguard Worker /* Prepare the sandbox to be installed by making a backup of the
1729*2d543d20SAndroid Build Coastguard Worker  * current active directory.  Then copy the sandbox to the active
1730*2d543d20SAndroid Build Coastguard Worker  * directory.  Return the new commit number on success, negative
1731*2d543d20SAndroid Build Coastguard Worker  * values on error. */
semanage_commit_sandbox(semanage_handle_t * sh)1732*2d543d20SAndroid Build Coastguard Worker static int semanage_commit_sandbox(semanage_handle_t * sh)
1733*2d543d20SAndroid Build Coastguard Worker {
1734*2d543d20SAndroid Build Coastguard Worker 	int commit_number, fd, retval;
1735*2d543d20SAndroid Build Coastguard Worker 	char write_buf[32];
1736*2d543d20SAndroid Build Coastguard Worker 	const char *commit_filename =
1737*2d543d20SAndroid Build Coastguard Worker 	    semanage_path(SEMANAGE_TMP, SEMANAGE_COMMIT_NUM_FILE);
1738*2d543d20SAndroid Build Coastguard Worker 	ssize_t amount_written;
1739*2d543d20SAndroid Build Coastguard Worker 	const char *active = semanage_path(SEMANAGE_ACTIVE, SEMANAGE_TOPLEVEL);
1740*2d543d20SAndroid Build Coastguard Worker 	const char *backup =
1741*2d543d20SAndroid Build Coastguard Worker 	    semanage_path(SEMANAGE_PREVIOUS, SEMANAGE_TOPLEVEL);
1742*2d543d20SAndroid Build Coastguard Worker 	const char *sandbox = semanage_path(SEMANAGE_TMP, SEMANAGE_TOPLEVEL);
1743*2d543d20SAndroid Build Coastguard Worker 	struct stat buf;
1744*2d543d20SAndroid Build Coastguard Worker 
1745*2d543d20SAndroid Build Coastguard Worker 	/* update the commit number */
1746*2d543d20SAndroid Build Coastguard Worker 	if ((commit_number = semanage_direct_get_serial(sh)) < 0) {
1747*2d543d20SAndroid Build Coastguard Worker 		return -1;
1748*2d543d20SAndroid Build Coastguard Worker 	}
1749*2d543d20SAndroid Build Coastguard Worker 	commit_number++;
1750*2d543d20SAndroid Build Coastguard Worker 	memset(write_buf, 0, sizeof(write_buf));
1751*2d543d20SAndroid Build Coastguard Worker 	snprintf(write_buf, sizeof(write_buf), "%d", commit_number);
1752*2d543d20SAndroid Build Coastguard Worker 	if ((fd =
1753*2d543d20SAndroid Build Coastguard Worker 	     open(commit_filename, O_WRONLY | O_CREAT | O_TRUNC,
1754*2d543d20SAndroid Build Coastguard Worker 		  S_IRUSR | S_IWUSR)) == -1) {
1755*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Could not open commit number file %s for writing.",
1756*2d543d20SAndroid Build Coastguard Worker 		    commit_filename);
1757*2d543d20SAndroid Build Coastguard Worker 		return -1;
1758*2d543d20SAndroid Build Coastguard Worker 	}
1759*2d543d20SAndroid Build Coastguard Worker 	amount_written = write(fd, write_buf, sizeof(write_buf));
1760*2d543d20SAndroid Build Coastguard Worker 	if (amount_written == -1) {
1761*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Error while writing commit number to %s.",
1762*2d543d20SAndroid Build Coastguard Worker 		    commit_filename);
1763*2d543d20SAndroid Build Coastguard Worker 		close(fd);
1764*2d543d20SAndroid Build Coastguard Worker 		return -1;
1765*2d543d20SAndroid Build Coastguard Worker 	}
1766*2d543d20SAndroid Build Coastguard Worker 	close(fd);
1767*2d543d20SAndroid Build Coastguard Worker 
1768*2d543d20SAndroid Build Coastguard Worker 	/* sync changes in sandbox to filesystem */
1769*2d543d20SAndroid Build Coastguard Worker 	fd = open(sandbox, O_DIRECTORY);
1770*2d543d20SAndroid Build Coastguard Worker 	if (fd == -1) {
1771*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Error while opening %s for syncfs(): %d", sandbox, errno);
1772*2d543d20SAndroid Build Coastguard Worker 		return -1;
1773*2d543d20SAndroid Build Coastguard Worker 	}
1774*2d543d20SAndroid Build Coastguard Worker 	if (syncfs(fd) == -1) {
1775*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Error while syncing %s to filesystem: %d", sandbox, errno);
1776*2d543d20SAndroid Build Coastguard Worker 		close(fd);
1777*2d543d20SAndroid Build Coastguard Worker 		return -1;
1778*2d543d20SAndroid Build Coastguard Worker 	}
1779*2d543d20SAndroid Build Coastguard Worker 	close(fd);
1780*2d543d20SAndroid Build Coastguard Worker 
1781*2d543d20SAndroid Build Coastguard Worker 	retval = commit_number;
1782*2d543d20SAndroid Build Coastguard Worker 
1783*2d543d20SAndroid Build Coastguard Worker 	if (semanage_get_active_lock(sh) < 0) {
1784*2d543d20SAndroid Build Coastguard Worker 		return -1;
1785*2d543d20SAndroid Build Coastguard Worker 	}
1786*2d543d20SAndroid Build Coastguard Worker 	/* make the backup of the current active directory */
1787*2d543d20SAndroid Build Coastguard Worker 	if (stat(backup, &buf) == 0) {
1788*2d543d20SAndroid Build Coastguard Worker 		if (S_ISDIR(buf.st_mode) &&
1789*2d543d20SAndroid Build Coastguard Worker 		    semanage_remove_directory(backup) != 0) {
1790*2d543d20SAndroid Build Coastguard Worker 			ERR(sh, "Could not remove previous backup %s.", backup);
1791*2d543d20SAndroid Build Coastguard Worker 			retval = -1;
1792*2d543d20SAndroid Build Coastguard Worker 			goto cleanup;
1793*2d543d20SAndroid Build Coastguard Worker 		}
1794*2d543d20SAndroid Build Coastguard Worker 	} else if (errno != ENOENT) {
1795*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Could not stat directory %s.", backup);
1796*2d543d20SAndroid Build Coastguard Worker 		retval = -1;
1797*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
1798*2d543d20SAndroid Build Coastguard Worker 	}
1799*2d543d20SAndroid Build Coastguard Worker 
1800*2d543d20SAndroid Build Coastguard Worker 	if (semanage_rename(sh, active, backup) == -1) {
1801*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Error while renaming %s to %s.", active, backup);
1802*2d543d20SAndroid Build Coastguard Worker 		retval = -1;
1803*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
1804*2d543d20SAndroid Build Coastguard Worker 	}
1805*2d543d20SAndroid Build Coastguard Worker 
1806*2d543d20SAndroid Build Coastguard Worker 	/* clean up some files from the sandbox before install */
1807*2d543d20SAndroid Build Coastguard Worker 	/* remove homedir_template from sandbox */
1808*2d543d20SAndroid Build Coastguard Worker 
1809*2d543d20SAndroid Build Coastguard Worker 	if (semanage_rename(sh, sandbox, active) == -1) {
1810*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Error while renaming %s to %s.", sandbox, active);
1811*2d543d20SAndroid Build Coastguard Worker 		/* note that if an error occurs during the next
1812*2d543d20SAndroid Build Coastguard Worker 		 * function then the store will be left in an
1813*2d543d20SAndroid Build Coastguard Worker 		 * inconsistent state */
1814*2d543d20SAndroid Build Coastguard Worker 		if (semanage_rename(sh, backup, active) < 0)
1815*2d543d20SAndroid Build Coastguard Worker 			ERR(sh, "Error while renaming %s back to %s.", backup,
1816*2d543d20SAndroid Build Coastguard Worker 			    active);
1817*2d543d20SAndroid Build Coastguard Worker 		retval = -1;
1818*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
1819*2d543d20SAndroid Build Coastguard Worker 	}
1820*2d543d20SAndroid Build Coastguard Worker 	if (semanage_install_final_tmp(sh) != 0) {
1821*2d543d20SAndroid Build Coastguard Worker 		/* note that if an error occurs during the next three
1822*2d543d20SAndroid Build Coastguard Worker 		 * function then the store will be left in an
1823*2d543d20SAndroid Build Coastguard Worker 		 * inconsistent state */
1824*2d543d20SAndroid Build Coastguard Worker 		int errsv = errno;
1825*2d543d20SAndroid Build Coastguard Worker 		if (semanage_rename(sh, active, sandbox) < 0)
1826*2d543d20SAndroid Build Coastguard Worker 			ERR(sh, "Error while renaming %s back to %s.", active,
1827*2d543d20SAndroid Build Coastguard Worker 			    sandbox);
1828*2d543d20SAndroid Build Coastguard Worker 		else if (semanage_rename(sh, backup, active) < 0)
1829*2d543d20SAndroid Build Coastguard Worker 			ERR(sh, "Error while renaming %s back to %s.", backup,
1830*2d543d20SAndroid Build Coastguard Worker 			    active);
1831*2d543d20SAndroid Build Coastguard Worker 		else
1832*2d543d20SAndroid Build Coastguard Worker 			semanage_install_final_tmp(sh);
1833*2d543d20SAndroid Build Coastguard Worker 		errno = errsv;
1834*2d543d20SAndroid Build Coastguard Worker 		retval = -1;
1835*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
1836*2d543d20SAndroid Build Coastguard Worker 	}
1837*2d543d20SAndroid Build Coastguard Worker 
1838*2d543d20SAndroid Build Coastguard Worker 	if (!sh->conf->save_previous) {
1839*2d543d20SAndroid Build Coastguard Worker 		int errsv = errno;
1840*2d543d20SAndroid Build Coastguard Worker 		if (semanage_remove_directory(backup) != 0) {
1841*2d543d20SAndroid Build Coastguard Worker 			ERR(sh, "Could not delete previous directory %s.", backup);
1842*2d543d20SAndroid Build Coastguard Worker 			retval = -1;
1843*2d543d20SAndroid Build Coastguard Worker 			goto cleanup;
1844*2d543d20SAndroid Build Coastguard Worker 		}
1845*2d543d20SAndroid Build Coastguard Worker 		errno = errsv;
1846*2d543d20SAndroid Build Coastguard Worker 	}
1847*2d543d20SAndroid Build Coastguard Worker 
1848*2d543d20SAndroid Build Coastguard Worker       cleanup:
1849*2d543d20SAndroid Build Coastguard Worker 	semanage_release_active_lock(sh);
1850*2d543d20SAndroid Build Coastguard Worker 	return retval;
1851*2d543d20SAndroid Build Coastguard Worker }
1852*2d543d20SAndroid Build Coastguard Worker 
1853*2d543d20SAndroid Build Coastguard Worker /* Takes the kernel policy in a sandbox, move it to the active
1854*2d543d20SAndroid Build Coastguard Worker  * directory, copy it to the binary policy path, then load it.	Upon
1855*2d543d20SAndroid Build Coastguard Worker  * error move the active directory back to the sandbox.	 This function
1856*2d543d20SAndroid Build Coastguard Worker  * should be placed within a mutex lock to ensure that it runs
1857*2d543d20SAndroid Build Coastguard Worker  * atomically.	Returns commit number on success, -1 on error.
1858*2d543d20SAndroid Build Coastguard Worker  */
semanage_install_sandbox(semanage_handle_t * sh)1859*2d543d20SAndroid Build Coastguard Worker int semanage_install_sandbox(semanage_handle_t * sh)
1860*2d543d20SAndroid Build Coastguard Worker {
1861*2d543d20SAndroid Build Coastguard Worker 	int retval = -1, commit_num = -1;
1862*2d543d20SAndroid Build Coastguard Worker 
1863*2d543d20SAndroid Build Coastguard Worker 	if (sh->conf->load_policy == NULL) {
1864*2d543d20SAndroid Build Coastguard Worker 		ERR(sh,
1865*2d543d20SAndroid Build Coastguard Worker 		    "No load_policy program specified in configuration file.");
1866*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
1867*2d543d20SAndroid Build Coastguard Worker 	}
1868*2d543d20SAndroid Build Coastguard Worker 	if (sh->conf->setfiles == NULL) {
1869*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "No setfiles program specified in configuration file.");
1870*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
1871*2d543d20SAndroid Build Coastguard Worker 	}
1872*2d543d20SAndroid Build Coastguard Worker 
1873*2d543d20SAndroid Build Coastguard Worker 	if (sh->conf->sefcontext_compile == NULL) {
1874*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "No sefcontext_compile program specified in configuration file.");
1875*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
1876*2d543d20SAndroid Build Coastguard Worker 	}
1877*2d543d20SAndroid Build Coastguard Worker 
1878*2d543d20SAndroid Build Coastguard Worker 	if (semanage_validate_and_compile_fcontexts(sh) < 0)
1879*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
1880*2d543d20SAndroid Build Coastguard Worker 
1881*2d543d20SAndroid Build Coastguard Worker 	if ((commit_num = semanage_commit_sandbox(sh)) < 0) {
1882*2d543d20SAndroid Build Coastguard Worker 		retval = commit_num;
1883*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
1884*2d543d20SAndroid Build Coastguard Worker 	}
1885*2d543d20SAndroid Build Coastguard Worker 
1886*2d543d20SAndroid Build Coastguard Worker 	retval = commit_num;
1887*2d543d20SAndroid Build Coastguard Worker 
1888*2d543d20SAndroid Build Coastguard Worker       cleanup:
1889*2d543d20SAndroid Build Coastguard Worker 	return retval;
1890*2d543d20SAndroid Build Coastguard Worker 
1891*2d543d20SAndroid Build Coastguard Worker }
1892*2d543d20SAndroid Build Coastguard Worker 
1893*2d543d20SAndroid Build Coastguard Worker /********************* functions that manipulate lock *********************/
1894*2d543d20SAndroid Build Coastguard Worker 
semanage_get_lock(semanage_handle_t * sh,const char * lock_name,const char * lock_file)1895*2d543d20SAndroid Build Coastguard Worker static int semanage_get_lock(semanage_handle_t * sh,
1896*2d543d20SAndroid Build Coastguard Worker 			     const char *lock_name, const char *lock_file)
1897*2d543d20SAndroid Build Coastguard Worker {
1898*2d543d20SAndroid Build Coastguard Worker 	int fd;
1899*2d543d20SAndroid Build Coastguard Worker 	struct timeval origtime, curtime;
1900*2d543d20SAndroid Build Coastguard Worker 	int got_lock = 0;
1901*2d543d20SAndroid Build Coastguard Worker 
1902*2d543d20SAndroid Build Coastguard Worker 	if ((fd = open(lock_file, O_RDONLY)) == -1) {
1903*2d543d20SAndroid Build Coastguard Worker 		if ((fd =
1904*2d543d20SAndroid Build Coastguard Worker 		     open(lock_file, O_RDWR | O_CREAT | O_TRUNC,
1905*2d543d20SAndroid Build Coastguard Worker 			  S_IRUSR | S_IWUSR)) == -1) {
1906*2d543d20SAndroid Build Coastguard Worker 			ERR(sh, "Could not open direct %s at %s.", lock_name,
1907*2d543d20SAndroid Build Coastguard Worker 			    lock_file);
1908*2d543d20SAndroid Build Coastguard Worker 			return -1;
1909*2d543d20SAndroid Build Coastguard Worker 		}
1910*2d543d20SAndroid Build Coastguard Worker 	}
1911*2d543d20SAndroid Build Coastguard Worker 	if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) {
1912*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Could not set close-on-exec for %s at %s.", lock_name,
1913*2d543d20SAndroid Build Coastguard Worker 		    lock_file);
1914*2d543d20SAndroid Build Coastguard Worker 		close(fd);
1915*2d543d20SAndroid Build Coastguard Worker 		return -1;
1916*2d543d20SAndroid Build Coastguard Worker 	}
1917*2d543d20SAndroid Build Coastguard Worker 
1918*2d543d20SAndroid Build Coastguard Worker 	if (sh->timeout == 0) {
1919*2d543d20SAndroid Build Coastguard Worker 		/* return immediately */
1920*2d543d20SAndroid Build Coastguard Worker 		origtime.tv_sec = 0;
1921*2d543d20SAndroid Build Coastguard Worker 	} else {
1922*2d543d20SAndroid Build Coastguard Worker 		origtime.tv_sec = sh->timeout;
1923*2d543d20SAndroid Build Coastguard Worker 	}
1924*2d543d20SAndroid Build Coastguard Worker 	origtime.tv_usec = 0;
1925*2d543d20SAndroid Build Coastguard Worker 	do {
1926*2d543d20SAndroid Build Coastguard Worker 		curtime.tv_sec = 1;
1927*2d543d20SAndroid Build Coastguard Worker 		curtime.tv_usec = 0;
1928*2d543d20SAndroid Build Coastguard Worker 		if (flock(fd, LOCK_EX | LOCK_NB) == 0) {
1929*2d543d20SAndroid Build Coastguard Worker 			got_lock = 1;
1930*2d543d20SAndroid Build Coastguard Worker 			break;
1931*2d543d20SAndroid Build Coastguard Worker 		} else if (errno != EAGAIN) {
1932*2d543d20SAndroid Build Coastguard Worker 			ERR(sh, "Error obtaining direct %s at %s.", lock_name,
1933*2d543d20SAndroid Build Coastguard Worker 			    lock_file);
1934*2d543d20SAndroid Build Coastguard Worker 			close(fd);
1935*2d543d20SAndroid Build Coastguard Worker 			return -1;
1936*2d543d20SAndroid Build Coastguard Worker 		}
1937*2d543d20SAndroid Build Coastguard Worker 		if (origtime.tv_sec > 0 || sh->timeout == -1) {
1938*2d543d20SAndroid Build Coastguard Worker 			if (select(0, NULL, NULL, NULL, &curtime) == -1) {
1939*2d543d20SAndroid Build Coastguard Worker 				if (errno == EINTR) {
1940*2d543d20SAndroid Build Coastguard Worker 					continue;
1941*2d543d20SAndroid Build Coastguard Worker 				}
1942*2d543d20SAndroid Build Coastguard Worker 				ERR(sh,
1943*2d543d20SAndroid Build Coastguard Worker 				    "Error while waiting to get direct %s at %s.",
1944*2d543d20SAndroid Build Coastguard Worker 				    lock_name, lock_file);
1945*2d543d20SAndroid Build Coastguard Worker 				close(fd);
1946*2d543d20SAndroid Build Coastguard Worker 				return -1;
1947*2d543d20SAndroid Build Coastguard Worker 			}
1948*2d543d20SAndroid Build Coastguard Worker 			origtime.tv_sec--;
1949*2d543d20SAndroid Build Coastguard Worker 		}
1950*2d543d20SAndroid Build Coastguard Worker 	} while (origtime.tv_sec > 0 || sh->timeout == -1);
1951*2d543d20SAndroid Build Coastguard Worker 	if (!got_lock) {
1952*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Could not get direct %s at %s.", lock_name, lock_file);
1953*2d543d20SAndroid Build Coastguard Worker 		close(fd);
1954*2d543d20SAndroid Build Coastguard Worker 		return -1;
1955*2d543d20SAndroid Build Coastguard Worker 	}
1956*2d543d20SAndroid Build Coastguard Worker 	return fd;
1957*2d543d20SAndroid Build Coastguard Worker }
1958*2d543d20SAndroid Build Coastguard Worker 
1959*2d543d20SAndroid Build Coastguard Worker /* Locking for the module store for transactions.  This is very basic
1960*2d543d20SAndroid Build Coastguard Worker  * locking of the module store and doesn't do anything if the module
1961*2d543d20SAndroid Build Coastguard Worker  * store is being manipulated with a program not using this library
1962*2d543d20SAndroid Build Coastguard Worker  * (but the policy should prevent that).  Returns 0 on success, -1 if
1963*2d543d20SAndroid Build Coastguard Worker  * it could not obtain a lock.
1964*2d543d20SAndroid Build Coastguard Worker  */
semanage_get_trans_lock(semanage_handle_t * sh)1965*2d543d20SAndroid Build Coastguard Worker int semanage_get_trans_lock(semanage_handle_t * sh)
1966*2d543d20SAndroid Build Coastguard Worker {
1967*2d543d20SAndroid Build Coastguard Worker 	const char *lock_file = semanage_files[SEMANAGE_TRANS_LOCK];
1968*2d543d20SAndroid Build Coastguard Worker 
1969*2d543d20SAndroid Build Coastguard Worker 	if (sh->u.direct.translock_file_fd >= 0)
1970*2d543d20SAndroid Build Coastguard Worker 		return 0;
1971*2d543d20SAndroid Build Coastguard Worker 
1972*2d543d20SAndroid Build Coastguard Worker 	sh->u.direct.translock_file_fd =
1973*2d543d20SAndroid Build Coastguard Worker 	    semanage_get_lock(sh, "transaction lock", lock_file);
1974*2d543d20SAndroid Build Coastguard Worker 	if (sh->u.direct.translock_file_fd >= 0) {
1975*2d543d20SAndroid Build Coastguard Worker 		return 0;
1976*2d543d20SAndroid Build Coastguard Worker 	} else {
1977*2d543d20SAndroid Build Coastguard Worker 		return -1;
1978*2d543d20SAndroid Build Coastguard Worker 	}
1979*2d543d20SAndroid Build Coastguard Worker }
1980*2d543d20SAndroid Build Coastguard Worker 
1981*2d543d20SAndroid Build Coastguard Worker /* Locking for the module store for active store reading; this also includes
1982*2d543d20SAndroid Build Coastguard Worker  * the file containing the commit number.  This is very basic locking
1983*2d543d20SAndroid Build Coastguard Worker  * of the module store and doesn't do anything if the module store is
1984*2d543d20SAndroid Build Coastguard Worker  * being manipulated with a program not using this library (but the
1985*2d543d20SAndroid Build Coastguard Worker  * policy should prevent that).	 Returns 0 on success, -1 if it could
1986*2d543d20SAndroid Build Coastguard Worker  * not obtain a lock.
1987*2d543d20SAndroid Build Coastguard Worker  */
semanage_get_active_lock(semanage_handle_t * sh)1988*2d543d20SAndroid Build Coastguard Worker int semanage_get_active_lock(semanage_handle_t * sh)
1989*2d543d20SAndroid Build Coastguard Worker {
1990*2d543d20SAndroid Build Coastguard Worker 	const char *lock_file = semanage_files[SEMANAGE_READ_LOCK];
1991*2d543d20SAndroid Build Coastguard Worker 
1992*2d543d20SAndroid Build Coastguard Worker 	if (sh->u.direct.activelock_file_fd >= 0)
1993*2d543d20SAndroid Build Coastguard Worker 		return 0;
1994*2d543d20SAndroid Build Coastguard Worker 
1995*2d543d20SAndroid Build Coastguard Worker 	sh->u.direct.activelock_file_fd =
1996*2d543d20SAndroid Build Coastguard Worker 	    semanage_get_lock(sh, "read lock", lock_file);
1997*2d543d20SAndroid Build Coastguard Worker 	if (sh->u.direct.activelock_file_fd >= 0) {
1998*2d543d20SAndroid Build Coastguard Worker 		return 0;
1999*2d543d20SAndroid Build Coastguard Worker 	} else {
2000*2d543d20SAndroid Build Coastguard Worker 		return -1;
2001*2d543d20SAndroid Build Coastguard Worker 	}
2002*2d543d20SAndroid Build Coastguard Worker }
2003*2d543d20SAndroid Build Coastguard Worker 
2004*2d543d20SAndroid Build Coastguard Worker /* Releases the transaction lock.  Does nothing if there was not one already
2005*2d543d20SAndroid Build Coastguard Worker  * there. */
semanage_release_trans_lock(semanage_handle_t * sh)2006*2d543d20SAndroid Build Coastguard Worker void semanage_release_trans_lock(semanage_handle_t * sh)
2007*2d543d20SAndroid Build Coastguard Worker {
2008*2d543d20SAndroid Build Coastguard Worker 	int errsv = errno;
2009*2d543d20SAndroid Build Coastguard Worker 	if (sh->u.direct.translock_file_fd >= 0) {
2010*2d543d20SAndroid Build Coastguard Worker 		flock(sh->u.direct.translock_file_fd, LOCK_UN);
2011*2d543d20SAndroid Build Coastguard Worker 		close(sh->u.direct.translock_file_fd);
2012*2d543d20SAndroid Build Coastguard Worker 		sh->u.direct.translock_file_fd = -1;
2013*2d543d20SAndroid Build Coastguard Worker 	}
2014*2d543d20SAndroid Build Coastguard Worker 	errno = errsv;
2015*2d543d20SAndroid Build Coastguard Worker }
2016*2d543d20SAndroid Build Coastguard Worker 
2017*2d543d20SAndroid Build Coastguard Worker /* Releases the read lock.  Does nothing if there was not one already
2018*2d543d20SAndroid Build Coastguard Worker  * there. */
semanage_release_active_lock(semanage_handle_t * sh)2019*2d543d20SAndroid Build Coastguard Worker void semanage_release_active_lock(semanage_handle_t * sh)
2020*2d543d20SAndroid Build Coastguard Worker {
2021*2d543d20SAndroid Build Coastguard Worker 	int errsv = errno;
2022*2d543d20SAndroid Build Coastguard Worker 	if (sh->u.direct.activelock_file_fd >= 0) {
2023*2d543d20SAndroid Build Coastguard Worker 		flock(sh->u.direct.activelock_file_fd, LOCK_UN);
2024*2d543d20SAndroid Build Coastguard Worker 		close(sh->u.direct.activelock_file_fd);
2025*2d543d20SAndroid Build Coastguard Worker 		sh->u.direct.activelock_file_fd = -1;
2026*2d543d20SAndroid Build Coastguard Worker 	}
2027*2d543d20SAndroid Build Coastguard Worker 	errno = errsv;
2028*2d543d20SAndroid Build Coastguard Worker }
2029*2d543d20SAndroid Build Coastguard Worker 
2030*2d543d20SAndroid Build Coastguard Worker /* Read the current commit number from the commit number file which
2031*2d543d20SAndroid Build Coastguard Worker  * the handle is pointing, resetting the file pointer afterwards.
2032*2d543d20SAndroid Build Coastguard Worker  * Return it (a non-negative number), or -1 on error. */
semanage_direct_get_serial(semanage_handle_t * sh)2033*2d543d20SAndroid Build Coastguard Worker int semanage_direct_get_serial(semanage_handle_t * sh)
2034*2d543d20SAndroid Build Coastguard Worker {
2035*2d543d20SAndroid Build Coastguard Worker 	char buf[32];
2036*2d543d20SAndroid Build Coastguard Worker 	int fd, commit_number;
2037*2d543d20SAndroid Build Coastguard Worker 	ssize_t amount_read;
2038*2d543d20SAndroid Build Coastguard Worker 	const char *commit_filename;
2039*2d543d20SAndroid Build Coastguard Worker 	memset(buf, 0, sizeof(buf));
2040*2d543d20SAndroid Build Coastguard Worker 
2041*2d543d20SAndroid Build Coastguard Worker 	if (sh->is_in_transaction) {
2042*2d543d20SAndroid Build Coastguard Worker 		commit_filename =
2043*2d543d20SAndroid Build Coastguard Worker 		    semanage_path(SEMANAGE_TMP, SEMANAGE_COMMIT_NUM_FILE);
2044*2d543d20SAndroid Build Coastguard Worker 	} else {
2045*2d543d20SAndroid Build Coastguard Worker 		commit_filename =
2046*2d543d20SAndroid Build Coastguard Worker 		    semanage_path(SEMANAGE_ACTIVE, SEMANAGE_COMMIT_NUM_FILE);
2047*2d543d20SAndroid Build Coastguard Worker 	}
2048*2d543d20SAndroid Build Coastguard Worker 
2049*2d543d20SAndroid Build Coastguard Worker 	if ((fd = open(commit_filename, O_RDONLY)) == -1) {
2050*2d543d20SAndroid Build Coastguard Worker 		if (errno == ENOENT) {
2051*2d543d20SAndroid Build Coastguard Worker 			/* the commit number file does not exist yet,
2052*2d543d20SAndroid Build Coastguard Worker 			 * so assume that the number is 0 */
2053*2d543d20SAndroid Build Coastguard Worker 			errno = 0;
2054*2d543d20SAndroid Build Coastguard Worker 			return 0;
2055*2d543d20SAndroid Build Coastguard Worker 		} else {
2056*2d543d20SAndroid Build Coastguard Worker 			ERR(sh, "Could not open commit number file %s.",
2057*2d543d20SAndroid Build Coastguard Worker 			    commit_filename);
2058*2d543d20SAndroid Build Coastguard Worker 			return -1;
2059*2d543d20SAndroid Build Coastguard Worker 		}
2060*2d543d20SAndroid Build Coastguard Worker 	}
2061*2d543d20SAndroid Build Coastguard Worker 
2062*2d543d20SAndroid Build Coastguard Worker 	amount_read = read(fd, buf, sizeof(buf));
2063*2d543d20SAndroid Build Coastguard Worker 	if (amount_read == -1) {
2064*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Error while reading commit number from %s.",
2065*2d543d20SAndroid Build Coastguard Worker 		    commit_filename);
2066*2d543d20SAndroid Build Coastguard Worker 		commit_number = -1;
2067*2d543d20SAndroid Build Coastguard Worker 	} else if (sscanf(buf, "%d", &commit_number) != 1) {
2068*2d543d20SAndroid Build Coastguard Worker 		/* if nothing was read, assume that the commit number is 0 */
2069*2d543d20SAndroid Build Coastguard Worker 		commit_number = 0;
2070*2d543d20SAndroid Build Coastguard Worker 	} else if (commit_number < 0) {
2071*2d543d20SAndroid Build Coastguard Worker 		/* read file ought never have negative values */
2072*2d543d20SAndroid Build Coastguard Worker 		ERR(sh,
2073*2d543d20SAndroid Build Coastguard Worker 		    "Commit number file %s is corrupted; it should only contain a non-negative integer.",
2074*2d543d20SAndroid Build Coastguard Worker 		    commit_filename);
2075*2d543d20SAndroid Build Coastguard Worker 		commit_number = -1;
2076*2d543d20SAndroid Build Coastguard Worker 	}
2077*2d543d20SAndroid Build Coastguard Worker 
2078*2d543d20SAndroid Build Coastguard Worker 	close(fd);
2079*2d543d20SAndroid Build Coastguard Worker 	return commit_number;
2080*2d543d20SAndroid Build Coastguard Worker }
2081*2d543d20SAndroid Build Coastguard Worker 
2082*2d543d20SAndroid Build Coastguard Worker /* HIGHER LEVEL COMMIT FUNCTIONS */
2083*2d543d20SAndroid Build Coastguard Worker 
semanage_load_files(semanage_handle_t * sh,cil_db_t * cildb,char ** filenames,int numfiles)2084*2d543d20SAndroid Build Coastguard Worker int semanage_load_files(semanage_handle_t * sh, cil_db_t *cildb, char **filenames, int numfiles)
2085*2d543d20SAndroid Build Coastguard Worker {
2086*2d543d20SAndroid Build Coastguard Worker 	int i, retval = 0;
2087*2d543d20SAndroid Build Coastguard Worker 	char *filename;
2088*2d543d20SAndroid Build Coastguard Worker 	struct file_contents contents = {};
2089*2d543d20SAndroid Build Coastguard Worker 
2090*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < numfiles; i++) {
2091*2d543d20SAndroid Build Coastguard Worker 		filename = filenames[i];
2092*2d543d20SAndroid Build Coastguard Worker 
2093*2d543d20SAndroid Build Coastguard Worker 		retval = map_compressed_file(sh, filename, &contents);
2094*2d543d20SAndroid Build Coastguard Worker 		if (retval < 0)
2095*2d543d20SAndroid Build Coastguard Worker 			return -1;
2096*2d543d20SAndroid Build Coastguard Worker 
2097*2d543d20SAndroid Build Coastguard Worker 		retval = cil_add_file(cildb, filename, contents.data, contents.len);
2098*2d543d20SAndroid Build Coastguard Worker 		unmap_compressed_file(&contents);
2099*2d543d20SAndroid Build Coastguard Worker 
2100*2d543d20SAndroid Build Coastguard Worker 		if (retval != SEPOL_OK) {
2101*2d543d20SAndroid Build Coastguard Worker 			ERR(sh, "Error while reading from file %s.", filename);
2102*2d543d20SAndroid Build Coastguard Worker 			return -1;
2103*2d543d20SAndroid Build Coastguard Worker 		}
2104*2d543d20SAndroid Build Coastguard Worker 	}
2105*2d543d20SAndroid Build Coastguard Worker 
2106*2d543d20SAndroid Build Coastguard Worker 	return 0;
2107*2d543d20SAndroid Build Coastguard Worker }
2108*2d543d20SAndroid Build Coastguard Worker 
2109*2d543d20SAndroid Build Coastguard Worker /*
2110*2d543d20SAndroid Build Coastguard Worker  * Expands the policy contained within *base
2111*2d543d20SAndroid Build Coastguard Worker  */
2112*2d543d20SAndroid Build Coastguard Worker 
2113*2d543d20SAndroid Build Coastguard Worker /**
2114*2d543d20SAndroid Build Coastguard Worker  * Read the policy from the sandbox (linked or kernel)
2115*2d543d20SAndroid Build Coastguard Worker  */
semanage_read_policydb(semanage_handle_t * sh,sepol_policydb_t * in,enum semanage_sandbox_defs file)2116*2d543d20SAndroid Build Coastguard Worker int semanage_read_policydb(semanage_handle_t * sh, sepol_policydb_t * in,
2117*2d543d20SAndroid Build Coastguard Worker 			   enum semanage_sandbox_defs file)
2118*2d543d20SAndroid Build Coastguard Worker {
2119*2d543d20SAndroid Build Coastguard Worker 
2120*2d543d20SAndroid Build Coastguard Worker 	int retval = STATUS_ERR;
2121*2d543d20SAndroid Build Coastguard Worker 	const char *kernel_filename = NULL;
2122*2d543d20SAndroid Build Coastguard Worker 	struct sepol_policy_file *pf = NULL;
2123*2d543d20SAndroid Build Coastguard Worker 	FILE *infile = NULL;
2124*2d543d20SAndroid Build Coastguard Worker 
2125*2d543d20SAndroid Build Coastguard Worker 	if ((kernel_filename =
2126*2d543d20SAndroid Build Coastguard Worker 	     semanage_path(SEMANAGE_ACTIVE, file)) == NULL) {
2127*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
2128*2d543d20SAndroid Build Coastguard Worker 	}
2129*2d543d20SAndroid Build Coastguard Worker 	if ((infile = fopen(kernel_filename, "r")) == NULL) {
2130*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Could not open kernel policy %s for reading.",
2131*2d543d20SAndroid Build Coastguard Worker 		    kernel_filename);
2132*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
2133*2d543d20SAndroid Build Coastguard Worker 	}
2134*2d543d20SAndroid Build Coastguard Worker 	__fsetlocking(infile, FSETLOCKING_BYCALLER);
2135*2d543d20SAndroid Build Coastguard Worker 	if (sepol_policy_file_create(&pf)) {
2136*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Out of memory!");
2137*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
2138*2d543d20SAndroid Build Coastguard Worker 	}
2139*2d543d20SAndroid Build Coastguard Worker 	sepol_policy_file_set_fp(pf, infile);
2140*2d543d20SAndroid Build Coastguard Worker 	sepol_policy_file_set_handle(pf, sh->sepolh);
2141*2d543d20SAndroid Build Coastguard Worker 	if (sepol_policydb_read(in, pf) == -1) {
2142*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Error while reading kernel policy from %s.",
2143*2d543d20SAndroid Build Coastguard Worker 		    kernel_filename);
2144*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
2145*2d543d20SAndroid Build Coastguard Worker 	}
2146*2d543d20SAndroid Build Coastguard Worker 	retval = STATUS_SUCCESS;
2147*2d543d20SAndroid Build Coastguard Worker 
2148*2d543d20SAndroid Build Coastguard Worker       cleanup:
2149*2d543d20SAndroid Build Coastguard Worker 	if (infile != NULL) {
2150*2d543d20SAndroid Build Coastguard Worker 		fclose(infile);
2151*2d543d20SAndroid Build Coastguard Worker 	}
2152*2d543d20SAndroid Build Coastguard Worker 	sepol_policy_file_free(pf);
2153*2d543d20SAndroid Build Coastguard Worker 	return retval;
2154*2d543d20SAndroid Build Coastguard Worker }
2155*2d543d20SAndroid Build Coastguard Worker /**
2156*2d543d20SAndroid Build Coastguard Worker  * Writes the policy to the sandbox (linked or kernel)
2157*2d543d20SAndroid Build Coastguard Worker  */
semanage_write_policydb(semanage_handle_t * sh,sepol_policydb_t * out,enum semanage_sandbox_defs file)2158*2d543d20SAndroid Build Coastguard Worker int semanage_write_policydb(semanage_handle_t * sh, sepol_policydb_t * out,
2159*2d543d20SAndroid Build Coastguard Worker 			    enum semanage_sandbox_defs file)
2160*2d543d20SAndroid Build Coastguard Worker {
2161*2d543d20SAndroid Build Coastguard Worker 
2162*2d543d20SAndroid Build Coastguard Worker 	int retval = STATUS_ERR;
2163*2d543d20SAndroid Build Coastguard Worker 	const char *kernel_filename = NULL;
2164*2d543d20SAndroid Build Coastguard Worker 	struct sepol_policy_file *pf = NULL;
2165*2d543d20SAndroid Build Coastguard Worker 	FILE *outfile = NULL;
2166*2d543d20SAndroid Build Coastguard Worker 	mode_t mask = umask(0077);
2167*2d543d20SAndroid Build Coastguard Worker 
2168*2d543d20SAndroid Build Coastguard Worker 	if ((kernel_filename =
2169*2d543d20SAndroid Build Coastguard Worker 	     semanage_path(SEMANAGE_TMP, file)) == NULL) {
2170*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
2171*2d543d20SAndroid Build Coastguard Worker 	}
2172*2d543d20SAndroid Build Coastguard Worker 	if ((outfile = fopen(kernel_filename, "wb")) == NULL) {
2173*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Could not open kernel policy %s for writing.",
2174*2d543d20SAndroid Build Coastguard Worker 		    kernel_filename);
2175*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
2176*2d543d20SAndroid Build Coastguard Worker 	}
2177*2d543d20SAndroid Build Coastguard Worker 	__fsetlocking(outfile, FSETLOCKING_BYCALLER);
2178*2d543d20SAndroid Build Coastguard Worker 	if (sepol_policy_file_create(&pf)) {
2179*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Out of memory!");
2180*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
2181*2d543d20SAndroid Build Coastguard Worker 	}
2182*2d543d20SAndroid Build Coastguard Worker 	sepol_policy_file_set_fp(pf, outfile);
2183*2d543d20SAndroid Build Coastguard Worker 	sepol_policy_file_set_handle(pf, sh->sepolh);
2184*2d543d20SAndroid Build Coastguard Worker 	if (sepol_policydb_write(out, pf) == -1) {
2185*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Error while writing kernel policy to %s.",
2186*2d543d20SAndroid Build Coastguard Worker 		    kernel_filename);
2187*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
2188*2d543d20SAndroid Build Coastguard Worker 	}
2189*2d543d20SAndroid Build Coastguard Worker 	retval = STATUS_SUCCESS;
2190*2d543d20SAndroid Build Coastguard Worker 
2191*2d543d20SAndroid Build Coastguard Worker       cleanup:
2192*2d543d20SAndroid Build Coastguard Worker 	if (outfile != NULL) {
2193*2d543d20SAndroid Build Coastguard Worker 		fclose(outfile);
2194*2d543d20SAndroid Build Coastguard Worker 	}
2195*2d543d20SAndroid Build Coastguard Worker 	umask(mask);
2196*2d543d20SAndroid Build Coastguard Worker 	sepol_policy_file_free(pf);
2197*2d543d20SAndroid Build Coastguard Worker 	return retval;
2198*2d543d20SAndroid Build Coastguard Worker }
2199*2d543d20SAndroid Build Coastguard Worker 
2200*2d543d20SAndroid Build Coastguard Worker /* Execute the module verification programs for each source module.
2201*2d543d20SAndroid Build Coastguard Worker  * Returns 0 if every verifier returned success, -1 on error.
2202*2d543d20SAndroid Build Coastguard Worker  */
semanage_verify_modules(semanage_handle_t * sh,char ** module_filenames,int num_modules)2203*2d543d20SAndroid Build Coastguard Worker int semanage_verify_modules(semanage_handle_t * sh,
2204*2d543d20SAndroid Build Coastguard Worker 			    char **module_filenames, int num_modules)
2205*2d543d20SAndroid Build Coastguard Worker {
2206*2d543d20SAndroid Build Coastguard Worker 	int i, retval;
2207*2d543d20SAndroid Build Coastguard Worker 	semanage_conf_t *conf = sh->conf;
2208*2d543d20SAndroid Build Coastguard Worker 	if (conf->mod_prog == NULL) {
2209*2d543d20SAndroid Build Coastguard Worker 		return 0;
2210*2d543d20SAndroid Build Coastguard Worker 	}
2211*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < num_modules; i++) {
2212*2d543d20SAndroid Build Coastguard Worker 		char *module = module_filenames[i];
2213*2d543d20SAndroid Build Coastguard Worker 		external_prog_t *e;
2214*2d543d20SAndroid Build Coastguard Worker 		for (e = conf->mod_prog; e != NULL; e = e->next) {
2215*2d543d20SAndroid Build Coastguard Worker 			if ((retval =
2216*2d543d20SAndroid Build Coastguard Worker 			     semanage_exec_prog(sh, e, module, "$<")) != 0) {
2217*2d543d20SAndroid Build Coastguard Worker 				return -1;
2218*2d543d20SAndroid Build Coastguard Worker 			}
2219*2d543d20SAndroid Build Coastguard Worker 		}
2220*2d543d20SAndroid Build Coastguard Worker 	}
2221*2d543d20SAndroid Build Coastguard Worker 	return 0;
2222*2d543d20SAndroid Build Coastguard Worker }
2223*2d543d20SAndroid Build Coastguard Worker 
2224*2d543d20SAndroid Build Coastguard Worker /* Execute the linker verification programs for the linked (but not
2225*2d543d20SAndroid Build Coastguard Worker  * expanded) base.  Returns 0 if every verifier returned success, -1
2226*2d543d20SAndroid Build Coastguard Worker  * on error.
2227*2d543d20SAndroid Build Coastguard Worker  */
semanage_verify_linked(semanage_handle_t * sh)2228*2d543d20SAndroid Build Coastguard Worker int semanage_verify_linked(semanage_handle_t * sh)
2229*2d543d20SAndroid Build Coastguard Worker {
2230*2d543d20SAndroid Build Coastguard Worker 	external_prog_t *e;
2231*2d543d20SAndroid Build Coastguard Worker 	semanage_conf_t *conf = sh->conf;
2232*2d543d20SAndroid Build Coastguard Worker 	const char *linked_filename =
2233*2d543d20SAndroid Build Coastguard Worker 	    semanage_path(SEMANAGE_TMP, SEMANAGE_LINKED);
2234*2d543d20SAndroid Build Coastguard Worker 	int retval = -1;
2235*2d543d20SAndroid Build Coastguard Worker 	if (conf->linked_prog == NULL) {
2236*2d543d20SAndroid Build Coastguard Worker 		return 0;
2237*2d543d20SAndroid Build Coastguard Worker 	}
2238*2d543d20SAndroid Build Coastguard Worker 	for (e = conf->linked_prog; e != NULL; e = e->next) {
2239*2d543d20SAndroid Build Coastguard Worker 		if (semanage_exec_prog(sh, e, linked_filename, "$<") != 0) {
2240*2d543d20SAndroid Build Coastguard Worker 			goto cleanup;
2241*2d543d20SAndroid Build Coastguard Worker 		}
2242*2d543d20SAndroid Build Coastguard Worker 	}
2243*2d543d20SAndroid Build Coastguard Worker 	retval = 0;
2244*2d543d20SAndroid Build Coastguard Worker       cleanup:
2245*2d543d20SAndroid Build Coastguard Worker 	return retval;
2246*2d543d20SAndroid Build Coastguard Worker }
2247*2d543d20SAndroid Build Coastguard Worker 
2248*2d543d20SAndroid Build Coastguard Worker /* Execute each of the kernel verification programs.  Returns 0 if
2249*2d543d20SAndroid Build Coastguard Worker  * every verifier returned success, -1 on error.
2250*2d543d20SAndroid Build Coastguard Worker  */
semanage_verify_kernel(semanage_handle_t * sh)2251*2d543d20SAndroid Build Coastguard Worker int semanage_verify_kernel(semanage_handle_t * sh)
2252*2d543d20SAndroid Build Coastguard Worker {
2253*2d543d20SAndroid Build Coastguard Worker 	int retval = -1;
2254*2d543d20SAndroid Build Coastguard Worker 	const char *kernel_filename =
2255*2d543d20SAndroid Build Coastguard Worker 	    semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_KERNEL);
2256*2d543d20SAndroid Build Coastguard Worker 	semanage_conf_t *conf = sh->conf;
2257*2d543d20SAndroid Build Coastguard Worker 	external_prog_t *e;
2258*2d543d20SAndroid Build Coastguard Worker 	if (conf->kernel_prog == NULL) {
2259*2d543d20SAndroid Build Coastguard Worker 		return 0;
2260*2d543d20SAndroid Build Coastguard Worker 	}
2261*2d543d20SAndroid Build Coastguard Worker 	for (e = conf->kernel_prog; e != NULL; e = e->next) {
2262*2d543d20SAndroid Build Coastguard Worker 		if (semanage_exec_prog(sh, e, kernel_filename, "$<") != 0) {
2263*2d543d20SAndroid Build Coastguard Worker 			goto cleanup;
2264*2d543d20SAndroid Build Coastguard Worker 		}
2265*2d543d20SAndroid Build Coastguard Worker 	}
2266*2d543d20SAndroid Build Coastguard Worker 	retval = 0;
2267*2d543d20SAndroid Build Coastguard Worker       cleanup:
2268*2d543d20SAndroid Build Coastguard Worker 	return retval;
2269*2d543d20SAndroid Build Coastguard Worker }
2270*2d543d20SAndroid Build Coastguard Worker 
2271*2d543d20SAndroid Build Coastguard Worker /********************* functions that sort file contexts *********************/
2272*2d543d20SAndroid Build Coastguard Worker 
2273*2d543d20SAndroid Build Coastguard Worker /* Free the given node. */
semanage_fc_node_destroy(semanage_file_context_node_t * x)2274*2d543d20SAndroid Build Coastguard Worker static void semanage_fc_node_destroy(semanage_file_context_node_t * x)
2275*2d543d20SAndroid Build Coastguard Worker {
2276*2d543d20SAndroid Build Coastguard Worker 	free(x->path);
2277*2d543d20SAndroid Build Coastguard Worker 	free(x->file_type);
2278*2d543d20SAndroid Build Coastguard Worker 	free(x->context);
2279*2d543d20SAndroid Build Coastguard Worker 	free(x);
2280*2d543d20SAndroid Build Coastguard Worker }
2281*2d543d20SAndroid Build Coastguard Worker 
2282*2d543d20SAndroid Build Coastguard Worker /* Free the linked list of nodes starting at the given node. */
semanage_fc_node_list_destroy(semanage_file_context_node_t * x)2283*2d543d20SAndroid Build Coastguard Worker static void semanage_fc_node_list_destroy(semanage_file_context_node_t * x)
2284*2d543d20SAndroid Build Coastguard Worker {
2285*2d543d20SAndroid Build Coastguard Worker 	semanage_file_context_node_t *temp;
2286*2d543d20SAndroid Build Coastguard Worker 
2287*2d543d20SAndroid Build Coastguard Worker 	while (x) {
2288*2d543d20SAndroid Build Coastguard Worker 		temp = x;
2289*2d543d20SAndroid Build Coastguard Worker 		x = x->next;
2290*2d543d20SAndroid Build Coastguard Worker 		semanage_fc_node_destroy(temp);
2291*2d543d20SAndroid Build Coastguard Worker 	}
2292*2d543d20SAndroid Build Coastguard Worker }
2293*2d543d20SAndroid Build Coastguard Worker 
2294*2d543d20SAndroid Build Coastguard Worker /* Free the linked list of buckets (and their node lists)
2295*2d543d20SAndroid Build Coastguard Worker  * starting at the given bucket. */
semanage_fc_bucket_list_destroy(semanage_file_context_bucket_t * x)2296*2d543d20SAndroid Build Coastguard Worker static void semanage_fc_bucket_list_destroy(semanage_file_context_bucket_t * x)
2297*2d543d20SAndroid Build Coastguard Worker {
2298*2d543d20SAndroid Build Coastguard Worker 	semanage_file_context_bucket_t *temp;
2299*2d543d20SAndroid Build Coastguard Worker 
2300*2d543d20SAndroid Build Coastguard Worker 	while (x) {
2301*2d543d20SAndroid Build Coastguard Worker 		temp = x;
2302*2d543d20SAndroid Build Coastguard Worker 		x = x->next;
2303*2d543d20SAndroid Build Coastguard Worker 		semanage_fc_node_list_destroy(temp->data);
2304*2d543d20SAndroid Build Coastguard Worker 		free(temp);
2305*2d543d20SAndroid Build Coastguard Worker 	}
2306*2d543d20SAndroid Build Coastguard Worker }
2307*2d543d20SAndroid Build Coastguard Worker 
2308*2d543d20SAndroid Build Coastguard Worker /* Compares two file contexts' regular expressions and returns:
2309*2d543d20SAndroid Build Coastguard Worker  *    -1 if a is less specific than b
2310*2d543d20SAndroid Build Coastguard Worker  *     0 if a and be are equally specific
2311*2d543d20SAndroid Build Coastguard Worker  *     1 if a is more specific than b
2312*2d543d20SAndroid Build Coastguard Worker  * The comparison is based on the following heuristics,
2313*2d543d20SAndroid Build Coastguard Worker  *  in order from most important to least important, given a and b:
2314*2d543d20SAndroid Build Coastguard Worker  *     If a is a regular expression and b is not,
2315*2d543d20SAndroid Build Coastguard Worker  *      -> a is less specific than b.
2316*2d543d20SAndroid Build Coastguard Worker  *     If a's stem length is shorter than b's stem length,
2317*2d543d20SAndroid Build Coastguard Worker  *      -> a is less specific than b.
2318*2d543d20SAndroid Build Coastguard Worker  *     If a's string length is shorter than b's string length,
2319*2d543d20SAndroid Build Coastguard Worker  *      -> a is less specific than b.
2320*2d543d20SAndroid Build Coastguard Worker  *     If a does not have a specified type and b does not,
2321*2d543d20SAndroid Build Coastguard Worker  *      -> a is less specific than b.
2322*2d543d20SAndroid Build Coastguard Worker  * FIXME: These heuristics are imperfect, but good enough for
2323*2d543d20SAndroid Build Coastguard Worker  * now.  A proper comparison would determine which (if either)
2324*2d543d20SAndroid Build Coastguard Worker  * regular expression is a subset of the other.
2325*2d543d20SAndroid Build Coastguard Worker  */
semanage_fc_compare(semanage_file_context_node_t * a,semanage_file_context_node_t * b)2326*2d543d20SAndroid Build Coastguard Worker static int semanage_fc_compare(semanage_file_context_node_t * a,
2327*2d543d20SAndroid Build Coastguard Worker 			       semanage_file_context_node_t * b)
2328*2d543d20SAndroid Build Coastguard Worker {
2329*2d543d20SAndroid Build Coastguard Worker 	int a_has_meta = (a->meta >= 0);
2330*2d543d20SAndroid Build Coastguard Worker 	int b_has_meta = (b->meta >= 0);
2331*2d543d20SAndroid Build Coastguard Worker 
2332*2d543d20SAndroid Build Coastguard Worker 	/* Check to see if either a or b are regexes
2333*2d543d20SAndroid Build Coastguard Worker 	 *  and the other isn't. */
2334*2d543d20SAndroid Build Coastguard Worker 	if (a_has_meta && !b_has_meta)
2335*2d543d20SAndroid Build Coastguard Worker 		return -1;
2336*2d543d20SAndroid Build Coastguard Worker 	if (b_has_meta && !a_has_meta)
2337*2d543d20SAndroid Build Coastguard Worker 		return 1;
2338*2d543d20SAndroid Build Coastguard Worker 
2339*2d543d20SAndroid Build Coastguard Worker 	/* Check to see if either a or b have a shorter stem
2340*2d543d20SAndroid Build Coastguard Worker 	 *  length than the other. */
2341*2d543d20SAndroid Build Coastguard Worker 	if (a->meta < b->meta)
2342*2d543d20SAndroid Build Coastguard Worker 		return -1;
2343*2d543d20SAndroid Build Coastguard Worker 	if (b->meta < a->meta)
2344*2d543d20SAndroid Build Coastguard Worker 		return 1;
2345*2d543d20SAndroid Build Coastguard Worker 
2346*2d543d20SAndroid Build Coastguard Worker 	/* Check to see if either a or b have a shorter string
2347*2d543d20SAndroid Build Coastguard Worker 	 *  length than the other. */
2348*2d543d20SAndroid Build Coastguard Worker 	if (a->effective_len < b->effective_len)
2349*2d543d20SAndroid Build Coastguard Worker 		return -1;
2350*2d543d20SAndroid Build Coastguard Worker 	if (b->effective_len < a->effective_len)
2351*2d543d20SAndroid Build Coastguard Worker 		return 1;
2352*2d543d20SAndroid Build Coastguard Worker 
2353*2d543d20SAndroid Build Coastguard Worker 	/* Check to see if either a or b has a specified type
2354*2d543d20SAndroid Build Coastguard Worker 	 *  and the other doesn't. */
2355*2d543d20SAndroid Build Coastguard Worker 	if (!a->file_type && b->file_type)
2356*2d543d20SAndroid Build Coastguard Worker 		return -1;
2357*2d543d20SAndroid Build Coastguard Worker 	if (!b->file_type && a->file_type)
2358*2d543d20SAndroid Build Coastguard Worker 		return 1;
2359*2d543d20SAndroid Build Coastguard Worker 
2360*2d543d20SAndroid Build Coastguard Worker 	/* If none of the above conditions were satisfied,
2361*2d543d20SAndroid Build Coastguard Worker 	 * then a and b are equally specific. */
2362*2d543d20SAndroid Build Coastguard Worker 	return 0;
2363*2d543d20SAndroid Build Coastguard Worker }
2364*2d543d20SAndroid Build Coastguard Worker 
2365*2d543d20SAndroid Build Coastguard Worker /* Merges two sorted file context linked lists into a single sorted one.
2366*2d543d20SAndroid Build Coastguard Worker  * The left list is assumed to represent nodes that came first in the original ordering.
2367*2d543d20SAndroid Build Coastguard Worker  * The final sorted list is returned.
2368*2d543d20SAndroid Build Coastguard Worker  */
2369*2d543d20SAndroid Build Coastguard Worker static semanage_file_context_node_t
semanage_fc_merge(semanage_file_context_node_t * left,semanage_file_context_node_t * right)2370*2d543d20SAndroid Build Coastguard Worker     * semanage_fc_merge(semanage_file_context_node_t * left,
2371*2d543d20SAndroid Build Coastguard Worker 			semanage_file_context_node_t * right)
2372*2d543d20SAndroid Build Coastguard Worker {
2373*2d543d20SAndroid Build Coastguard Worker 	semanage_file_context_node_t *head;
2374*2d543d20SAndroid Build Coastguard Worker 	semanage_file_context_node_t *current;
2375*2d543d20SAndroid Build Coastguard Worker 	semanage_file_context_node_t *tail;
2376*2d543d20SAndroid Build Coastguard Worker 
2377*2d543d20SAndroid Build Coastguard Worker 	if (!left)
2378*2d543d20SAndroid Build Coastguard Worker 		return right;
2379*2d543d20SAndroid Build Coastguard Worker 
2380*2d543d20SAndroid Build Coastguard Worker 	if (!right)
2381*2d543d20SAndroid Build Coastguard Worker 		return left;
2382*2d543d20SAndroid Build Coastguard Worker 
2383*2d543d20SAndroid Build Coastguard Worker 	if (semanage_fc_compare(left, right) == 1) {
2384*2d543d20SAndroid Build Coastguard Worker 		head = tail = right;
2385*2d543d20SAndroid Build Coastguard Worker 		right = right->next;
2386*2d543d20SAndroid Build Coastguard Worker 	} else {
2387*2d543d20SAndroid Build Coastguard Worker 		head = tail = left;
2388*2d543d20SAndroid Build Coastguard Worker 		left = left->next;
2389*2d543d20SAndroid Build Coastguard Worker 	}
2390*2d543d20SAndroid Build Coastguard Worker 
2391*2d543d20SAndroid Build Coastguard Worker 	while (left && right) {
2392*2d543d20SAndroid Build Coastguard Worker 		/* if left was more specific than right,
2393*2d543d20SAndroid Build Coastguard Worker 		 * insert right before left.  Otherwise leave order alone. */
2394*2d543d20SAndroid Build Coastguard Worker 		if (semanage_fc_compare(left, right) == 1) {
2395*2d543d20SAndroid Build Coastguard Worker 			current = right;
2396*2d543d20SAndroid Build Coastguard Worker 			right = right->next;
2397*2d543d20SAndroid Build Coastguard Worker 		} else {
2398*2d543d20SAndroid Build Coastguard Worker 			current = left;
2399*2d543d20SAndroid Build Coastguard Worker 			left = left->next;
2400*2d543d20SAndroid Build Coastguard Worker 		}
2401*2d543d20SAndroid Build Coastguard Worker 
2402*2d543d20SAndroid Build Coastguard Worker 		tail = tail->next = current;
2403*2d543d20SAndroid Build Coastguard Worker 	}
2404*2d543d20SAndroid Build Coastguard Worker 
2405*2d543d20SAndroid Build Coastguard Worker 	tail->next = (left != NULL) ? left : right;
2406*2d543d20SAndroid Build Coastguard Worker 
2407*2d543d20SAndroid Build Coastguard Worker 	return head;
2408*2d543d20SAndroid Build Coastguard Worker }
2409*2d543d20SAndroid Build Coastguard Worker 
2410*2d543d20SAndroid Build Coastguard Worker /* Sorts file contexts from least specific to most specific.
2411*2d543d20SAndroid Build Coastguard Worker  * A bucket linked list is passed in.  Upon completion,
2412*2d543d20SAndroid Build Coastguard Worker  * there is only one bucket (pointed to by "main") that
2413*2d543d20SAndroid Build Coastguard Worker  * contains a linked list of all the file contexts in sorted order.
2414*2d543d20SAndroid Build Coastguard Worker  * Explanation of the algorithm:
2415*2d543d20SAndroid Build Coastguard Worker  *  This is a stable implementation of an iterative merge sort.
2416*2d543d20SAndroid Build Coastguard Worker  *  Each bucket initially has a linked list of file contexts
2417*2d543d20SAndroid Build Coastguard Worker  *   that are 1 node long.
2418*2d543d20SAndroid Build Coastguard Worker  *  Each pass, buckets (and the nodes they contain) are merged
2419*2d543d20SAndroid Build Coastguard Worker  *   two at time.
2420*2d543d20SAndroid Build Coastguard Worker  *  Buckets are merged until there is only one bucket left,
2421*2d543d20SAndroid Build Coastguard Worker  *   containing the list of file contexts, sorted.
2422*2d543d20SAndroid Build Coastguard Worker  */
semanage_fc_merge_sort(semanage_file_context_bucket_t * main)2423*2d543d20SAndroid Build Coastguard Worker static void semanage_fc_merge_sort(semanage_file_context_bucket_t * main)
2424*2d543d20SAndroid Build Coastguard Worker {
2425*2d543d20SAndroid Build Coastguard Worker 	semanage_file_context_bucket_t *current;
2426*2d543d20SAndroid Build Coastguard Worker 	semanage_file_context_bucket_t *temp;
2427*2d543d20SAndroid Build Coastguard Worker 
2428*2d543d20SAndroid Build Coastguard Worker 	/* Loop until "main" is the only bucket left.
2429*2d543d20SAndroid Build Coastguard Worker 	 * When we stop "main" contains the sorted list. */
2430*2d543d20SAndroid Build Coastguard Worker 	while (main->next) {
2431*2d543d20SAndroid Build Coastguard Worker 		current = main;
2432*2d543d20SAndroid Build Coastguard Worker 
2433*2d543d20SAndroid Build Coastguard Worker 		/* Merge buckets two-by-two.
2434*2d543d20SAndroid Build Coastguard Worker 		 * If there is an odd number of buckets, the last
2435*2d543d20SAndroid Build Coastguard Worker 		 * bucket will be left alone, which corresponds
2436*2d543d20SAndroid Build Coastguard Worker 		 * to the operation of merging it with an empty bucket. */
2437*2d543d20SAndroid Build Coastguard Worker 		while (current) {
2438*2d543d20SAndroid Build Coastguard Worker 			if (current->next) {
2439*2d543d20SAndroid Build Coastguard Worker 				current->data =
2440*2d543d20SAndroid Build Coastguard Worker 				    semanage_fc_merge(current->data,
2441*2d543d20SAndroid Build Coastguard Worker 						      current->next->data);
2442*2d543d20SAndroid Build Coastguard Worker 				temp = current->next;
2443*2d543d20SAndroid Build Coastguard Worker 				current->next = current->next->next;
2444*2d543d20SAndroid Build Coastguard Worker 
2445*2d543d20SAndroid Build Coastguard Worker 				/* Free the (now empty) second bucket.
2446*2d543d20SAndroid Build Coastguard Worker 				 * (This does not touch the node list
2447*2d543d20SAndroid Build Coastguard Worker 				 * in the bucket because it has been
2448*2d543d20SAndroid Build Coastguard Worker 				 * shifted over to the first bucket. */
2449*2d543d20SAndroid Build Coastguard Worker 				free(temp);
2450*2d543d20SAndroid Build Coastguard Worker 			}
2451*2d543d20SAndroid Build Coastguard Worker 			current = current->next;
2452*2d543d20SAndroid Build Coastguard Worker 		}
2453*2d543d20SAndroid Build Coastguard Worker 	}
2454*2d543d20SAndroid Build Coastguard Worker }
2455*2d543d20SAndroid Build Coastguard Worker 
2456*2d543d20SAndroid Build Coastguard Worker /* Compute the location of the first regular expression
2457*2d543d20SAndroid Build Coastguard Worker  *   meta character in the path of the given node, if it exists.
2458*2d543d20SAndroid Build Coastguard Worker  * On return:
2459*2d543d20SAndroid Build Coastguard Worker  *     fc_node->meta = position of meta character, if it exists
2460*2d543d20SAndroid Build Coastguard Worker  *			(-1 corresponds to no character)
2461*2d543d20SAndroid Build Coastguard Worker  */
semanage_fc_find_meta(semanage_file_context_node_t * fc_node)2462*2d543d20SAndroid Build Coastguard Worker static void semanage_fc_find_meta(semanage_file_context_node_t * fc_node)
2463*2d543d20SAndroid Build Coastguard Worker {
2464*2d543d20SAndroid Build Coastguard Worker 	int c = 0;
2465*2d543d20SAndroid Build Coastguard Worker 	int escape_chars = 0;
2466*2d543d20SAndroid Build Coastguard Worker 
2467*2d543d20SAndroid Build Coastguard Worker 	fc_node->meta = -1;
2468*2d543d20SAndroid Build Coastguard Worker 
2469*2d543d20SAndroid Build Coastguard Worker 	/* Note: this while loop has been adapted from
2470*2d543d20SAndroid Build Coastguard Worker 	 *  spec_hasMetaChars in matchpathcon.c from
2471*2d543d20SAndroid Build Coastguard Worker 	 *  libselinux-1.22. */
2472*2d543d20SAndroid Build Coastguard Worker 	while (fc_node->path[c] != '\0') {
2473*2d543d20SAndroid Build Coastguard Worker 		switch (fc_node->path[c]) {
2474*2d543d20SAndroid Build Coastguard Worker 		case '.':
2475*2d543d20SAndroid Build Coastguard Worker 		case '^':
2476*2d543d20SAndroid Build Coastguard Worker 		case '$':
2477*2d543d20SAndroid Build Coastguard Worker 		case '?':
2478*2d543d20SAndroid Build Coastguard Worker 		case '*':
2479*2d543d20SAndroid Build Coastguard Worker 		case '+':
2480*2d543d20SAndroid Build Coastguard Worker 		case '|':
2481*2d543d20SAndroid Build Coastguard Worker 		case '[':
2482*2d543d20SAndroid Build Coastguard Worker 		case '(':
2483*2d543d20SAndroid Build Coastguard Worker 		case '{':
2484*2d543d20SAndroid Build Coastguard Worker 			fc_node->meta = c - escape_chars;
2485*2d543d20SAndroid Build Coastguard Worker 			return;
2486*2d543d20SAndroid Build Coastguard Worker 		case '\\':
2487*2d543d20SAndroid Build Coastguard Worker 			/* If an escape character is found,
2488*2d543d20SAndroid Build Coastguard Worker 			 *  skip the next character. */
2489*2d543d20SAndroid Build Coastguard Worker 			c++;
2490*2d543d20SAndroid Build Coastguard Worker 			escape_chars++;
2491*2d543d20SAndroid Build Coastguard Worker 			break;
2492*2d543d20SAndroid Build Coastguard Worker 		}
2493*2d543d20SAndroid Build Coastguard Worker 
2494*2d543d20SAndroid Build Coastguard Worker 		c++;
2495*2d543d20SAndroid Build Coastguard Worker 	}
2496*2d543d20SAndroid Build Coastguard Worker }
2497*2d543d20SAndroid Build Coastguard Worker 
2498*2d543d20SAndroid Build Coastguard Worker /* Replicates strchr, but limits search to buf_len characters. */
semanage_strnchr(const char * buf,size_t buf_len,char c)2499*2d543d20SAndroid Build Coastguard Worker static char *semanage_strnchr(const char *buf, size_t buf_len, char c)
2500*2d543d20SAndroid Build Coastguard Worker {
2501*2d543d20SAndroid Build Coastguard Worker 	size_t idx = 0;
2502*2d543d20SAndroid Build Coastguard Worker 
2503*2d543d20SAndroid Build Coastguard Worker 	if (buf == NULL)
2504*2d543d20SAndroid Build Coastguard Worker 		return NULL;
2505*2d543d20SAndroid Build Coastguard Worker 	if (buf_len <= 0)
2506*2d543d20SAndroid Build Coastguard Worker 		return NULL;
2507*2d543d20SAndroid Build Coastguard Worker 
2508*2d543d20SAndroid Build Coastguard Worker 	while (idx < buf_len) {
2509*2d543d20SAndroid Build Coastguard Worker 		if (buf[idx] == c)
2510*2d543d20SAndroid Build Coastguard Worker 			return (char *)buf + idx;
2511*2d543d20SAndroid Build Coastguard Worker 		idx++;
2512*2d543d20SAndroid Build Coastguard Worker 	}
2513*2d543d20SAndroid Build Coastguard Worker 
2514*2d543d20SAndroid Build Coastguard Worker 	return NULL;
2515*2d543d20SAndroid Build Coastguard Worker }
2516*2d543d20SAndroid Build Coastguard Worker 
2517*2d543d20SAndroid Build Coastguard Worker /* Returns a pointer to the end of line character in the given buffer.
2518*2d543d20SAndroid Build Coastguard Worker  * Used in the context of a file context char buffer that we will be
2519*2d543d20SAndroid Build Coastguard Worker  * parsing and sorting.
2520*2d543d20SAndroid Build Coastguard Worker  */
semanage_get_line_end(const char * buf,size_t buf_len)2521*2d543d20SAndroid Build Coastguard Worker static char *semanage_get_line_end(const char *buf, size_t buf_len)
2522*2d543d20SAndroid Build Coastguard Worker {
2523*2d543d20SAndroid Build Coastguard Worker 	char *line_end = NULL;
2524*2d543d20SAndroid Build Coastguard Worker 
2525*2d543d20SAndroid Build Coastguard Worker 	if (buf == NULL)
2526*2d543d20SAndroid Build Coastguard Worker 		return NULL;
2527*2d543d20SAndroid Build Coastguard Worker 	if (buf_len <= 0)
2528*2d543d20SAndroid Build Coastguard Worker 		return NULL;
2529*2d543d20SAndroid Build Coastguard Worker 
2530*2d543d20SAndroid Build Coastguard Worker 	line_end = semanage_strnchr(buf, buf_len, '\n');
2531*2d543d20SAndroid Build Coastguard Worker 	if (!line_end)
2532*2d543d20SAndroid Build Coastguard Worker 		line_end = semanage_strnchr(buf, buf_len, '\r');
2533*2d543d20SAndroid Build Coastguard Worker 	if (!line_end)
2534*2d543d20SAndroid Build Coastguard Worker 		line_end = semanage_strnchr(buf, buf_len, EOF);
2535*2d543d20SAndroid Build Coastguard Worker 
2536*2d543d20SAndroid Build Coastguard Worker 	return line_end;
2537*2d543d20SAndroid Build Coastguard Worker }
2538*2d543d20SAndroid Build Coastguard Worker 
2539*2d543d20SAndroid Build Coastguard Worker /*  Entry function for sorting a set of file context lines.
2540*2d543d20SAndroid Build Coastguard Worker  *  Returns 0 on success, -1 on failure.
2541*2d543d20SAndroid Build Coastguard Worker  *  Allocates a buffer pointed to by sorted_buf that contains the sorted lines.
2542*2d543d20SAndroid Build Coastguard Worker  *  sorted_buf_len is set to the size of this buffer.
2543*2d543d20SAndroid Build Coastguard Worker  *  This buffer is guaranteed to have a final \0 character.
2544*2d543d20SAndroid Build Coastguard Worker  *  This buffer must be released by the caller.
2545*2d543d20SAndroid Build Coastguard Worker  */
semanage_fc_sort(semanage_handle_t * sh,const char * buf,size_t buf_len,char ** sorted_buf,size_t * sorted_buf_len)2546*2d543d20SAndroid Build Coastguard Worker int semanage_fc_sort(semanage_handle_t * sh, const char *buf, size_t buf_len,
2547*2d543d20SAndroid Build Coastguard Worker 		     char **sorted_buf, size_t * sorted_buf_len)
2548*2d543d20SAndroid Build Coastguard Worker {
2549*2d543d20SAndroid Build Coastguard Worker 	size_t start, finish, regex_len, type_len, context_len;
2550*2d543d20SAndroid Build Coastguard Worker 	size_t line_len, buf_remainder, i;
2551*2d543d20SAndroid Build Coastguard Worker 	ssize_t sanity_check;
2552*2d543d20SAndroid Build Coastguard Worker 	const char *line_buf, *line_end;
2553*2d543d20SAndroid Build Coastguard Worker 	char *sorted_buf_pos;
2554*2d543d20SAndroid Build Coastguard Worker 	int escape_chars, just_saw_escape;
2555*2d543d20SAndroid Build Coastguard Worker 
2556*2d543d20SAndroid Build Coastguard Worker 	semanage_file_context_node_t *temp;
2557*2d543d20SAndroid Build Coastguard Worker 	semanage_file_context_node_t *head;
2558*2d543d20SAndroid Build Coastguard Worker 	semanage_file_context_node_t *current;
2559*2d543d20SAndroid Build Coastguard Worker 	semanage_file_context_bucket_t *main;
2560*2d543d20SAndroid Build Coastguard Worker 	semanage_file_context_bucket_t *bcurrent;
2561*2d543d20SAndroid Build Coastguard Worker 
2562*2d543d20SAndroid Build Coastguard Worker 	i = 0;
2563*2d543d20SAndroid Build Coastguard Worker 
2564*2d543d20SAndroid Build Coastguard Worker 	if (sh == NULL) {
2565*2d543d20SAndroid Build Coastguard Worker 		return -1;
2566*2d543d20SAndroid Build Coastguard Worker 	}
2567*2d543d20SAndroid Build Coastguard Worker 	if (buf == NULL) {
2568*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Received NULL buffer.");
2569*2d543d20SAndroid Build Coastguard Worker 		return -1;
2570*2d543d20SAndroid Build Coastguard Worker 	}
2571*2d543d20SAndroid Build Coastguard Worker 	if (buf_len <= 0) {
2572*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Received buffer of length 0.");
2573*2d543d20SAndroid Build Coastguard Worker 		return -1;
2574*2d543d20SAndroid Build Coastguard Worker 	}
2575*2d543d20SAndroid Build Coastguard Worker 
2576*2d543d20SAndroid Build Coastguard Worker 	/* Initialize the head of the linked list
2577*2d543d20SAndroid Build Coastguard Worker 	 * that will contain a node for each file context line. */
2578*2d543d20SAndroid Build Coastguard Worker 	head = current =
2579*2d543d20SAndroid Build Coastguard Worker 	    (semanage_file_context_node_t *) calloc(1,
2580*2d543d20SAndroid Build Coastguard Worker 						    sizeof
2581*2d543d20SAndroid Build Coastguard Worker 						    (semanage_file_context_node_t));
2582*2d543d20SAndroid Build Coastguard Worker 	if (!head) {
2583*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Failure allocating memory.");
2584*2d543d20SAndroid Build Coastguard Worker 		return -1;
2585*2d543d20SAndroid Build Coastguard Worker 	}
2586*2d543d20SAndroid Build Coastguard Worker 
2587*2d543d20SAndroid Build Coastguard Worker 	/* Parse the char buffer into a semanage_file_context_node_t linked list. */
2588*2d543d20SAndroid Build Coastguard Worker 	line_buf = buf;
2589*2d543d20SAndroid Build Coastguard Worker 	buf_remainder = buf_len;
2590*2d543d20SAndroid Build Coastguard Worker 	while ((line_end = semanage_get_line_end(line_buf, buf_remainder))) {
2591*2d543d20SAndroid Build Coastguard Worker 		line_len = line_end - line_buf + 1;
2592*2d543d20SAndroid Build Coastguard Worker 		sanity_check = buf_remainder - line_len;
2593*2d543d20SAndroid Build Coastguard Worker 		buf_remainder = buf_remainder - line_len;
2594*2d543d20SAndroid Build Coastguard Worker 
2595*2d543d20SAndroid Build Coastguard Worker 		if (sanity_check < 0) {
2596*2d543d20SAndroid Build Coastguard Worker 			ERR(sh, "Failure parsing file context buffer.");
2597*2d543d20SAndroid Build Coastguard Worker 			semanage_fc_node_list_destroy(head);
2598*2d543d20SAndroid Build Coastguard Worker 			return -1;
2599*2d543d20SAndroid Build Coastguard Worker 		}
2600*2d543d20SAndroid Build Coastguard Worker 
2601*2d543d20SAndroid Build Coastguard Worker 		if (line_len == 0 || line_len == 1) {
2602*2d543d20SAndroid Build Coastguard Worker 			line_buf = line_end + 1;
2603*2d543d20SAndroid Build Coastguard Worker 			continue;
2604*2d543d20SAndroid Build Coastguard Worker 		}
2605*2d543d20SAndroid Build Coastguard Worker 
2606*2d543d20SAndroid Build Coastguard Worker 		/* Skip the whitespace at the front of the line. */
2607*2d543d20SAndroid Build Coastguard Worker 		for (i = 0; i < line_len; i++) {
2608*2d543d20SAndroid Build Coastguard Worker 			if (!isspace(line_buf[i]))
2609*2d543d20SAndroid Build Coastguard Worker 				break;
2610*2d543d20SAndroid Build Coastguard Worker 		}
2611*2d543d20SAndroid Build Coastguard Worker 
2612*2d543d20SAndroid Build Coastguard Worker 		/* Check for a blank line. */
2613*2d543d20SAndroid Build Coastguard Worker 		if (i >= line_len) {
2614*2d543d20SAndroid Build Coastguard Worker 			line_buf = line_end + 1;
2615*2d543d20SAndroid Build Coastguard Worker 			continue;
2616*2d543d20SAndroid Build Coastguard Worker 		}
2617*2d543d20SAndroid Build Coastguard Worker 
2618*2d543d20SAndroid Build Coastguard Worker 		/* Check if the line is a comment. */
2619*2d543d20SAndroid Build Coastguard Worker 		if (line_buf[i] == '#') {
2620*2d543d20SAndroid Build Coastguard Worker 			line_buf = line_end + 1;
2621*2d543d20SAndroid Build Coastguard Worker 			continue;
2622*2d543d20SAndroid Build Coastguard Worker 		}
2623*2d543d20SAndroid Build Coastguard Worker 
2624*2d543d20SAndroid Build Coastguard Worker 		/* Allocate a new node. */
2625*2d543d20SAndroid Build Coastguard Worker 		temp =
2626*2d543d20SAndroid Build Coastguard Worker 		    (semanage_file_context_node_t *) calloc(1,
2627*2d543d20SAndroid Build Coastguard Worker 							    sizeof
2628*2d543d20SAndroid Build Coastguard Worker 							    (semanage_file_context_node_t));
2629*2d543d20SAndroid Build Coastguard Worker 		if (!temp) {
2630*2d543d20SAndroid Build Coastguard Worker 			ERR(sh, "Failure allocating memory.");
2631*2d543d20SAndroid Build Coastguard Worker 			semanage_fc_node_list_destroy(head);
2632*2d543d20SAndroid Build Coastguard Worker 			return -1;
2633*2d543d20SAndroid Build Coastguard Worker 		}
2634*2d543d20SAndroid Build Coastguard Worker 		temp->next = NULL;
2635*2d543d20SAndroid Build Coastguard Worker 
2636*2d543d20SAndroid Build Coastguard Worker 		/* Extract the regular expression from the line. */
2637*2d543d20SAndroid Build Coastguard Worker 		escape_chars = 0;
2638*2d543d20SAndroid Build Coastguard Worker 		just_saw_escape = 0;
2639*2d543d20SAndroid Build Coastguard Worker 		start = i;
2640*2d543d20SAndroid Build Coastguard Worker 		while (i < line_len && (!isspace(line_buf[i]))) {
2641*2d543d20SAndroid Build Coastguard Worker 			if (line_buf[i] == '\\') {
2642*2d543d20SAndroid Build Coastguard Worker 				if (!just_saw_escape) {
2643*2d543d20SAndroid Build Coastguard Worker 					escape_chars++;
2644*2d543d20SAndroid Build Coastguard Worker 					just_saw_escape = 1;
2645*2d543d20SAndroid Build Coastguard Worker 				} else {
2646*2d543d20SAndroid Build Coastguard Worker 					/* We're looking at an escaped
2647*2d543d20SAndroid Build Coastguard Worker 					   escape. Reset our flag. */
2648*2d543d20SAndroid Build Coastguard Worker 					just_saw_escape = 0;
2649*2d543d20SAndroid Build Coastguard Worker 				}
2650*2d543d20SAndroid Build Coastguard Worker 			} else {
2651*2d543d20SAndroid Build Coastguard Worker 				just_saw_escape = 0;
2652*2d543d20SAndroid Build Coastguard Worker 			}
2653*2d543d20SAndroid Build Coastguard Worker 			i++;
2654*2d543d20SAndroid Build Coastguard Worker 		}
2655*2d543d20SAndroid Build Coastguard Worker 		finish = i;
2656*2d543d20SAndroid Build Coastguard Worker 		regex_len = finish - start;
2657*2d543d20SAndroid Build Coastguard Worker 
2658*2d543d20SAndroid Build Coastguard Worker 		if (regex_len == 0) {
2659*2d543d20SAndroid Build Coastguard Worker 			ERR(sh,
2660*2d543d20SAndroid Build Coastguard Worker 			    "WARNING: semanage_fc_sort: Regex of length 0.");
2661*2d543d20SAndroid Build Coastguard Worker 			semanage_fc_node_destroy(temp);
2662*2d543d20SAndroid Build Coastguard Worker 			line_buf = line_end + 1;
2663*2d543d20SAndroid Build Coastguard Worker 			continue;
2664*2d543d20SAndroid Build Coastguard Worker 		}
2665*2d543d20SAndroid Build Coastguard Worker 
2666*2d543d20SAndroid Build Coastguard Worker 		temp->path = (char *)strndup(&line_buf[start], regex_len);
2667*2d543d20SAndroid Build Coastguard Worker 		if (!temp->path) {
2668*2d543d20SAndroid Build Coastguard Worker 			ERR(sh, "Failure allocating memory.");
2669*2d543d20SAndroid Build Coastguard Worker 			semanage_fc_node_destroy(temp);
2670*2d543d20SAndroid Build Coastguard Worker 			semanage_fc_node_list_destroy(head);
2671*2d543d20SAndroid Build Coastguard Worker 			return -1;
2672*2d543d20SAndroid Build Coastguard Worker 		}
2673*2d543d20SAndroid Build Coastguard Worker 
2674*2d543d20SAndroid Build Coastguard Worker 		/* Skip the whitespace after the regular expression. */
2675*2d543d20SAndroid Build Coastguard Worker 		for (; i < line_len; i++) {
2676*2d543d20SAndroid Build Coastguard Worker 			if (!isspace(line_buf[i]))
2677*2d543d20SAndroid Build Coastguard Worker 				break;
2678*2d543d20SAndroid Build Coastguard Worker 		}
2679*2d543d20SAndroid Build Coastguard Worker 		if (i == line_len) {
2680*2d543d20SAndroid Build Coastguard Worker 			ERR(sh,
2681*2d543d20SAndroid Build Coastguard Worker 			    "WARNING: semanage_fc_sort: Incomplete context. %s", temp->path);
2682*2d543d20SAndroid Build Coastguard Worker 			semanage_fc_node_destroy(temp);
2683*2d543d20SAndroid Build Coastguard Worker 			line_buf = line_end + 1;
2684*2d543d20SAndroid Build Coastguard Worker 			continue;
2685*2d543d20SAndroid Build Coastguard Worker 		}
2686*2d543d20SAndroid Build Coastguard Worker 
2687*2d543d20SAndroid Build Coastguard Worker 		/* Extract the inode type from the line (if it exists). */
2688*2d543d20SAndroid Build Coastguard Worker 		if (line_buf[i] == '-') {
2689*2d543d20SAndroid Build Coastguard Worker 			type_len = 2;	/* defined as '--', '-d', '-f', etc. */
2690*2d543d20SAndroid Build Coastguard Worker 
2691*2d543d20SAndroid Build Coastguard Worker 			if (i + type_len >= line_len) {
2692*2d543d20SAndroid Build Coastguard Worker 				ERR(sh,
2693*2d543d20SAndroid Build Coastguard Worker 				    "WARNING: semanage_fc_sort: Incomplete context. %s", temp->path);
2694*2d543d20SAndroid Build Coastguard Worker 				semanage_fc_node_destroy(temp);
2695*2d543d20SAndroid Build Coastguard Worker 				line_buf = line_end + 1;
2696*2d543d20SAndroid Build Coastguard Worker 				continue;
2697*2d543d20SAndroid Build Coastguard Worker 			}
2698*2d543d20SAndroid Build Coastguard Worker 
2699*2d543d20SAndroid Build Coastguard Worker 			/* Record the inode type. */
2700*2d543d20SAndroid Build Coastguard Worker 			temp->file_type =
2701*2d543d20SAndroid Build Coastguard Worker 			    (char *)strndup(&line_buf[i], type_len);
2702*2d543d20SAndroid Build Coastguard Worker 			if (!temp->file_type) {
2703*2d543d20SAndroid Build Coastguard Worker 				ERR(sh, "Failure allocating memory.");
2704*2d543d20SAndroid Build Coastguard Worker 				semanage_fc_node_destroy(temp);
2705*2d543d20SAndroid Build Coastguard Worker 				semanage_fc_node_list_destroy(head);
2706*2d543d20SAndroid Build Coastguard Worker 				return -1;
2707*2d543d20SAndroid Build Coastguard Worker 			}
2708*2d543d20SAndroid Build Coastguard Worker 
2709*2d543d20SAndroid Build Coastguard Worker 			i += type_len;
2710*2d543d20SAndroid Build Coastguard Worker 
2711*2d543d20SAndroid Build Coastguard Worker 			/* Skip the whitespace after the type. */
2712*2d543d20SAndroid Build Coastguard Worker 			for (; i < line_len; i++) {
2713*2d543d20SAndroid Build Coastguard Worker 				if (!isspace(line_buf[i]))
2714*2d543d20SAndroid Build Coastguard Worker 					break;
2715*2d543d20SAndroid Build Coastguard Worker 			}
2716*2d543d20SAndroid Build Coastguard Worker 			if (i == line_len) {
2717*2d543d20SAndroid Build Coastguard Worker 				ERR(sh,
2718*2d543d20SAndroid Build Coastguard Worker 				    "WARNING: semanage_fc_sort: Incomplete context. %s", temp->path);
2719*2d543d20SAndroid Build Coastguard Worker 				semanage_fc_node_destroy(temp);
2720*2d543d20SAndroid Build Coastguard Worker 				line_buf = line_end + 1;
2721*2d543d20SAndroid Build Coastguard Worker 				continue;
2722*2d543d20SAndroid Build Coastguard Worker 			}
2723*2d543d20SAndroid Build Coastguard Worker 		} else {
2724*2d543d20SAndroid Build Coastguard Worker 			type_len = 0;	/* inode type did not exist in the file context */
2725*2d543d20SAndroid Build Coastguard Worker 		}
2726*2d543d20SAndroid Build Coastguard Worker 
2727*2d543d20SAndroid Build Coastguard Worker 		/* Extract the context from the line. */
2728*2d543d20SAndroid Build Coastguard Worker 		start = i;
2729*2d543d20SAndroid Build Coastguard Worker 		while (i < line_len && (!isspace(line_buf[i])))
2730*2d543d20SAndroid Build Coastguard Worker 			i++;
2731*2d543d20SAndroid Build Coastguard Worker 		finish = i;
2732*2d543d20SAndroid Build Coastguard Worker 		context_len = finish - start;
2733*2d543d20SAndroid Build Coastguard Worker 
2734*2d543d20SAndroid Build Coastguard Worker 		temp->context = (char *)strndup(&line_buf[start], context_len);
2735*2d543d20SAndroid Build Coastguard Worker 		if (!temp->context) {
2736*2d543d20SAndroid Build Coastguard Worker 			ERR(sh, "Failure allocating memory.");
2737*2d543d20SAndroid Build Coastguard Worker 			semanage_fc_node_destroy(temp);
2738*2d543d20SAndroid Build Coastguard Worker 			semanage_fc_node_list_destroy(head);
2739*2d543d20SAndroid Build Coastguard Worker 			return -1;
2740*2d543d20SAndroid Build Coastguard Worker 		}
2741*2d543d20SAndroid Build Coastguard Worker 
2742*2d543d20SAndroid Build Coastguard Worker 		/* Initialize the data about the file context. */
2743*2d543d20SAndroid Build Coastguard Worker 		temp->path_len = regex_len;
2744*2d543d20SAndroid Build Coastguard Worker 		temp->effective_len = regex_len - escape_chars;
2745*2d543d20SAndroid Build Coastguard Worker 		temp->type_len = type_len;
2746*2d543d20SAndroid Build Coastguard Worker 		temp->context_len = context_len;
2747*2d543d20SAndroid Build Coastguard Worker 		semanage_fc_find_meta(temp);
2748*2d543d20SAndroid Build Coastguard Worker 
2749*2d543d20SAndroid Build Coastguard Worker 		/* Add this node to the end of the linked list. */
2750*2d543d20SAndroid Build Coastguard Worker 		current->next = temp;
2751*2d543d20SAndroid Build Coastguard Worker 		current = current->next;
2752*2d543d20SAndroid Build Coastguard Worker 
2753*2d543d20SAndroid Build Coastguard Worker 		line_buf = line_end + 1;
2754*2d543d20SAndroid Build Coastguard Worker 	}
2755*2d543d20SAndroid Build Coastguard Worker 
2756*2d543d20SAndroid Build Coastguard Worker 	/* Create the bucket linked list from the node linked list. */
2757*2d543d20SAndroid Build Coastguard Worker 	current = head->next;
2758*2d543d20SAndroid Build Coastguard Worker 	bcurrent = main = (semanage_file_context_bucket_t *)
2759*2d543d20SAndroid Build Coastguard Worker 	    calloc(1, sizeof(semanage_file_context_bucket_t));
2760*2d543d20SAndroid Build Coastguard Worker 	if (!main) {
2761*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Failure allocating memory.");
2762*2d543d20SAndroid Build Coastguard Worker 		semanage_fc_node_list_destroy(head);
2763*2d543d20SAndroid Build Coastguard Worker 		return -1;
2764*2d543d20SAndroid Build Coastguard Worker 	}
2765*2d543d20SAndroid Build Coastguard Worker 
2766*2d543d20SAndroid Build Coastguard Worker 	/* Free the head node, as it is no longer used. */
2767*2d543d20SAndroid Build Coastguard Worker 	semanage_fc_node_destroy(head);
2768*2d543d20SAndroid Build Coastguard Worker 	head = NULL;
2769*2d543d20SAndroid Build Coastguard Worker 
2770*2d543d20SAndroid Build Coastguard Worker 	/* Place each node into a bucket. */
2771*2d543d20SAndroid Build Coastguard Worker 	while (current) {
2772*2d543d20SAndroid Build Coastguard Worker 		bcurrent->data = current;
2773*2d543d20SAndroid Build Coastguard Worker 		current = current->next;
2774*2d543d20SAndroid Build Coastguard Worker 
2775*2d543d20SAndroid Build Coastguard Worker 		/* Detach the node in the bucket from the old list. */
2776*2d543d20SAndroid Build Coastguard Worker 		bcurrent->data->next = NULL;
2777*2d543d20SAndroid Build Coastguard Worker 
2778*2d543d20SAndroid Build Coastguard Worker 		/* If we need another bucket, add one to the end. */
2779*2d543d20SAndroid Build Coastguard Worker 		if (current) {
2780*2d543d20SAndroid Build Coastguard Worker 			bcurrent->next = (semanage_file_context_bucket_t *)
2781*2d543d20SAndroid Build Coastguard Worker 			    calloc(1, sizeof(semanage_file_context_bucket_t));
2782*2d543d20SAndroid Build Coastguard Worker 			if (!(bcurrent->next)) {
2783*2d543d20SAndroid Build Coastguard Worker 				ERR(sh, "Failure allocating memory.");
2784*2d543d20SAndroid Build Coastguard Worker 				semanage_fc_bucket_list_destroy(main);
2785*2d543d20SAndroid Build Coastguard Worker 				return -1;
2786*2d543d20SAndroid Build Coastguard Worker 			}
2787*2d543d20SAndroid Build Coastguard Worker 
2788*2d543d20SAndroid Build Coastguard Worker 			bcurrent = bcurrent->next;
2789*2d543d20SAndroid Build Coastguard Worker 		}
2790*2d543d20SAndroid Build Coastguard Worker 	}
2791*2d543d20SAndroid Build Coastguard Worker 
2792*2d543d20SAndroid Build Coastguard Worker 	/* Sort the bucket list. */
2793*2d543d20SAndroid Build Coastguard Worker 	semanage_fc_merge_sort(main);
2794*2d543d20SAndroid Build Coastguard Worker 
2795*2d543d20SAndroid Build Coastguard Worker 	/* First, calculate how much space we'll need for
2796*2d543d20SAndroid Build Coastguard Worker 	 * the newly sorted block of data.  (We don't just
2797*2d543d20SAndroid Build Coastguard Worker 	 * use buf_len for this because we have extracted
2798*2d543d20SAndroid Build Coastguard Worker 	 * comments and whitespace.) */
2799*2d543d20SAndroid Build Coastguard Worker 	i = 0;
2800*2d543d20SAndroid Build Coastguard Worker 	current = main->data;
2801*2d543d20SAndroid Build Coastguard Worker 	while (current) {
2802*2d543d20SAndroid Build Coastguard Worker 		i += current->path_len + 1;	/* +1 for a tab */
2803*2d543d20SAndroid Build Coastguard Worker 		if (current->file_type) {
2804*2d543d20SAndroid Build Coastguard Worker 			i += current->type_len + 1;	/* +1 for a tab */
2805*2d543d20SAndroid Build Coastguard Worker 		}
2806*2d543d20SAndroid Build Coastguard Worker 		i += current->context_len + 1;	/* +1 for a newline */
2807*2d543d20SAndroid Build Coastguard Worker 		current = current->next;
2808*2d543d20SAndroid Build Coastguard Worker 	}
2809*2d543d20SAndroid Build Coastguard Worker 	i = i + 1;		/* +1 for trailing \0 */
2810*2d543d20SAndroid Build Coastguard Worker 
2811*2d543d20SAndroid Build Coastguard Worker 	/* Allocate the buffer for the sorted list. */
2812*2d543d20SAndroid Build Coastguard Worker 	*sorted_buf = calloc(i, sizeof(char));
2813*2d543d20SAndroid Build Coastguard Worker 	if (!*sorted_buf) {
2814*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Failure allocating memory.");
2815*2d543d20SAndroid Build Coastguard Worker 		semanage_fc_bucket_list_destroy(main);
2816*2d543d20SAndroid Build Coastguard Worker 		return -1;
2817*2d543d20SAndroid Build Coastguard Worker 	}
2818*2d543d20SAndroid Build Coastguard Worker 	*sorted_buf_len = i;
2819*2d543d20SAndroid Build Coastguard Worker 
2820*2d543d20SAndroid Build Coastguard Worker 	/* Output the sorted semanage_file_context linked list to the char buffer. */
2821*2d543d20SAndroid Build Coastguard Worker 	sorted_buf_pos = *sorted_buf;
2822*2d543d20SAndroid Build Coastguard Worker 	current = main->data;
2823*2d543d20SAndroid Build Coastguard Worker 	while (current) {
2824*2d543d20SAndroid Build Coastguard Worker 		/* Output the path. */
2825*2d543d20SAndroid Build Coastguard Worker 		i = current->path_len + 1;	/* +1 for tab */
2826*2d543d20SAndroid Build Coastguard Worker 		snprintf(sorted_buf_pos, i + 1, "%s\t", current->path);
2827*2d543d20SAndroid Build Coastguard Worker 		sorted_buf_pos = sorted_buf_pos + i;
2828*2d543d20SAndroid Build Coastguard Worker 
2829*2d543d20SAndroid Build Coastguard Worker 		/* Output the type, if there is one. */
2830*2d543d20SAndroid Build Coastguard Worker 		if (current->file_type) {
2831*2d543d20SAndroid Build Coastguard Worker 			i = strlen(current->file_type) + 1;	/* +1 for tab */
2832*2d543d20SAndroid Build Coastguard Worker 			snprintf(sorted_buf_pos, i + 1, "%s\t",
2833*2d543d20SAndroid Build Coastguard Worker 				 current->file_type);
2834*2d543d20SAndroid Build Coastguard Worker 			sorted_buf_pos = sorted_buf_pos + i;
2835*2d543d20SAndroid Build Coastguard Worker 		}
2836*2d543d20SAndroid Build Coastguard Worker 
2837*2d543d20SAndroid Build Coastguard Worker 		/* Output the context. */
2838*2d543d20SAndroid Build Coastguard Worker 		i = strlen(current->context) + 1;	/* +1 for newline */
2839*2d543d20SAndroid Build Coastguard Worker 		snprintf(sorted_buf_pos, i + 1, "%s\n", current->context);
2840*2d543d20SAndroid Build Coastguard Worker 		sorted_buf_pos = sorted_buf_pos + i;
2841*2d543d20SAndroid Build Coastguard Worker 
2842*2d543d20SAndroid Build Coastguard Worker 		current = current->next;
2843*2d543d20SAndroid Build Coastguard Worker 	}
2844*2d543d20SAndroid Build Coastguard Worker 
2845*2d543d20SAndroid Build Coastguard Worker 	/* Clean up. */
2846*2d543d20SAndroid Build Coastguard Worker 	semanage_fc_bucket_list_destroy(main);
2847*2d543d20SAndroid Build Coastguard Worker 
2848*2d543d20SAndroid Build Coastguard Worker 	/* Sanity check. */
2849*2d543d20SAndroid Build Coastguard Worker 	sorted_buf_pos++;
2850*2d543d20SAndroid Build Coastguard Worker 	if ((sorted_buf_pos - *sorted_buf) != (ssize_t) * sorted_buf_len) {
2851*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Failure writing sorted buffer.");
2852*2d543d20SAndroid Build Coastguard Worker 		free(*sorted_buf);
2853*2d543d20SAndroid Build Coastguard Worker 		*sorted_buf = NULL;
2854*2d543d20SAndroid Build Coastguard Worker 		return -1;
2855*2d543d20SAndroid Build Coastguard Worker 	}
2856*2d543d20SAndroid Build Coastguard Worker 
2857*2d543d20SAndroid Build Coastguard Worker 	return 0;
2858*2d543d20SAndroid Build Coastguard Worker }
2859*2d543d20SAndroid Build Coastguard Worker 
2860*2d543d20SAndroid Build Coastguard Worker /********************* functions that sort netfilter contexts *********************/
2861*2d543d20SAndroid Build Coastguard Worker #define NC_SORT_NAMES { "pre", "base", "module", "local", "post" }
2862*2d543d20SAndroid Build Coastguard Worker #define NC_SORT_NAMES_LEN { 3, 4, 6, 5, 4 }
2863*2d543d20SAndroid Build Coastguard Worker #define NC_SORT_NEL 5
semanage_nc_destroy_ruletab(semanage_netfilter_context_node_t * ruletab[NC_SORT_NEL][2])2864*2d543d20SAndroid Build Coastguard Worker static void semanage_nc_destroy_ruletab(semanage_netfilter_context_node_t *
2865*2d543d20SAndroid Build Coastguard Worker 					ruletab[NC_SORT_NEL][2])
2866*2d543d20SAndroid Build Coastguard Worker {
2867*2d543d20SAndroid Build Coastguard Worker 	semanage_netfilter_context_node_t *curr, *next;
2868*2d543d20SAndroid Build Coastguard Worker 	int i;
2869*2d543d20SAndroid Build Coastguard Worker 
2870*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < NC_SORT_NEL; i++) {
2871*2d543d20SAndroid Build Coastguard Worker 		for (curr = ruletab[i][0]; curr != NULL; curr = next) {
2872*2d543d20SAndroid Build Coastguard Worker 			next = curr->next;
2873*2d543d20SAndroid Build Coastguard Worker 			free(curr->rule);
2874*2d543d20SAndroid Build Coastguard Worker 			free(curr);
2875*2d543d20SAndroid Build Coastguard Worker 		}
2876*2d543d20SAndroid Build Coastguard Worker 	}
2877*2d543d20SAndroid Build Coastguard Worker }
2878*2d543d20SAndroid Build Coastguard Worker 
2879*2d543d20SAndroid Build Coastguard Worker /*  Entry function for sorting a set of netfilter context lines.
2880*2d543d20SAndroid Build Coastguard Worker  *  Returns 0 on success, -1 on failure.
2881*2d543d20SAndroid Build Coastguard Worker  *  Allocates a buffer pointed to by sorted_buf that contains the sorted lines.
2882*2d543d20SAndroid Build Coastguard Worker  *  sorted_buf_len is set to the size of this buffer.
2883*2d543d20SAndroid Build Coastguard Worker  *  This buffer is guaranteed to have a final \0 character.
2884*2d543d20SAndroid Build Coastguard Worker  *  This buffer must be released by the caller.
2885*2d543d20SAndroid Build Coastguard Worker  */
semanage_nc_sort(semanage_handle_t * sh,const char * buf,size_t buf_len,char ** sorted_buf,size_t * sorted_buf_len)2886*2d543d20SAndroid Build Coastguard Worker int semanage_nc_sort(semanage_handle_t * sh, const char *buf, size_t buf_len,
2887*2d543d20SAndroid Build Coastguard Worker 		     char **sorted_buf, size_t * sorted_buf_len)
2888*2d543d20SAndroid Build Coastguard Worker {
2889*2d543d20SAndroid Build Coastguard Worker 
2890*2d543d20SAndroid Build Coastguard Worker 	/* parsing bits */
2891*2d543d20SAndroid Build Coastguard Worker 	const char *priority_names[] = NC_SORT_NAMES;
2892*2d543d20SAndroid Build Coastguard Worker 	const int priority_names_len[] = NC_SORT_NAMES_LEN;
2893*2d543d20SAndroid Build Coastguard Worker 	size_t line_len, buf_remainder, i, offset;
2894*2d543d20SAndroid Build Coastguard Worker 	const char *line_buf, *line_end;
2895*2d543d20SAndroid Build Coastguard Worker 
2896*2d543d20SAndroid Build Coastguard Worker 	/* ruletab bits */
2897*2d543d20SAndroid Build Coastguard Worker 	/* keep track of the head (index 0) and tail (index 1) with this array */
2898*2d543d20SAndroid Build Coastguard Worker 	semanage_netfilter_context_node_t *ruletab[NC_SORT_NEL][2];
2899*2d543d20SAndroid Build Coastguard Worker 	semanage_netfilter_context_node_t *curr, *node;
2900*2d543d20SAndroid Build Coastguard Worker 	int priority;
2901*2d543d20SAndroid Build Coastguard Worker 
2902*2d543d20SAndroid Build Coastguard Worker 	/* sorted buffer bits */
2903*2d543d20SAndroid Build Coastguard Worker 	char *sorted_buf_pos;
2904*2d543d20SAndroid Build Coastguard Worker 	size_t count;
2905*2d543d20SAndroid Build Coastguard Worker 
2906*2d543d20SAndroid Build Coastguard Worker 	/* initialize ruletab */
2907*2d543d20SAndroid Build Coastguard Worker 	memset(ruletab, 0,
2908*2d543d20SAndroid Build Coastguard Worker 	       NC_SORT_NEL * 2 * sizeof(semanage_netfilter_context_node_t *));
2909*2d543d20SAndroid Build Coastguard Worker 
2910*2d543d20SAndroid Build Coastguard Worker 	/* while lines to be read */
2911*2d543d20SAndroid Build Coastguard Worker 	line_buf = buf;
2912*2d543d20SAndroid Build Coastguard Worker 	buf_remainder = buf_len;
2913*2d543d20SAndroid Build Coastguard Worker 	while ((line_end = semanage_get_line_end(line_buf, buf_remainder))) {
2914*2d543d20SAndroid Build Coastguard Worker 		line_len = line_end - line_buf + 1;
2915*2d543d20SAndroid Build Coastguard Worker 		buf_remainder = buf_remainder - line_len;
2916*2d543d20SAndroid Build Coastguard Worker 
2917*2d543d20SAndroid Build Coastguard Worker 		if (line_len == 0 || line_len == 1) {
2918*2d543d20SAndroid Build Coastguard Worker 			line_buf = line_end + 1;
2919*2d543d20SAndroid Build Coastguard Worker 			continue;
2920*2d543d20SAndroid Build Coastguard Worker 		}
2921*2d543d20SAndroid Build Coastguard Worker 
2922*2d543d20SAndroid Build Coastguard Worker 		/* Skip the whitespace at the front of the line. */
2923*2d543d20SAndroid Build Coastguard Worker 		for (i = 0; i < line_len; i++) {
2924*2d543d20SAndroid Build Coastguard Worker 			if (!isspace(line_buf[i]))
2925*2d543d20SAndroid Build Coastguard Worker 				break;
2926*2d543d20SAndroid Build Coastguard Worker 		}
2927*2d543d20SAndroid Build Coastguard Worker 
2928*2d543d20SAndroid Build Coastguard Worker 		/* Check for a blank line. */
2929*2d543d20SAndroid Build Coastguard Worker 		if (i >= line_len) {
2930*2d543d20SAndroid Build Coastguard Worker 			line_buf = line_end + 1;
2931*2d543d20SAndroid Build Coastguard Worker 			continue;
2932*2d543d20SAndroid Build Coastguard Worker 		}
2933*2d543d20SAndroid Build Coastguard Worker 
2934*2d543d20SAndroid Build Coastguard Worker 		/* Check if the line is a comment. */
2935*2d543d20SAndroid Build Coastguard Worker 		if (line_buf[i] == '#') {
2936*2d543d20SAndroid Build Coastguard Worker 			line_buf = line_end + 1;
2937*2d543d20SAndroid Build Coastguard Worker 			continue;
2938*2d543d20SAndroid Build Coastguard Worker 		}
2939*2d543d20SAndroid Build Coastguard Worker 
2940*2d543d20SAndroid Build Coastguard Worker 		/* extract priority */
2941*2d543d20SAndroid Build Coastguard Worker 		priority = -1;
2942*2d543d20SAndroid Build Coastguard Worker 		offset = 0;
2943*2d543d20SAndroid Build Coastguard Worker 		for (i = 0; i < NC_SORT_NEL; i++) {
2944*2d543d20SAndroid Build Coastguard Worker 			if (strncmp
2945*2d543d20SAndroid Build Coastguard Worker 			    (line_buf, priority_names[i],
2946*2d543d20SAndroid Build Coastguard Worker 			     priority_names_len[i]) == 0) {
2947*2d543d20SAndroid Build Coastguard Worker 				priority = i;
2948*2d543d20SAndroid Build Coastguard Worker 				offset = priority_names_len[i];
2949*2d543d20SAndroid Build Coastguard Worker 				break;
2950*2d543d20SAndroid Build Coastguard Worker 			}
2951*2d543d20SAndroid Build Coastguard Worker 		}
2952*2d543d20SAndroid Build Coastguard Worker 
2953*2d543d20SAndroid Build Coastguard Worker 		if (priority < 0) {
2954*2d543d20SAndroid Build Coastguard Worker 			ERR(sh, "Netfilter context line missing priority.");
2955*2d543d20SAndroid Build Coastguard Worker 			semanage_nc_destroy_ruletab(ruletab);
2956*2d543d20SAndroid Build Coastguard Worker 			return -1;
2957*2d543d20SAndroid Build Coastguard Worker 		}
2958*2d543d20SAndroid Build Coastguard Worker 
2959*2d543d20SAndroid Build Coastguard Worker 		/* skip over whitespace */
2960*2d543d20SAndroid Build Coastguard Worker 		for (; offset < line_len && isspace(line_buf[offset]);
2961*2d543d20SAndroid Build Coastguard Worker 		     offset++) ;
2962*2d543d20SAndroid Build Coastguard Worker 
2963*2d543d20SAndroid Build Coastguard Worker 		/* load rule into node */
2964*2d543d20SAndroid Build Coastguard Worker 		node = (semanage_netfilter_context_node_t *)
2965*2d543d20SAndroid Build Coastguard Worker 		    malloc(sizeof(semanage_netfilter_context_node_t));
2966*2d543d20SAndroid Build Coastguard Worker 		if (!node) {
2967*2d543d20SAndroid Build Coastguard Worker 			ERR(sh, "Failure allocating memory.");
2968*2d543d20SAndroid Build Coastguard Worker 			semanage_nc_destroy_ruletab(ruletab);
2969*2d543d20SAndroid Build Coastguard Worker 			return -1;
2970*2d543d20SAndroid Build Coastguard Worker 		}
2971*2d543d20SAndroid Build Coastguard Worker 
2972*2d543d20SAndroid Build Coastguard Worker 		node->rule =
2973*2d543d20SAndroid Build Coastguard Worker 		    (char *)strndup(line_buf + offset, line_len - offset);
2974*2d543d20SAndroid Build Coastguard Worker 		node->rule_len = line_len - offset;
2975*2d543d20SAndroid Build Coastguard Worker 		node->next = NULL;
2976*2d543d20SAndroid Build Coastguard Worker 
2977*2d543d20SAndroid Build Coastguard Worker 		if (!node->rule) {
2978*2d543d20SAndroid Build Coastguard Worker 			ERR(sh, "Failure allocating memory.");
2979*2d543d20SAndroid Build Coastguard Worker 			free(node);
2980*2d543d20SAndroid Build Coastguard Worker 			semanage_nc_destroy_ruletab(ruletab);
2981*2d543d20SAndroid Build Coastguard Worker 			return -1;
2982*2d543d20SAndroid Build Coastguard Worker 		}
2983*2d543d20SAndroid Build Coastguard Worker 
2984*2d543d20SAndroid Build Coastguard Worker 		/* add node to rule table */
2985*2d543d20SAndroid Build Coastguard Worker 		if (ruletab[priority][0] && ruletab[priority][1]) {
2986*2d543d20SAndroid Build Coastguard Worker 			/* add to end of list, update tail pointer */
2987*2d543d20SAndroid Build Coastguard Worker 			ruletab[priority][1]->next = node;
2988*2d543d20SAndroid Build Coastguard Worker 			ruletab[priority][1] = node;
2989*2d543d20SAndroid Build Coastguard Worker 		} else {
2990*2d543d20SAndroid Build Coastguard Worker 			/* this list is empty, make head and tail point to the node */
2991*2d543d20SAndroid Build Coastguard Worker 			ruletab[priority][0] = ruletab[priority][1] = node;
2992*2d543d20SAndroid Build Coastguard Worker 		}
2993*2d543d20SAndroid Build Coastguard Worker 
2994*2d543d20SAndroid Build Coastguard Worker 		line_buf = line_end + 1;
2995*2d543d20SAndroid Build Coastguard Worker 	}
2996*2d543d20SAndroid Build Coastguard Worker 
2997*2d543d20SAndroid Build Coastguard Worker 	/* First, calculate how much space we'll need for
2998*2d543d20SAndroid Build Coastguard Worker 	 * the newly sorted block of data.  (We don't just
2999*2d543d20SAndroid Build Coastguard Worker 	 * use buf_len for this because we have extracted
3000*2d543d20SAndroid Build Coastguard Worker 	 * comments and whitespace.)  Start at 1 for trailing \0 */
3001*2d543d20SAndroid Build Coastguard Worker 	count = 1;
3002*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < NC_SORT_NEL; i++)
3003*2d543d20SAndroid Build Coastguard Worker 		for (curr = ruletab[i][0]; curr != NULL; curr = curr->next)
3004*2d543d20SAndroid Build Coastguard Worker 			count += curr->rule_len;
3005*2d543d20SAndroid Build Coastguard Worker 
3006*2d543d20SAndroid Build Coastguard Worker 	/* Allocate the buffer for the sorted list. */
3007*2d543d20SAndroid Build Coastguard Worker 	*sorted_buf = calloc(count, sizeof(char));
3008*2d543d20SAndroid Build Coastguard Worker 	if (!*sorted_buf) {
3009*2d543d20SAndroid Build Coastguard Worker 		ERR(sh, "Failure allocating memory.");
3010*2d543d20SAndroid Build Coastguard Worker 		semanage_nc_destroy_ruletab(ruletab);
3011*2d543d20SAndroid Build Coastguard Worker 		return -1;
3012*2d543d20SAndroid Build Coastguard Worker 	}
3013*2d543d20SAndroid Build Coastguard Worker 	*sorted_buf_len = count;
3014*2d543d20SAndroid Build Coastguard Worker 
3015*2d543d20SAndroid Build Coastguard Worker 	/* write out rule buffer */
3016*2d543d20SAndroid Build Coastguard Worker 	sorted_buf_pos = *sorted_buf;
3017*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < NC_SORT_NEL; i++) {
3018*2d543d20SAndroid Build Coastguard Worker 		for (curr = ruletab[i][0]; curr != NULL; curr = curr->next) {
3019*2d543d20SAndroid Build Coastguard Worker 			/* put rule into buffer */
3020*2d543d20SAndroid Build Coastguard Worker 			snprintf(sorted_buf_pos, curr->rule_len + 1, "%s\n", curr->rule);	/* +1 for newline */
3021*2d543d20SAndroid Build Coastguard Worker 			sorted_buf_pos = sorted_buf_pos + curr->rule_len;
3022*2d543d20SAndroid Build Coastguard Worker 		}
3023*2d543d20SAndroid Build Coastguard Worker 	}
3024*2d543d20SAndroid Build Coastguard Worker 
3025*2d543d20SAndroid Build Coastguard Worker 	/* free ruletab */
3026*2d543d20SAndroid Build Coastguard Worker 	semanage_nc_destroy_ruletab(ruletab);
3027*2d543d20SAndroid Build Coastguard Worker 
3028*2d543d20SAndroid Build Coastguard Worker 	return 0;
3029*2d543d20SAndroid Build Coastguard Worker }
3030*2d543d20SAndroid Build Coastguard Worker 
3031*2d543d20SAndroid Build Coastguard Worker /* Make sure the file context and ownership of files in the policy
3032*2d543d20SAndroid Build Coastguard Worker  * store does not change */
semanage_setfiles(const char * path)3033*2d543d20SAndroid Build Coastguard Worker void semanage_setfiles(const char *path){
3034*2d543d20SAndroid Build Coastguard Worker 	struct stat sb;
3035*2d543d20SAndroid Build Coastguard Worker 	int fd;
3036*2d543d20SAndroid Build Coastguard Worker 	/* Fix the user and role portions of the context, ignore errors
3037*2d543d20SAndroid Build Coastguard Worker 	 * since this is not a critical operation */
3038*2d543d20SAndroid Build Coastguard Worker 	selinux_restorecon(path, SELINUX_RESTORECON_SET_SPECFILE_CTX | SELINUX_RESTORECON_IGNORE_NOENTRY);
3039*2d543d20SAndroid Build Coastguard Worker 
3040*2d543d20SAndroid Build Coastguard Worker 	/* Make sure "path" is owned by root */
3041*2d543d20SAndroid Build Coastguard Worker 	if ((geteuid() != 0 || getegid() != 0) &&
3042*2d543d20SAndroid Build Coastguard Worker 	    ((fd = open(path, O_RDONLY)) != -1)){
3043*2d543d20SAndroid Build Coastguard Worker 		/* Skip files with the SUID or SGID bit set -- abuse protection */
3044*2d543d20SAndroid Build Coastguard Worker 		if ((fstat(fd, &sb) != -1) &&
3045*2d543d20SAndroid Build Coastguard Worker 		    !(S_ISREG(sb.st_mode) &&
3046*2d543d20SAndroid Build Coastguard Worker 		      (sb.st_mode & (S_ISUID | S_ISGID))) &&
3047*2d543d20SAndroid Build Coastguard Worker 		    (fchown(fd, 0, 0) == -1))
3048*2d543d20SAndroid Build Coastguard Worker 			fprintf(stderr, "Warning! Could not set ownership of %s to root\n", path);
3049*2d543d20SAndroid Build Coastguard Worker 
3050*2d543d20SAndroid Build Coastguard Worker 		close(fd);
3051*2d543d20SAndroid Build Coastguard Worker 	}
3052*2d543d20SAndroid Build Coastguard Worker }
3053