xref: /aosp_15_r20/external/selinux/libsemanage/src/conf-parse.y (revision 2d543d20722ada2425b5bdab9d0d1d29470e7bba)
1*2d543d20SAndroid Build Coastguard Worker /* Authors: Jason Tang     <[email protected]>
2*2d543d20SAndroid Build Coastguard Worker  *          James Athey    <[email protected]>
3*2d543d20SAndroid Build Coastguard Worker  *
4*2d543d20SAndroid Build Coastguard Worker  * Copyright (C) 2004-2006 Tresys Technology, LLC
5*2d543d20SAndroid Build Coastguard Worker  *
6*2d543d20SAndroid Build Coastguard Worker  *  This library is free software; you can redistribute it and/or
7*2d543d20SAndroid Build Coastguard Worker  *  modify it under the terms of the GNU Lesser General Public
8*2d543d20SAndroid Build Coastguard Worker  *  License as published by the Free Software Foundation; either
9*2d543d20SAndroid Build Coastguard Worker  *  version 2.1 of the License, or (at your option) any later version.
10*2d543d20SAndroid Build Coastguard Worker  *
11*2d543d20SAndroid Build Coastguard Worker  *  This library is distributed in the hope that it will be useful,
12*2d543d20SAndroid Build Coastguard Worker  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13*2d543d20SAndroid Build Coastguard Worker  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14*2d543d20SAndroid Build Coastguard Worker  *  Lesser General Public License for more details.
15*2d543d20SAndroid Build Coastguard Worker  *
16*2d543d20SAndroid Build Coastguard Worker  *  You should have received a copy of the GNU Lesser General Public
17*2d543d20SAndroid Build Coastguard Worker  *  License along with this library; if not, write to the Free Software
18*2d543d20SAndroid Build Coastguard Worker  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19*2d543d20SAndroid Build Coastguard Worker  */
20*2d543d20SAndroid Build Coastguard Worker 
21*2d543d20SAndroid Build Coastguard Worker %{
22*2d543d20SAndroid Build Coastguard Worker 
23*2d543d20SAndroid Build Coastguard Worker #include "semanage_conf.h"
24*2d543d20SAndroid Build Coastguard Worker 
25*2d543d20SAndroid Build Coastguard Worker #include <sepol/policydb.h>
26*2d543d20SAndroid Build Coastguard Worker #include <selinux/selinux.h>
27*2d543d20SAndroid Build Coastguard Worker #include <semanage/handle.h>
28*2d543d20SAndroid Build Coastguard Worker 
29*2d543d20SAndroid Build Coastguard Worker #include <unistd.h>
30*2d543d20SAndroid Build Coastguard Worker #include <stdio.h>
31*2d543d20SAndroid Build Coastguard Worker #include <stdlib.h>
32*2d543d20SAndroid Build Coastguard Worker #include <string.h>
33*2d543d20SAndroid Build Coastguard Worker 
34*2d543d20SAndroid Build Coastguard Worker extern int semanage_lex(void);                /* defined in conf-scan.c */
35*2d543d20SAndroid Build Coastguard Worker extern int semanage_lex_destroy(void);        /* defined in conf-scan.c */
36*2d543d20SAndroid Build Coastguard Worker int semanage_error(const char *msg);
37*2d543d20SAndroid Build Coastguard Worker 
38*2d543d20SAndroid Build Coastguard Worker extern FILE *semanage_in;
39*2d543d20SAndroid Build Coastguard Worker extern char *semanage_text;
40*2d543d20SAndroid Build Coastguard Worker 
41*2d543d20SAndroid Build Coastguard Worker static int parse_module_store(char *arg);
42*2d543d20SAndroid Build Coastguard Worker static int parse_store_root_path(char *arg);
43*2d543d20SAndroid Build Coastguard Worker static int parse_compiler_path(char *arg);
44*2d543d20SAndroid Build Coastguard Worker static void semanage_conf_external_prog_destroy(external_prog_t *ep);
45*2d543d20SAndroid Build Coastguard Worker static int new_external_prog(external_prog_t **chain);
46*2d543d20SAndroid Build Coastguard Worker 
47*2d543d20SAndroid Build Coastguard Worker static semanage_conf_t *current_conf;
48*2d543d20SAndroid Build Coastguard Worker static external_prog_t *new_external;
49*2d543d20SAndroid Build Coastguard Worker static int parse_errors;
50*2d543d20SAndroid Build Coastguard Worker 
51*2d543d20SAndroid Build Coastguard Worker #define PASSIGN(p1,p2) { free(p1); p1 = p2; }
52*2d543d20SAndroid Build Coastguard Worker 
53*2d543d20SAndroid Build Coastguard Worker %}
54*2d543d20SAndroid Build Coastguard Worker 
55*2d543d20SAndroid Build Coastguard Worker %name-prefix "semanage_"
56*2d543d20SAndroid Build Coastguard Worker 
57*2d543d20SAndroid Build Coastguard Worker %union {
58*2d543d20SAndroid Build Coastguard Worker         int d;
59*2d543d20SAndroid Build Coastguard Worker         char *s;
60*2d543d20SAndroid Build Coastguard Worker }
61*2d543d20SAndroid Build Coastguard Worker 
62*2d543d20SAndroid Build Coastguard Worker %token MODULE_STORE VERSION EXPAND_CHECK FILE_MODE SAVE_PREVIOUS SAVE_LINKED TARGET_PLATFORM COMPILER_DIR IGNORE_MODULE_CACHE STORE_ROOT OPTIMIZE_POLICY
63*2d543d20SAndroid Build Coastguard Worker %token LOAD_POLICY_START SETFILES_START SEFCONTEXT_COMPILE_START DISABLE_GENHOMEDIRCON HANDLE_UNKNOWN USEPASSWD IGNOREDIRS
64*2d543d20SAndroid Build Coastguard Worker %token BZIP_BLOCKSIZE BZIP_SMALL REMOVE_HLL
65*2d543d20SAndroid Build Coastguard Worker %token VERIFY_MOD_START VERIFY_LINKED_START VERIFY_KERNEL_START BLOCK_END
66*2d543d20SAndroid Build Coastguard Worker %token PROG_PATH PROG_ARGS
67*2d543d20SAndroid Build Coastguard Worker %token <s> ARG
68*2d543d20SAndroid Build Coastguard Worker %type <d> verify_start_tok
69*2d543d20SAndroid Build Coastguard Worker 
70*2d543d20SAndroid Build Coastguard Worker %%
71*2d543d20SAndroid Build Coastguard Worker 
72*2d543d20SAndroid Build Coastguard Worker config_file:    config_line config_file
73*2d543d20SAndroid Build Coastguard Worker         |       /* empty */
74*2d543d20SAndroid Build Coastguard Worker         ;
75*2d543d20SAndroid Build Coastguard Worker 
76*2d543d20SAndroid Build Coastguard Worker config_line:    single_opt
77*2d543d20SAndroid Build Coastguard Worker         |       command_block
78*2d543d20SAndroid Build Coastguard Worker         |       verify_block
79*2d543d20SAndroid Build Coastguard Worker         ;
80*2d543d20SAndroid Build Coastguard Worker 
81*2d543d20SAndroid Build Coastguard Worker single_opt:     module_store
82*2d543d20SAndroid Build Coastguard Worker         |       version
83*2d543d20SAndroid Build Coastguard Worker         |       target_platform
84*2d543d20SAndroid Build Coastguard Worker         |       store_root
85*2d543d20SAndroid Build Coastguard Worker         |       compiler_dir
86*2d543d20SAndroid Build Coastguard Worker         |       ignore_module_cache
87*2d543d20SAndroid Build Coastguard Worker         |       expand_check
88*2d543d20SAndroid Build Coastguard Worker         |       file_mode
89*2d543d20SAndroid Build Coastguard Worker         |       save_previous
90*2d543d20SAndroid Build Coastguard Worker         |       save_linked
91*2d543d20SAndroid Build Coastguard Worker         |       disable_genhomedircon
92*2d543d20SAndroid Build Coastguard Worker         |       usepasswd
93*2d543d20SAndroid Build Coastguard Worker         |       ignoredirs
94*2d543d20SAndroid Build Coastguard Worker         |       handle_unknown
95*2d543d20SAndroid Build Coastguard Worker 	|	bzip_blocksize
96*2d543d20SAndroid Build Coastguard Worker 	|	bzip_small
97*2d543d20SAndroid Build Coastguard Worker 	|	remove_hll
98*2d543d20SAndroid Build Coastguard Worker 	|	optimize_policy
99*2d543d20SAndroid Build Coastguard Worker         ;
100*2d543d20SAndroid Build Coastguard Worker 
101*2d543d20SAndroid Build Coastguard Worker module_store:   MODULE_STORE '=' ARG {
102*2d543d20SAndroid Build Coastguard Worker                         if (parse_module_store($3) != 0) {
103*2d543d20SAndroid Build Coastguard Worker                                 parse_errors++;
104*2d543d20SAndroid Build Coastguard Worker                                 YYABORT;
105*2d543d20SAndroid Build Coastguard Worker                         }
106*2d543d20SAndroid Build Coastguard Worker                         free($3);
107*2d543d20SAndroid Build Coastguard Worker                 }
108*2d543d20SAndroid Build Coastguard Worker 
109*2d543d20SAndroid Build Coastguard Worker         ;
110*2d543d20SAndroid Build Coastguard Worker 
111*2d543d20SAndroid Build Coastguard Worker store_root:     STORE_ROOT '=' ARG  {
112*2d543d20SAndroid Build Coastguard Worker                         if (parse_store_root_path($3) != 0) {
113*2d543d20SAndroid Build Coastguard Worker                                 parse_errors++;
114*2d543d20SAndroid Build Coastguard Worker                                 YYABORT;
115*2d543d20SAndroid Build Coastguard Worker                         }
116*2d543d20SAndroid Build Coastguard Worker                         free($3);
117*2d543d20SAndroid Build Coastguard Worker                 }
118*2d543d20SAndroid Build Coastguard Worker         ;
119*2d543d20SAndroid Build Coastguard Worker 
120*2d543d20SAndroid Build Coastguard Worker compiler_dir:       COMPILER_DIR '=' ARG  {
121*2d543d20SAndroid Build Coastguard Worker                         if (parse_compiler_path($3) != 0) {
122*2d543d20SAndroid Build Coastguard Worker                                 parse_errors++;
123*2d543d20SAndroid Build Coastguard Worker                                 YYABORT;
124*2d543d20SAndroid Build Coastguard Worker                         }
125*2d543d20SAndroid Build Coastguard Worker                         free($3);
126*2d543d20SAndroid Build Coastguard Worker                 }
127*2d543d20SAndroid Build Coastguard Worker         ;
128*2d543d20SAndroid Build Coastguard Worker 
129*2d543d20SAndroid Build Coastguard Worker ignore_module_cache:	IGNORE_MODULE_CACHE '=' ARG  {
130*2d543d20SAndroid Build Coastguard Worker 							if (strcasecmp($3, "true") == 0)
131*2d543d20SAndroid Build Coastguard Worker 								current_conf->ignore_module_cache = 1;
132*2d543d20SAndroid Build Coastguard Worker 							else if (strcasecmp($3, "false") == 0)
133*2d543d20SAndroid Build Coastguard Worker 								current_conf->ignore_module_cache = 0;
134*2d543d20SAndroid Build Coastguard Worker 							else {
135*2d543d20SAndroid Build Coastguard Worker 								yyerror("disable-caching can only be 'true' or 'false'");
136*2d543d20SAndroid Build Coastguard Worker 							}
137*2d543d20SAndroid Build Coastguard Worker 							free($3);
138*2d543d20SAndroid Build Coastguard Worker 						}
139*2d543d20SAndroid Build Coastguard Worker         ;
140*2d543d20SAndroid Build Coastguard Worker 
141*2d543d20SAndroid Build Coastguard Worker version:        VERSION '=' ARG  {
142*2d543d20SAndroid Build Coastguard Worker                         current_conf->policyvers = atoi($3);
143*2d543d20SAndroid Build Coastguard Worker                         free($3);
144*2d543d20SAndroid Build Coastguard Worker                         if (current_conf->policyvers < sepol_policy_kern_vers_min() ||
145*2d543d20SAndroid Build Coastguard Worker                             current_conf->policyvers > sepol_policy_kern_vers_max()) {
146*2d543d20SAndroid Build Coastguard Worker                                 parse_errors++;
147*2d543d20SAndroid Build Coastguard Worker                                 YYABORT;
148*2d543d20SAndroid Build Coastguard Worker                         }
149*2d543d20SAndroid Build Coastguard Worker                 }
150*2d543d20SAndroid Build Coastguard Worker         ;
151*2d543d20SAndroid Build Coastguard Worker 
152*2d543d20SAndroid Build Coastguard Worker target_platform: TARGET_PLATFORM '=' ARG  {
153*2d543d20SAndroid Build Coastguard Worker                         if (strcasecmp($3, "selinux") == 0)
154*2d543d20SAndroid Build Coastguard Worker                                 current_conf->target_platform = SEPOL_TARGET_SELINUX;
155*2d543d20SAndroid Build Coastguard Worker                         else if (strcasecmp($3, "xen") == 0)
156*2d543d20SAndroid Build Coastguard Worker                                 current_conf->target_platform = SEPOL_TARGET_XEN;
157*2d543d20SAndroid Build Coastguard Worker                         else {
158*2d543d20SAndroid Build Coastguard Worker                                 yyerror("target_platform can only be 'selinux' or 'xen'");
159*2d543d20SAndroid Build Coastguard Worker                         }
160*2d543d20SAndroid Build Coastguard Worker                         free($3);
161*2d543d20SAndroid Build Coastguard Worker                 }
162*2d543d20SAndroid Build Coastguard Worker         ;
163*2d543d20SAndroid Build Coastguard Worker 
164*2d543d20SAndroid Build Coastguard Worker expand_check:   EXPAND_CHECK '=' ARG  {
165*2d543d20SAndroid Build Coastguard Worker                         current_conf->expand_check = atoi($3);
166*2d543d20SAndroid Build Coastguard Worker                         free($3);
167*2d543d20SAndroid Build Coastguard Worker                 }
168*2d543d20SAndroid Build Coastguard Worker         ;
169*2d543d20SAndroid Build Coastguard Worker 
170*2d543d20SAndroid Build Coastguard Worker file_mode:   FILE_MODE '=' ARG  {
171*2d543d20SAndroid Build Coastguard Worker                         current_conf->file_mode = strtoul($3, NULL, 8);
172*2d543d20SAndroid Build Coastguard Worker                         free($3);
173*2d543d20SAndroid Build Coastguard Worker                 }
174*2d543d20SAndroid Build Coastguard Worker         ;
175*2d543d20SAndroid Build Coastguard Worker 
176*2d543d20SAndroid Build Coastguard Worker save_previous:    SAVE_PREVIOUS '=' ARG {
177*2d543d20SAndroid Build Coastguard Worker 	                if (strcasecmp($3, "true") == 0)
178*2d543d20SAndroid Build Coastguard Worker 		                current_conf->save_previous = 1;
179*2d543d20SAndroid Build Coastguard Worker 			else if (strcasecmp($3, "false") == 0)
180*2d543d20SAndroid Build Coastguard Worker 				current_conf->save_previous = 0;
181*2d543d20SAndroid Build Coastguard Worker 			else {
182*2d543d20SAndroid Build Coastguard Worker 				yyerror("save-previous can only be 'true' or 'false'");
183*2d543d20SAndroid Build Coastguard Worker 			}
184*2d543d20SAndroid Build Coastguard Worker 			free($3);
185*2d543d20SAndroid Build Coastguard Worker                 }
186*2d543d20SAndroid Build Coastguard Worker         ;
187*2d543d20SAndroid Build Coastguard Worker 
188*2d543d20SAndroid Build Coastguard Worker 
189*2d543d20SAndroid Build Coastguard Worker save_linked:    SAVE_LINKED '=' ARG {
190*2d543d20SAndroid Build Coastguard Worker 	                if (strcasecmp($3, "true") == 0)
191*2d543d20SAndroid Build Coastguard Worker 		                current_conf->save_linked = 1;
192*2d543d20SAndroid Build Coastguard Worker 			else if (strcasecmp($3, "false") == 0)
193*2d543d20SAndroid Build Coastguard Worker 				current_conf->save_linked = 0;
194*2d543d20SAndroid Build Coastguard Worker 			else {
195*2d543d20SAndroid Build Coastguard Worker 				yyerror("save-linked can only be 'true' or 'false'");
196*2d543d20SAndroid Build Coastguard Worker 			}
197*2d543d20SAndroid Build Coastguard Worker 			free($3);
198*2d543d20SAndroid Build Coastguard Worker                 }
199*2d543d20SAndroid Build Coastguard Worker         ;
200*2d543d20SAndroid Build Coastguard Worker 
201*2d543d20SAndroid Build Coastguard Worker disable_genhomedircon: DISABLE_GENHOMEDIRCON '=' ARG {
202*2d543d20SAndroid Build Coastguard Worker 	if (strcasecmp($3, "false") == 0) {
203*2d543d20SAndroid Build Coastguard Worker 		current_conf->disable_genhomedircon = 0;
204*2d543d20SAndroid Build Coastguard Worker 	} else if (strcasecmp($3, "true") == 0) {
205*2d543d20SAndroid Build Coastguard Worker 		current_conf->disable_genhomedircon = 1;
206*2d543d20SAndroid Build Coastguard Worker 	} else {
207*2d543d20SAndroid Build Coastguard Worker 		yyerror("disable-genhomedircon can only be 'true' or 'false'");
208*2d543d20SAndroid Build Coastguard Worker 	}
209*2d543d20SAndroid Build Coastguard Worker 	free($3);
210*2d543d20SAndroid Build Coastguard Worker  }
211*2d543d20SAndroid Build Coastguard Worker 
212*2d543d20SAndroid Build Coastguard Worker usepasswd: USEPASSWD '=' ARG {
213*2d543d20SAndroid Build Coastguard Worker 	if (strcasecmp($3, "false") == 0) {
214*2d543d20SAndroid Build Coastguard Worker 		current_conf->usepasswd = 0;
215*2d543d20SAndroid Build Coastguard Worker 	} else if (strcasecmp($3, "true") == 0) {
216*2d543d20SAndroid Build Coastguard Worker 		current_conf->usepasswd = 1;
217*2d543d20SAndroid Build Coastguard Worker 	} else {
218*2d543d20SAndroid Build Coastguard Worker 		yyerror("usepasswd can only be 'true' or 'false'");
219*2d543d20SAndroid Build Coastguard Worker 	}
220*2d543d20SAndroid Build Coastguard Worker 	free($3);
221*2d543d20SAndroid Build Coastguard Worker  }
222*2d543d20SAndroid Build Coastguard Worker 
223*2d543d20SAndroid Build Coastguard Worker ignoredirs: IGNOREDIRS '=' ARG {
224*2d543d20SAndroid Build Coastguard Worker 	current_conf->ignoredirs = strdup($3);
225*2d543d20SAndroid Build Coastguard Worker 	free($3);
226*2d543d20SAndroid Build Coastguard Worker  }
227*2d543d20SAndroid Build Coastguard Worker 
228*2d543d20SAndroid Build Coastguard Worker handle_unknown: HANDLE_UNKNOWN '=' ARG {
229*2d543d20SAndroid Build Coastguard Worker 	if (strcasecmp($3, "deny") == 0) {
230*2d543d20SAndroid Build Coastguard Worker 		current_conf->handle_unknown = SEPOL_DENY_UNKNOWN;
231*2d543d20SAndroid Build Coastguard Worker 	} else if (strcasecmp($3, "reject") == 0) {
232*2d543d20SAndroid Build Coastguard Worker 		current_conf->handle_unknown = SEPOL_REJECT_UNKNOWN;
233*2d543d20SAndroid Build Coastguard Worker 	} else if (strcasecmp($3, "allow") == 0) {
234*2d543d20SAndroid Build Coastguard Worker 		current_conf->handle_unknown = SEPOL_ALLOW_UNKNOWN;
235*2d543d20SAndroid Build Coastguard Worker 	} else {
236*2d543d20SAndroid Build Coastguard Worker 		yyerror("handle-unknown can only be 'deny', 'reject' or 'allow'");
237*2d543d20SAndroid Build Coastguard Worker 	}
238*2d543d20SAndroid Build Coastguard Worker 	free($3);
239*2d543d20SAndroid Build Coastguard Worker  }
240*2d543d20SAndroid Build Coastguard Worker 
241*2d543d20SAndroid Build Coastguard Worker bzip_blocksize:  BZIP_BLOCKSIZE '=' ARG {
242*2d543d20SAndroid Build Coastguard Worker 	int blocksize = atoi($3);
243*2d543d20SAndroid Build Coastguard Worker 	free($3);
244*2d543d20SAndroid Build Coastguard Worker 	if (blocksize > 9)
245*2d543d20SAndroid Build Coastguard Worker 		yyerror("bzip-blocksize can only be in the range 0-9");
246*2d543d20SAndroid Build Coastguard Worker 	else
247*2d543d20SAndroid Build Coastguard Worker 		current_conf->bzip_blocksize = blocksize;
248*2d543d20SAndroid Build Coastguard Worker }
249*2d543d20SAndroid Build Coastguard Worker 
250*2d543d20SAndroid Build Coastguard Worker bzip_small:  BZIP_SMALL '=' ARG {
251*2d543d20SAndroid Build Coastguard Worker 	if (strcasecmp($3, "false") == 0) {
252*2d543d20SAndroid Build Coastguard Worker 		current_conf->bzip_small = 0;
253*2d543d20SAndroid Build Coastguard Worker 	} else if (strcasecmp($3, "true") == 0) {
254*2d543d20SAndroid Build Coastguard Worker 		current_conf->bzip_small = 1;
255*2d543d20SAndroid Build Coastguard Worker 	} else {
256*2d543d20SAndroid Build Coastguard Worker 		yyerror("bzip-small can only be 'true' or 'false'");
257*2d543d20SAndroid Build Coastguard Worker 	}
258*2d543d20SAndroid Build Coastguard Worker 	free($3);
259*2d543d20SAndroid Build Coastguard Worker }
260*2d543d20SAndroid Build Coastguard Worker 
261*2d543d20SAndroid Build Coastguard Worker remove_hll:  REMOVE_HLL'=' ARG {
262*2d543d20SAndroid Build Coastguard Worker 	if (strcasecmp($3, "false") == 0) {
263*2d543d20SAndroid Build Coastguard Worker 		current_conf->remove_hll = 0;
264*2d543d20SAndroid Build Coastguard Worker 	} else if (strcasecmp($3, "true") == 0) {
265*2d543d20SAndroid Build Coastguard Worker 		current_conf->remove_hll = 1;
266*2d543d20SAndroid Build Coastguard Worker 	} else {
267*2d543d20SAndroid Build Coastguard Worker 		yyerror("remove-hll can only be 'true' or 'false'");
268*2d543d20SAndroid Build Coastguard Worker 	}
269*2d543d20SAndroid Build Coastguard Worker 	free($3);
270*2d543d20SAndroid Build Coastguard Worker }
271*2d543d20SAndroid Build Coastguard Worker 
272*2d543d20SAndroid Build Coastguard Worker optimize_policy:  OPTIMIZE_POLICY '=' ARG {
273*2d543d20SAndroid Build Coastguard Worker 	if (strcasecmp($3, "false") == 0) {
274*2d543d20SAndroid Build Coastguard Worker 		current_conf->optimize_policy = 0;
275*2d543d20SAndroid Build Coastguard Worker 	} else if (strcasecmp($3, "true") == 0) {
276*2d543d20SAndroid Build Coastguard Worker 		current_conf->optimize_policy = 1;
277*2d543d20SAndroid Build Coastguard Worker 	} else {
278*2d543d20SAndroid Build Coastguard Worker 		yyerror("optimize-policy can only be 'true' or 'false'");
279*2d543d20SAndroid Build Coastguard Worker 	}
280*2d543d20SAndroid Build Coastguard Worker 	free($3);
281*2d543d20SAndroid Build Coastguard Worker }
282*2d543d20SAndroid Build Coastguard Worker 
283*2d543d20SAndroid Build Coastguard Worker command_block:
284*2d543d20SAndroid Build Coastguard Worker                 command_start external_opts BLOCK_END  {
285*2d543d20SAndroid Build Coastguard Worker                         if (new_external->path == NULL) {
286*2d543d20SAndroid Build Coastguard Worker                                 parse_errors++;
287*2d543d20SAndroid Build Coastguard Worker                                 YYABORT;
288*2d543d20SAndroid Build Coastguard Worker                         }
289*2d543d20SAndroid Build Coastguard Worker                 }
290*2d543d20SAndroid Build Coastguard Worker         ;
291*2d543d20SAndroid Build Coastguard Worker 
292*2d543d20SAndroid Build Coastguard Worker command_start:
293*2d543d20SAndroid Build Coastguard Worker                 LOAD_POLICY_START {
294*2d543d20SAndroid Build Coastguard Worker                         semanage_conf_external_prog_destroy(current_conf->load_policy);
295*2d543d20SAndroid Build Coastguard Worker                         current_conf->load_policy = NULL;
296*2d543d20SAndroid Build Coastguard Worker                         if (new_external_prog(&current_conf->load_policy) == -1) {
297*2d543d20SAndroid Build Coastguard Worker                                 parse_errors++;
298*2d543d20SAndroid Build Coastguard Worker                                 YYABORT;
299*2d543d20SAndroid Build Coastguard Worker                         }
300*2d543d20SAndroid Build Coastguard Worker                 }
301*2d543d20SAndroid Build Coastguard Worker         |       SETFILES_START {
302*2d543d20SAndroid Build Coastguard Worker                         semanage_conf_external_prog_destroy(current_conf->setfiles);
303*2d543d20SAndroid Build Coastguard Worker                         current_conf->setfiles = NULL;
304*2d543d20SAndroid Build Coastguard Worker                         if (new_external_prog(&current_conf->setfiles) == -1) {
305*2d543d20SAndroid Build Coastguard Worker                                 parse_errors++;
306*2d543d20SAndroid Build Coastguard Worker                                 YYABORT;
307*2d543d20SAndroid Build Coastguard Worker                         }
308*2d543d20SAndroid Build Coastguard Worker                 }
309*2d543d20SAndroid Build Coastguard Worker         |       SEFCONTEXT_COMPILE_START {
310*2d543d20SAndroid Build Coastguard Worker                         semanage_conf_external_prog_destroy(current_conf->sefcontext_compile);
311*2d543d20SAndroid Build Coastguard Worker                         current_conf->sefcontext_compile = NULL;
312*2d543d20SAndroid Build Coastguard Worker                         if (new_external_prog(&current_conf->sefcontext_compile) == -1) {
313*2d543d20SAndroid Build Coastguard Worker                                 parse_errors++;
314*2d543d20SAndroid Build Coastguard Worker                                 YYABORT;
315*2d543d20SAndroid Build Coastguard Worker                         }
316*2d543d20SAndroid Build Coastguard Worker                 }
317*2d543d20SAndroid Build Coastguard Worker         ;
318*2d543d20SAndroid Build Coastguard Worker 
319*2d543d20SAndroid Build Coastguard Worker verify_block:   verify_start external_opts BLOCK_END  {
320*2d543d20SAndroid Build Coastguard Worker                         if (new_external->path == NULL) {
321*2d543d20SAndroid Build Coastguard Worker                                 parse_errors++;
322*2d543d20SAndroid Build Coastguard Worker                                 YYABORT;
323*2d543d20SAndroid Build Coastguard Worker                         }
324*2d543d20SAndroid Build Coastguard Worker                 }
325*2d543d20SAndroid Build Coastguard Worker         ;
326*2d543d20SAndroid Build Coastguard Worker 
327*2d543d20SAndroid Build Coastguard Worker verify_start:   verify_start_tok {
328*2d543d20SAndroid Build Coastguard Worker                         if ($1 == -1) {
329*2d543d20SAndroid Build Coastguard Worker                                 parse_errors++;
330*2d543d20SAndroid Build Coastguard Worker                                 YYABORT;
331*2d543d20SAndroid Build Coastguard Worker                         }
332*2d543d20SAndroid Build Coastguard Worker                 }
333*2d543d20SAndroid Build Coastguard Worker         ;
334*2d543d20SAndroid Build Coastguard Worker 
335*2d543d20SAndroid Build Coastguard Worker verify_start_tok: VERIFY_MOD_START  {$$ = new_external_prog(&current_conf->mod_prog);}
336*2d543d20SAndroid Build Coastguard Worker         |       VERIFY_LINKED_START {$$ = new_external_prog(&current_conf->linked_prog);}
337*2d543d20SAndroid Build Coastguard Worker         |       VERIFY_KERNEL_START {$$ = new_external_prog(&current_conf->kernel_prog);}
338*2d543d20SAndroid Build Coastguard Worker         ;
339*2d543d20SAndroid Build Coastguard Worker 
340*2d543d20SAndroid Build Coastguard Worker external_opts:  external_opt external_opts
341*2d543d20SAndroid Build Coastguard Worker         |       /* empty */
342*2d543d20SAndroid Build Coastguard Worker         ;
343*2d543d20SAndroid Build Coastguard Worker 
344*2d543d20SAndroid Build Coastguard Worker external_opt:   PROG_PATH '=' ARG  { PASSIGN(new_external->path, $3); }
345*2d543d20SAndroid Build Coastguard Worker         |       PROG_ARGS '=' ARG  { PASSIGN(new_external->args, $3); }
346*2d543d20SAndroid Build Coastguard Worker         ;
347*2d543d20SAndroid Build Coastguard Worker 
348*2d543d20SAndroid Build Coastguard Worker %%
349*2d543d20SAndroid Build Coastguard Worker 
350*2d543d20SAndroid Build Coastguard Worker static int semanage_conf_init(semanage_conf_t * conf)
351*2d543d20SAndroid Build Coastguard Worker {
352*2d543d20SAndroid Build Coastguard Worker 	conf->store_type = SEMANAGE_CON_DIRECT;
353*2d543d20SAndroid Build Coastguard Worker 	conf->store_path = strdup(basename(selinux_policy_root()));
354*2d543d20SAndroid Build Coastguard Worker 	conf->ignoredirs = NULL;
355*2d543d20SAndroid Build Coastguard Worker 	conf->store_root_path = strdup("/var/lib/selinux");
356*2d543d20SAndroid Build Coastguard Worker 	conf->compiler_directory_path = strdup("/usr/libexec/selinux/hll");
357*2d543d20SAndroid Build Coastguard Worker 	conf->policyvers = sepol_policy_kern_vers_max();
358*2d543d20SAndroid Build Coastguard Worker 	conf->target_platform = SEPOL_TARGET_SELINUX;
359*2d543d20SAndroid Build Coastguard Worker 	conf->expand_check = 1;
360*2d543d20SAndroid Build Coastguard Worker 	conf->handle_unknown = -1;
361*2d543d20SAndroid Build Coastguard Worker 	conf->usepasswd = 1;
362*2d543d20SAndroid Build Coastguard Worker 	conf->file_mode = 0644;
363*2d543d20SAndroid Build Coastguard Worker 	conf->bzip_blocksize = 9;
364*2d543d20SAndroid Build Coastguard Worker 	conf->bzip_small = 0;
365*2d543d20SAndroid Build Coastguard Worker 	conf->ignore_module_cache = 0;
366*2d543d20SAndroid Build Coastguard Worker 	conf->remove_hll = 0;
367*2d543d20SAndroid Build Coastguard Worker 	conf->optimize_policy = 0;
368*2d543d20SAndroid Build Coastguard Worker 
369*2d543d20SAndroid Build Coastguard Worker 	conf->save_previous = 0;
370*2d543d20SAndroid Build Coastguard Worker 	conf->save_linked = 0;
371*2d543d20SAndroid Build Coastguard Worker 
372*2d543d20SAndroid Build Coastguard Worker 	if ((conf->load_policy =
373*2d543d20SAndroid Build Coastguard Worker 	     calloc(1, sizeof(*(current_conf->load_policy)))) == NULL) {
374*2d543d20SAndroid Build Coastguard Worker 		return -1;
375*2d543d20SAndroid Build Coastguard Worker 	}
376*2d543d20SAndroid Build Coastguard Worker 
377*2d543d20SAndroid Build Coastguard Worker 	if (access("/sbin/load_policy", X_OK) == 0) {
378*2d543d20SAndroid Build Coastguard Worker 		conf->load_policy->path = strdup("/sbin/load_policy");
379*2d543d20SAndroid Build Coastguard Worker 	} else {
380*2d543d20SAndroid Build Coastguard Worker 		conf->load_policy->path = strdup("/usr/sbin/load_policy");
381*2d543d20SAndroid Build Coastguard Worker 	}
382*2d543d20SAndroid Build Coastguard Worker 	if (conf->load_policy->path == NULL) {
383*2d543d20SAndroid Build Coastguard Worker 		return -1;
384*2d543d20SAndroid Build Coastguard Worker 	}
385*2d543d20SAndroid Build Coastguard Worker 	conf->load_policy->args = NULL;
386*2d543d20SAndroid Build Coastguard Worker 
387*2d543d20SAndroid Build Coastguard Worker 	if ((conf->setfiles =
388*2d543d20SAndroid Build Coastguard Worker 	     calloc(1, sizeof(*(current_conf->setfiles)))) == NULL) {
389*2d543d20SAndroid Build Coastguard Worker 		return -1;
390*2d543d20SAndroid Build Coastguard Worker 	}
391*2d543d20SAndroid Build Coastguard Worker 	if (access("/sbin/setfiles", X_OK) == 0) {
392*2d543d20SAndroid Build Coastguard Worker 		conf->setfiles->path = strdup("/sbin/setfiles");
393*2d543d20SAndroid Build Coastguard Worker 	} else {
394*2d543d20SAndroid Build Coastguard Worker 		conf->setfiles->path = strdup("/usr/sbin/setfiles");
395*2d543d20SAndroid Build Coastguard Worker 	}
396*2d543d20SAndroid Build Coastguard Worker 	if ((conf->setfiles->path == NULL) ||
397*2d543d20SAndroid Build Coastguard Worker 	    (conf->setfiles->args = strdup("-q -c $@ $<")) == NULL) {
398*2d543d20SAndroid Build Coastguard Worker 		return -1;
399*2d543d20SAndroid Build Coastguard Worker 	}
400*2d543d20SAndroid Build Coastguard Worker 
401*2d543d20SAndroid Build Coastguard Worker 	if ((conf->sefcontext_compile =
402*2d543d20SAndroid Build Coastguard Worker 	     calloc(1, sizeof(*(current_conf->sefcontext_compile)))) == NULL) {
403*2d543d20SAndroid Build Coastguard Worker 		return -1;
404*2d543d20SAndroid Build Coastguard Worker 	}
405*2d543d20SAndroid Build Coastguard Worker 	if (access("/sbin/sefcontext_compile", X_OK) == 0) {
406*2d543d20SAndroid Build Coastguard Worker 		conf->sefcontext_compile->path = strdup("/sbin/sefcontext_compile");
407*2d543d20SAndroid Build Coastguard Worker 	} else {
408*2d543d20SAndroid Build Coastguard Worker 		conf->sefcontext_compile->path = strdup("/usr/sbin/sefcontext_compile");
409*2d543d20SAndroid Build Coastguard Worker 	}
410*2d543d20SAndroid Build Coastguard Worker 	if ((conf->sefcontext_compile->path == NULL) ||
411*2d543d20SAndroid Build Coastguard Worker 	    (conf->sefcontext_compile->args = strdup("$@")) == NULL) {
412*2d543d20SAndroid Build Coastguard Worker 		return -1;
413*2d543d20SAndroid Build Coastguard Worker 	}
414*2d543d20SAndroid Build Coastguard Worker 
415*2d543d20SAndroid Build Coastguard Worker 	return 0;
416*2d543d20SAndroid Build Coastguard Worker }
417*2d543d20SAndroid Build Coastguard Worker 
418*2d543d20SAndroid Build Coastguard Worker /* Parse a libsemanage configuration file.  THIS FUNCTION IS NOT
419*2d543d20SAndroid Build Coastguard Worker  * THREAD-SAFE!	 Return a newly allocated semanage_conf_t *.  If the
420*2d543d20SAndroid Build Coastguard Worker  * configuration file could be read, parse it; otherwise rely upon
421*2d543d20SAndroid Build Coastguard Worker  * default values.  If the file could not be parsed correctly or if
422*2d543d20SAndroid Build Coastguard Worker  * out of memory return NULL.
423*2d543d20SAndroid Build Coastguard Worker  */
semanage_conf_parse(const char * config_filename)424*2d543d20SAndroid Build Coastguard Worker semanage_conf_t *semanage_conf_parse(const char *config_filename)
425*2d543d20SAndroid Build Coastguard Worker {
426*2d543d20SAndroid Build Coastguard Worker 	if ((current_conf = calloc(1, sizeof(*current_conf))) == NULL) {
427*2d543d20SAndroid Build Coastguard Worker 		return NULL;
428*2d543d20SAndroid Build Coastguard Worker 	}
429*2d543d20SAndroid Build Coastguard Worker 	if (semanage_conf_init(current_conf) == -1) {
430*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
431*2d543d20SAndroid Build Coastguard Worker 	}
432*2d543d20SAndroid Build Coastguard Worker 	if ((semanage_in = fopen(config_filename, "r")) == NULL) {
433*2d543d20SAndroid Build Coastguard Worker 		/* configuration file does not exist or could not be
434*2d543d20SAndroid Build Coastguard Worker 		 * read.  THIS IS NOT AN ERROR.  just rely on the
435*2d543d20SAndroid Build Coastguard Worker 		 * defaults. */
436*2d543d20SAndroid Build Coastguard Worker 		return current_conf;
437*2d543d20SAndroid Build Coastguard Worker 	}
438*2d543d20SAndroid Build Coastguard Worker 	parse_errors = 0;
439*2d543d20SAndroid Build Coastguard Worker 	semanage_parse();
440*2d543d20SAndroid Build Coastguard Worker 	fclose(semanage_in);
441*2d543d20SAndroid Build Coastguard Worker 	semanage_lex_destroy();
442*2d543d20SAndroid Build Coastguard Worker 	if (parse_errors != 0) {
443*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
444*2d543d20SAndroid Build Coastguard Worker 	}
445*2d543d20SAndroid Build Coastguard Worker 	return current_conf;
446*2d543d20SAndroid Build Coastguard Worker       cleanup:
447*2d543d20SAndroid Build Coastguard Worker 	semanage_conf_destroy(current_conf);
448*2d543d20SAndroid Build Coastguard Worker 	return NULL;
449*2d543d20SAndroid Build Coastguard Worker }
450*2d543d20SAndroid Build Coastguard Worker 
semanage_conf_external_prog_destroy(external_prog_t * ep)451*2d543d20SAndroid Build Coastguard Worker static void semanage_conf_external_prog_destroy(external_prog_t * ep)
452*2d543d20SAndroid Build Coastguard Worker {
453*2d543d20SAndroid Build Coastguard Worker 	while (ep != NULL) {
454*2d543d20SAndroid Build Coastguard Worker 		external_prog_t *next = ep->next;
455*2d543d20SAndroid Build Coastguard Worker 		free(ep->path);
456*2d543d20SAndroid Build Coastguard Worker 		free(ep->args);
457*2d543d20SAndroid Build Coastguard Worker 		free(ep);
458*2d543d20SAndroid Build Coastguard Worker 		ep = next;
459*2d543d20SAndroid Build Coastguard Worker 	}
460*2d543d20SAndroid Build Coastguard Worker }
461*2d543d20SAndroid Build Coastguard Worker 
462*2d543d20SAndroid Build Coastguard Worker /* Deallocates all space associated with a configuration struct,
463*2d543d20SAndroid Build Coastguard Worker  * including the pointer itself. */
semanage_conf_destroy(semanage_conf_t * conf)464*2d543d20SAndroid Build Coastguard Worker void semanage_conf_destroy(semanage_conf_t * conf)
465*2d543d20SAndroid Build Coastguard Worker {
466*2d543d20SAndroid Build Coastguard Worker 	if (conf != NULL) {
467*2d543d20SAndroid Build Coastguard Worker 		free(conf->store_path);
468*2d543d20SAndroid Build Coastguard Worker 		free(conf->ignoredirs);
469*2d543d20SAndroid Build Coastguard Worker 		free(conf->store_root_path);
470*2d543d20SAndroid Build Coastguard Worker 		free(conf->compiler_directory_path);
471*2d543d20SAndroid Build Coastguard Worker 		semanage_conf_external_prog_destroy(conf->load_policy);
472*2d543d20SAndroid Build Coastguard Worker 		semanage_conf_external_prog_destroy(conf->setfiles);
473*2d543d20SAndroid Build Coastguard Worker 		semanage_conf_external_prog_destroy(conf->sefcontext_compile);
474*2d543d20SAndroid Build Coastguard Worker 		semanage_conf_external_prog_destroy(conf->mod_prog);
475*2d543d20SAndroid Build Coastguard Worker 		semanage_conf_external_prog_destroy(conf->linked_prog);
476*2d543d20SAndroid Build Coastguard Worker 		semanage_conf_external_prog_destroy(conf->kernel_prog);
477*2d543d20SAndroid Build Coastguard Worker 		free(conf);
478*2d543d20SAndroid Build Coastguard Worker 	}
479*2d543d20SAndroid Build Coastguard Worker }
480*2d543d20SAndroid Build Coastguard Worker 
semanage_error(const char * msg)481*2d543d20SAndroid Build Coastguard Worker int semanage_error(const char *msg)
482*2d543d20SAndroid Build Coastguard Worker {
483*2d543d20SAndroid Build Coastguard Worker 	fprintf(stderr, "error parsing semanage configuration file: %s\n", msg);
484*2d543d20SAndroid Build Coastguard Worker 	parse_errors++;
485*2d543d20SAndroid Build Coastguard Worker 	return 0;
486*2d543d20SAndroid Build Coastguard Worker }
487*2d543d20SAndroid Build Coastguard Worker 
488*2d543d20SAndroid Build Coastguard Worker /* Take the string argument for a module store.	 If it is exactly the
489*2d543d20SAndroid Build Coastguard Worker  * word "direct" then have libsemanage directly manipulate the module
490*2d543d20SAndroid Build Coastguard Worker  * store. The policy path will default to the active policy directory.
491*2d543d20SAndroid Build Coastguard Worker  * Otherwise if it begins with a forward slash interpret it as
492*2d543d20SAndroid Build Coastguard Worker  * an absolute path to a named socket, to which a policy server is
493*2d543d20SAndroid Build Coastguard Worker  * listening on the other end.	Otherwise treat it as the host name to
494*2d543d20SAndroid Build Coastguard Worker  * an external server; if there is a colon in the name then everything
495*2d543d20SAndroid Build Coastguard Worker  * after gives a port number.  The default port number is 4242.
496*2d543d20SAndroid Build Coastguard Worker  * Returns 0 on success, -1 if out of memory, -2 if a port number is
497*2d543d20SAndroid Build Coastguard Worker  * illegal.
498*2d543d20SAndroid Build Coastguard Worker  */
parse_module_store(char * arg)499*2d543d20SAndroid Build Coastguard Worker static int parse_module_store(char *arg)
500*2d543d20SAndroid Build Coastguard Worker {
501*2d543d20SAndroid Build Coastguard Worker 	/* arg is already a strdup()ed copy of yytext */
502*2d543d20SAndroid Build Coastguard Worker 	if (arg == NULL) {
503*2d543d20SAndroid Build Coastguard Worker 		return -1;
504*2d543d20SAndroid Build Coastguard Worker 	}
505*2d543d20SAndroid Build Coastguard Worker 	free(current_conf->store_path);
506*2d543d20SAndroid Build Coastguard Worker 	if (strcmp(arg, "direct") == 0) {
507*2d543d20SAndroid Build Coastguard Worker 		current_conf->store_type = SEMANAGE_CON_DIRECT;
508*2d543d20SAndroid Build Coastguard Worker 		current_conf->store_path =
509*2d543d20SAndroid Build Coastguard Worker 		    strdup(basename(selinux_policy_root()));
510*2d543d20SAndroid Build Coastguard Worker 		current_conf->server_port = -1;
511*2d543d20SAndroid Build Coastguard Worker 	} else if (*arg == '/') {
512*2d543d20SAndroid Build Coastguard Worker 		current_conf->store_type = SEMANAGE_CON_POLSERV_LOCAL;
513*2d543d20SAndroid Build Coastguard Worker 		current_conf->store_path = strdup(arg);
514*2d543d20SAndroid Build Coastguard Worker 		current_conf->server_port = -1;
515*2d543d20SAndroid Build Coastguard Worker 	} else {
516*2d543d20SAndroid Build Coastguard Worker 		char *s;
517*2d543d20SAndroid Build Coastguard Worker 		current_conf->store_type = SEMANAGE_CON_POLSERV_REMOTE;
518*2d543d20SAndroid Build Coastguard Worker 		if ((s = strchr(arg, ':')) == NULL) {
519*2d543d20SAndroid Build Coastguard Worker 			current_conf->store_path = strdup(arg);
520*2d543d20SAndroid Build Coastguard Worker 			current_conf->server_port = 4242;
521*2d543d20SAndroid Build Coastguard Worker 		} else {
522*2d543d20SAndroid Build Coastguard Worker 			char *endptr;
523*2d543d20SAndroid Build Coastguard Worker 			*s = '\0';
524*2d543d20SAndroid Build Coastguard Worker 			current_conf->store_path = strdup(arg);
525*2d543d20SAndroid Build Coastguard Worker 			current_conf->server_port = strtol(s + 1, &endptr, 10);
526*2d543d20SAndroid Build Coastguard Worker 			if (*(s + 1) == '\0' || *endptr != '\0') {
527*2d543d20SAndroid Build Coastguard Worker 				return -2;
528*2d543d20SAndroid Build Coastguard Worker 			}
529*2d543d20SAndroid Build Coastguard Worker 		}
530*2d543d20SAndroid Build Coastguard Worker 	}
531*2d543d20SAndroid Build Coastguard Worker 	return 0;
532*2d543d20SAndroid Build Coastguard Worker }
533*2d543d20SAndroid Build Coastguard Worker 
parse_store_root_path(char * arg)534*2d543d20SAndroid Build Coastguard Worker static int parse_store_root_path(char *arg)
535*2d543d20SAndroid Build Coastguard Worker {
536*2d543d20SAndroid Build Coastguard Worker 	if (arg == NULL) {
537*2d543d20SAndroid Build Coastguard Worker 		return -1;
538*2d543d20SAndroid Build Coastguard Worker 	}
539*2d543d20SAndroid Build Coastguard Worker 
540*2d543d20SAndroid Build Coastguard Worker 	free(current_conf->store_root_path);
541*2d543d20SAndroid Build Coastguard Worker 	current_conf->store_root_path = strdup(arg);
542*2d543d20SAndroid Build Coastguard Worker 	return 0;
543*2d543d20SAndroid Build Coastguard Worker }
544*2d543d20SAndroid Build Coastguard Worker 
parse_compiler_path(char * arg)545*2d543d20SAndroid Build Coastguard Worker static int parse_compiler_path(char *arg)
546*2d543d20SAndroid Build Coastguard Worker {
547*2d543d20SAndroid Build Coastguard Worker 	if (arg == NULL) {
548*2d543d20SAndroid Build Coastguard Worker 		return -1;
549*2d543d20SAndroid Build Coastguard Worker 	}
550*2d543d20SAndroid Build Coastguard Worker 	free(current_conf->compiler_directory_path);
551*2d543d20SAndroid Build Coastguard Worker 	current_conf->compiler_directory_path = strdup(arg);
552*2d543d20SAndroid Build Coastguard Worker 	return 0;
553*2d543d20SAndroid Build Coastguard Worker }
554*2d543d20SAndroid Build Coastguard Worker 
555*2d543d20SAndroid Build Coastguard Worker /* Helper function; called whenever configuration file specifies
556*2d543d20SAndroid Build Coastguard Worker  * another external program.  Returns 0 on success, -1 if out of
557*2d543d20SAndroid Build Coastguard Worker  * memory.
558*2d543d20SAndroid Build Coastguard Worker  */
new_external_prog(external_prog_t ** chain)559*2d543d20SAndroid Build Coastguard Worker static int new_external_prog(external_prog_t ** chain)
560*2d543d20SAndroid Build Coastguard Worker {
561*2d543d20SAndroid Build Coastguard Worker 	if ((new_external = calloc(1, sizeof(*new_external))) == NULL) {
562*2d543d20SAndroid Build Coastguard Worker 		return -1;
563*2d543d20SAndroid Build Coastguard Worker 	}
564*2d543d20SAndroid Build Coastguard Worker 	/* hook this new external program to the end of the chain */
565*2d543d20SAndroid Build Coastguard Worker 	if (*chain == NULL) {
566*2d543d20SAndroid Build Coastguard Worker 		*chain = new_external;
567*2d543d20SAndroid Build Coastguard Worker 	} else {
568*2d543d20SAndroid Build Coastguard Worker 		external_prog_t *prog = *chain;
569*2d543d20SAndroid Build Coastguard Worker 		while (prog->next != NULL) {
570*2d543d20SAndroid Build Coastguard Worker 			prog = prog->next;
571*2d543d20SAndroid Build Coastguard Worker 		}
572*2d543d20SAndroid Build Coastguard Worker 		prog->next = new_external;
573*2d543d20SAndroid Build Coastguard Worker 	}
574*2d543d20SAndroid Build Coastguard Worker 	return 0;
575*2d543d20SAndroid Build Coastguard Worker }
576