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