diff options
author | Greg Hudson <ghudson@mit.edu> | 2010-08-24 21:52:32 +0000 |
---|---|---|
committer | Greg Hudson <ghudson@mit.edu> | 2010-08-24 21:52:32 +0000 |
commit | c187732f09e477d9a611ad18bfa1739befb86074 (patch) | |
tree | 297982ef42c8a291f686a5bbe380b3ee2603ab2e /src/util | |
parent | 63a020538575070aeb66faf948467b877139384e (diff) | |
download | krb5-c187732f09e477d9a611ad18bfa1739befb86074.zip krb5-c187732f09e477d9a611ad18bfa1739befb86074.tar.gz krb5-c187732f09e477d9a611ad18bfa1739befb86074.tar.bz2 |
add profile include support
Add support for "include" and "includedir" directives in profile files.
See http://k5wiki.kerberos.org/wiki/Projects/Profile_Includes for more
details.
ticket: 6761
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@24253 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/util')
-rw-r--r-- | src/util/profile/prof_err.et | 8 | ||||
-rw-r--r-- | src/util/profile/prof_parse.c | 105 | ||||
-rw-r--r-- | src/util/profile/prof_test1 | 57 |
3 files changed, 156 insertions, 14 deletions
diff --git a/src/util/profile/prof_err.et b/src/util/profile/prof_err.et index af7801e..2384127 100644 --- a/src/util/profile/prof_err.et +++ b/src/util/profile/prof_err.et @@ -60,7 +60,13 @@ error_code PROF_EXISTS, "Section already exists" error_code PROF_BAD_BOOLEAN, "Invalid boolean value" error_code PROF_BAD_INTEGER, "Invalid integer value" +# +# new error codes added at end to avoid changing values +# error_code PROF_MAGIC_FILE_DATA, "Bad magic value in profile_file_data_t" - +error_code PROF_FAIL_INCLUDE_FILE, + "Included profile file could not be read" +error_code PROF_FAIL_INCLUDE_DIR, + "Included profile directory could not be read" end diff --git a/src/util/profile/prof_parse.c b/src/util/profile/prof_parse.c index 413c7df..1ed4484 100644 --- a/src/util/profile/prof_parse.c +++ b/src/util/profile/prof_parse.c @@ -1,6 +1,7 @@ /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ #include "prof_int.h" +#include <sys/types.h> #include <stdio.h> #include <string.h> #ifdef HAVE_STDLIB_H @@ -8,6 +9,7 @@ #endif #include <errno.h> #include <ctype.h> +#include <dirent.h> #define SECTION_SEP_CHAR '/' @@ -22,6 +24,8 @@ struct parse_state { struct profile_node *current_section; }; +static errcode_t parse_file(FILE *f, struct parse_state *state); + static char *skip_over_blanks(char *cp) { while (*cp && isspace((int) (*cp))) @@ -33,7 +37,7 @@ static void strip_line(char *line) { char *p = line + strlen(line); while (p > line && (p[-1] == '\n' || p[-1] == '\r')) - *p-- = 0; + *--p = 0; } static void parse_quoted_string(char *str) @@ -201,10 +205,76 @@ static errcode_t parse_std_line(char *line, struct parse_state *state) return 0; } +/* Parse lines from filename as if they were part of the profile file. */ +static errcode_t parse_include_file(char *filename, struct parse_state *state) +{ + FILE *fp; + errcode_t retval = 0; + + fp = fopen(filename, "r"); + if (fp == NULL) + return PROF_FAIL_INCLUDE_FILE; + retval = parse_file(fp, state); + fclose(fp); + return retval; +} + +/* Return non-zero if filename contains only alphanumeric characters and + * underscores. */ +static int valid_name(const char *filename) +{ + const char *p; + + for (p = filename; *p != '\0'; p++) { + if (!isalnum((unsigned char)*p) && *p != '-' && *p != '_') + return 0; + } + return 1; +} + +/* + * Parse lines from files in dirname as if they were part of the profile file. + * Only files with names consisting entirely of alphanumeric chracters and + * underscores are parsed, in order to avoid parsing editor backup files, + * .rpmsave files, and the like. + */ +static errcode_t parse_include_dir(char *dirname, struct parse_state *state) +{ + DIR *dir; + char *pathname; + errcode_t retval; + struct dirent *ent; + + dir = opendir(dirname); + if (dir == NULL) + return PROF_FAIL_INCLUDE_DIR; + while ((ent = readdir(dir)) != NULL) { + if (!valid_name(ent->d_name)) + continue; + if (asprintf(&pathname, "%s/%s", dirname, ent->d_name) < 0) + return ENOMEM; + retval = parse_include_file(pathname, state); + free(pathname); + if (retval) + return retval; + } + return 0; +} + static errcode_t parse_line(char *line, struct parse_state *state) { char *cp; + if (strncmp(line, "include", 7) == 0 && isspace(line[7])) { + cp = skip_over_blanks(line + 7); + strip_line(cp); + return parse_include_file(cp, state); + } + if (strncmp(line, "includedir", 10) == 0 && isspace(line[10])) { + cp = skip_over_blanks(line + 10); + strip_line(cp); + return parse_include_dir(cp, state); + } switch (state->state) { case STATE_INIT_COMMENT: if (line[0] != '[') @@ -221,29 +291,22 @@ static errcode_t parse_line(char *line, struct parse_state *state) return 0; } -errcode_t profile_parse_file(FILE *f, struct profile_node **root) +static errcode_t parse_file(FILE *f, struct parse_state *state) { #define BUF_SIZE 2048 char *bptr; errcode_t retval; - struct parse_state state; bptr = malloc (BUF_SIZE); if (!bptr) return ENOMEM; - retval = parse_init_state(&state); - if (retval) { - free (bptr); - return retval; - } while (!feof(f)) { if (fgets(bptr, BUF_SIZE, f) == NULL) break; #ifndef PROFILE_SUPPORTS_FOREIGN_NEWLINES - retval = parse_line(bptr, &state); + retval = parse_line(bptr, state); if (retval) { - profile_free_node(state.root_section); free (bptr); return retval; } @@ -286,9 +349,8 @@ errcode_t profile_parse_file(FILE *f, struct profile_node **root) /* parse_line modifies contents of p */ newp = p + strlen (p) + 1; - retval = parse_line (p, &state); + retval = parse_line (p, state); if (retval) { - profile_free_node(state.root_section); free (bptr); return retval; } @@ -298,12 +360,29 @@ errcode_t profile_parse_file(FILE *f, struct profile_node **root) } #endif } - *root = state.root_section; free (bptr); return 0; } +errcode_t profile_parse_file(FILE *f, struct profile_node **root) +{ + struct parse_state state; + errcode_t retval; + + *root = NULL; + retval = parse_init_state(&state); + if (retval) + return retval; + retval = parse_file(f, &state); + if (retval) { + profile_free_node(state.root_section); + return retval; + } + *root = state.root_section; + return 0; +} + /* * Return TRUE if the string begins or ends with whitespace */ diff --git a/src/util/profile/prof_test1 b/src/util/profile/prof_test1 index bd49012..dc08671 100644 --- a/src/util/profile/prof_test1 +++ b/src/util/profile/prof_test1 @@ -147,8 +147,65 @@ proc test3 {} { puts "OK: test3: Clearing relation and adding one entry yields correct count." } +# Exercise the include and includedir directives. +proc test4 {} { + global wd verbose + + # Test expected error message when including nonexistent file. + catch [file delete $wd/testinc.ini] + exec echo "include does-not-exist" >$wd/testinc.ini + catch { profile_init_path $wd/testinc.ini } err + if $verbose { puts "Got error message $err" } + if { $err ne "Included profile file could not be read" } { + puts stderr "Error: test4: Did not get expected error when including nonexistent file." + exit 1 + } + + # Test expected error message when including nonexistent directory. + catch [file delete $wd/testinc.ini] + exec echo "includedir does-not-exist" >$wd/testinc.ini + catch { profile_init_path $wd/testinc.ini } err + if $verbose { puts "Got error message $err" } + if { $err ne "Included profile directory could not be read" } { + puts stderr "Error: test4: Did not get expected error when including nonexistent directory." + exit 1 + } + + # Test including a file. + catch [file delete $wd/testinc.ini] + exec echo "include $wd/test2.ini" >$wd/testinc.ini + set p [profile_init_path $wd/testinc.ini] + set x [profile_get_values $p {{test section 1} bar}] + if $verbose { puts "Read $x from included profile" } + if { [lindex $x 0] ne "foo" } { + puts stderr "Error: test4: Did not get expected result from included profile." + exit 1 + } + profile_release $p + + # Test including a directory. (Put two copies of test2.ini inside + # it and check that we get two values for one of the variables.) + catch [file delete -force $wd/test_include_dir] + exec mkdir $wd/test_include_dir + exec cp $wd/test2.ini $wd/test_include_dir/a + exec cp $wd/test2.ini $wd/test_include_dir/b + catch [file delete $wd/testinc.ini] + exec echo "includedir $wd/test_include_dir" >$wd/testinc.ini + set p [profile_init_path $wd/testinc.ini] + set x [profile_get_values $p {{test section 1} bar}] + if $verbose { puts "Read $x from included directory" } + if { $x ne "foo foo" } { + puts stderr, "Error: test4: Did not get expected result from included directory." + exit 1 + } + profile_release $p + + puts "OK: test4: include and includedir directives" +} + test1 test2 test3 +test4 exit 0 |