diff --git a/parser/Makefile b/parser/Makefile index 5088806e1..5913ac0a0 100644 --- a/parser/Makefile +++ b/parser/Makefile @@ -111,7 +111,7 @@ EXTRA_CFLAGS += $(INCLUDE_APPARMOR) LEX_C_FILES = parser_lex.c YACC_C_FILES = parser_yacc.c parser_yacc.h -TESTS = tst_regex tst_misc tst_symtab tst_variable +TESTS = tst_regex tst_misc tst_symtab tst_variable tst_lib TEST_CFLAGS = $(EXTRA_CFLAGS) -DUNIT_TEST -Wno-unused-result TEST_OBJECTS = $(filter-out \ parser_lex.o \ @@ -262,6 +262,8 @@ af_names.h: cap_names.h: /usr/include/linux/capability.h echo "$(CAPABILITIES)" | LC_ALL=C sed -n -e "s/[ \\t]\\?CAP_\\([A-Z0-9_]\\+\\)/\{\"\\L\\1\", \\UCAP_\\1\},\\n/pg" > $@ +tst_lib: lib.c parser.h $(filter-out lib.o, ${TEST_OBJECTS}) + $(CXX) $(TEST_CFLAGS) -o $@ $< $(filter-out $(<:.c=.o), ${TEST_OBJECTS}) $(TEST_LDFLAGS) tst_%: parser_%.c parser.h $(filter-out parser_%.o, ${TEST_OBJECTS}) $(CXX) $(TEST_CFLAGS) -o $@ $< $(filter-out $(<:.c=.o), ${TEST_OBJECTS}) $(TEST_LDFLAGS) diff --git a/parser/lib.c b/parser/lib.c index 6f6f1109b..be645672d 100644 --- a/parser/lib.c +++ b/parser/lib.c @@ -29,6 +29,7 @@ #include #include +#include "lib.h" #include "parser.h" /** @@ -135,3 +136,387 @@ fail: return -1; } + +/** + * isodigit - test if a character is an octal digit + * @c: character to test + * + * Returns: true if an octal digit, else false + */ +bool isodigit(char c) +{ + return (c >= '0' && c <= '7') ? true : false; +} + +/* convert char character 0..9a..z into a number 0-35 + * + * Returns: digit value of character or -1 if character is invalid + */ +static int chrtoi(char c, int base) +{ + int val = -1; + + if (base < 2 || base > 36) + return -1; + + if (isdigit(c)) + val = c - '0'; + else if (isalpha(c) && isascii(c)) + val = tolower(c) - 'a' + 10; + + if (val >= base) + return -1; + + return val; +} + +/** + * strntol - convert a sequence of characters as a hex number + * @str: pointer to a string of character to convert + * @endptr: RETURNS: if not NULL, the first char after converted chars. + * @base: base of convertion + * @maxval: maximum value. don't consume next char if value will exceed @maxval + * @n: maximum number of characters to consume doing the conversion + * + * Returns: converted number. If there is no conversion 0 is returned and + * *@endptr = @str + * + * Not a complete replacement for strtol yet, Does not process base prefixes, + * nor +/- sign yet. + * + * - take the largest sequence of character that is in range of 0-@maxval + * - will consume the minimum of @maxlen or @base digits in @maxval + * - if there is not n valid characters for the base only the n-1 will be taken + * eg. for the sequence string 4z with base 16 only 4 will be taken as the + * hex number + */ +long strntol(const char *str, const char **endptr, int base, long maxval, + size_t n) +{ + long c, val = 0; + + if (base > 1 && base < 37) { + for (; n && (c = chrtoi(*str, base)) != -1; str++, n--) { + long tmp = (val * base) + c; + if (tmp > maxval) + break; + val = tmp; + } + } + + if (endptr) + *endptr = str; + + return val; +} + +/** + * strn_escseq - + * @pos: position of first character in esc sequence + * @chrs: list of exact return chars to support eg. \+ returns + instead of -1 + * @n: maximum length of string to processes + * + * Returns: character for escape sequence or -1 if an error + * + * pos will point to first character after esc sequence + * OR + * pos will point to first character where an error was discovered + * errors can be unrecognized esc character, octal, decimal, or hex + * character encoding with no valid number. eg. \xT + */ +int strn_escseq(const char **pos, const char *chrs, size_t n) +{ + const char *end; + long tmp; + + if (n < 1) + return -1; + + if (isodigit(**pos)) { + tmp = strntol(*pos, &end, 8, 255, min(3ul, n)); + if (tmp == 0 && end == *pos) { + /* this should never happen because of isodigit test */ + return -1; + } + *pos = end; + return tmp; + } + + char c = *(*pos)++; + switch(c) { + case '\\': + return '\\'; + case '"': + return '"'; + case 'd': + tmp = strntol(*pos, &end, 10, 255, min(3ul, n)); + if (tmp == 0 && end == *pos) { + /* \d no valid encoding */ + return -1; + } + *pos = end; + return tmp; + case 'x': + tmp = strntol(*pos, &end, 16, 255, min(2ul, n)); + if (tmp == 0 && end == *pos) { + /* \x no valid encoding */ + return -1; + } + *pos = end; + return tmp; + case 'a': + return '\a'; + case 'e': + return 033 /* ESC */; + case 'f': + return '\f'; + case 'n': + return '\n'; + case 'r': + return '\r'; + case 't': + return '\t'; + } + + if (strchr(chrs, c)) + return c; + + /* unsupported escap sequence, backup to return that char */ + pos--; + return -1; +} + +int str_escseq(const char **pos, const char *chrs) +{ + /* no len limit just use end of string, yes could use strlen(pos) */ + return strn_escseq(pos, chrs, SIZE_MAX); +} + +#ifdef UNIT_TEST + +#include "lib.h" +#include "parser.h" +#include "unit_test.h" + +static int test_oct(const char *str) +{ + const char *end; + long retval = strntol(str, &end, 8, 255, 3); + if (retval == 0 && str == end) + return -1; + return retval; +} + +static int test_dec(const char *str) +{ + const char *end; + long retval = strntol(str, &end, 10, 255, 3); + if (retval == 0 && str == end) + return -1; + return retval; +} + +static int test_hex(const char *str) +{ + const char *end; + long retval = strntol(str, &end, 16, 255, 2); + if (retval == 0 && str == end) + return -1; + return retval; +} + +int main(void) +{ + int rc = 0; + int retval; + + struct test_struct { + const char *test; /* test string */ + int expected; /* expected result */ + const char *msg; /* failure message */ + }; + + struct test_struct oct_tests[] = { + { "0a", 0, "oct conversion of \\0a failed" }, + { "00000003a", 0, "oct conversion of \\00000003a failed" }, + { "62", 50, "oct conversion of \\62 failed" }, + { "623", 50, "oct conversion of \\623 failed" }, + { "123", 83, "oct conversion of \\123 failed" }, + { "123;", 83, "oct conversion of \\123; failed" }, + { "2234", 147, "oct conversion of \\2234 failed" }, + { "xx", -1, "oct conversion of \\xx failed" }, + { NULL, 0, NULL } + }; + + struct test_struct dec_tests[] = { + { "0a", 0, "dec conversion of \\d0a failed" }, + { "00000003a", 0, "dec conversion of \\d00000003a failed" }, + { "62", 62, "dec conversion of \\d62 failed" }, + { "623", 62, "dec conversion of \\d623 failed" }, + { "132", 132, "dec conversion of \\d132 failed" }, + { "132UL", 132, "dec conversion of \\d132UL failed" }, + { "255", 255, "dec conversion of \\d255 failed" }, + { "256", 25, "dec conversion of \\d256 failed" }, + { "2234", 223, "dec conversion of \\d2234 failed" }, + { "xx", -1, "dec conversion of \\dxx failed" }, + { NULL, 0, NULL } + }; + + struct test_struct hex_tests[] = { + { "0", 0x0, "hex conversion of 0x0 failed" }, + { "0x1", 0x0, "hex conversion of 0x0x1 failed" }, + { "1x", 0x1, "hex conversion of 0x1x failed" }, + { "00", 0x0, "hex conversion of 0x00 failed" }, + { "00x", 0x0, "hex conversion of 0x00x failed" }, + { "01", 0x1, "hex conversion of 0x01 failed" }, + { "01x", 0x1, "hex conversion of 0x01x failed" }, + { "ab", 0xab, "hex conversion of 0xAb failed" }, + { "AB", 0xab, "hex conversion of 0xAB failed" }, + { "Ab", 0xab, "hex conversion of 0xAb failed" }, + { "aB", 0xab, "hex conversion of 0xaB failed" }, + { "4z", 0x4, "hex conversion of 0x4z failed" }, + { "123", 0x12, "hex conversion of 0x123 failed" }, + { "12M", 0x12, "hex conversion of 0x12M failed" }, + { "ff", 0xff, "hex conversion of 0x255 failed" }, + { "FF", 0xff, "hex conversion of 0x255 failed" }, + { "XX", -1, "hex conversion of 0xXX failed" }, + { NULL, 0, NULL } + }; + + struct test_struct escseq_tests[] = { + { "", -1, "escseq conversion of \"\" failed" }, + { "0a", 0, "escseq oct conversion of \\0a failed" }, + { "00000003a", 0, "escseq oct conversion of \\00000003a failed" }, + { "62", 50, "escseq oct conversion of \\62 failed" }, + { "623", 50, "escseq oct conversion of \\623 failed" }, + { "123", 83, "escseq oct conversion of \\123 failed" }, + { "123;", 83, "escseq oct conversion of \\123; failed" }, + { "2234", 147, "escseq oct conversion of \\2234 failed" }, + { "xx", -1, "escseq oct conversion of \\xx failed" }, + + { "d0a", 0, "escseq dec conversion of \\d0a failed" }, + { "d00000003a", 0, "escseq dec conversion of \\d00000003a failed" }, + { "d62", 62, "escseq dec conversion of \\d62 failed" }, + { "d623", 62, "escseq dec conversion of \\d623 failed" }, + { "d132", 132, "escseq dec conversion of \\d132 failed" }, + { "d132UL", 132, "escseq dec conversion of \\d132UL failed" }, + { "d255", 255, "escseq dec conversion of \\d255 failed" }, + { "d256", 25, "escseq dec conversion of \\d256 failed" }, + { "d2234", 223, "escseq dec conversion of \\d2234 failed" }, + { "dxx", -1, "escseq dec conversion of \\dxx failed" }, + + { "x0", 0x0, "escseq hex conversion of 0x0 failed" }, + { "x0x1", 0x0, "escseq hex conversion of 0x0x1 failed" }, + { "x1x", 0x1, "escseq hex conversion of 0x1x failed" }, + { "x00", 0x0, "escseq hex conversion of 0x00 failed" }, + { "x00x", 0x0, "escseq hex conversion of 0x00x failed" }, + { "x01", 0x1, "escseq hex conversion of 0x01 failed" }, + { "x01x", 0x1, "escseq hex conversion of 0x01x failed" }, + { "xab", 0xab, "escseq hex conversion of 0xAb failed" }, + { "xAB", 0xab, "escseq hex conversion of 0xAB failed" }, + { "xAb", 0xab, "escseq hex conversion of 0xAb failed" }, + { "xaB", 0xab, "escseq hex conversion of 0xaB failed" }, + { "x4z", 0x4, "escseq hex conversion of 0x4z failed" }, + { "x123", 0x12, "escseq hex conversion of 0x123 failed" }, + { "x12M", 0x12, "escseq hex conversion of 0x12M failed" }, + { "xff", 0xff, "escseq hex conversion of 0x255 failed" }, + { "xFF", 0xff, "escseq hex conversion of 0x255 failed" }, + { "xXX", -1, "escseq hex conversion of 0xXX failed" }, + + { "\\", '\\', "escseq '\\\\' failed" }, + { "\"", '"', "escseq '\\\"' failed" }, + { "a", '\a', "escseq '\\a' failed" }, + { "e", '\033', "escseq '\\e' failed" }, + { "f", '\f', "escseq '\\f' failed" }, + { "n", '\n', "escseq '\\n' failed" }, + { "r", '\r', "escseq '\\r' failed" }, + { "t", '\t', "escseq '\\t' failed" }, + { NULL, 0, NULL } + }; + + struct test_struct escseqextra_tests[] = { + { "+", '+', "escseq extra conversion of \\+ failed" }, + { "-", '-', "escseq conversion of \\- failed" }, + { "*", '*', "escseq conversion of \\* failed" }, + { "(", '(', "escseq conversion of \\( failed" }, + { ")", ')', "escseq conversion of \\) failed" }, + { "|", '|', "escseq conversion of \\| failed" }, + { ".", '.', "escseq conversion of \\. failed" }, + { "[", '[', "escseq conversion of \\[ failed" }, + { "]", ']', "escseq conversion of \\] failed" }, + { "^", '^', "escseq conversion of \\^ failed" }, + { NULL, 0, NULL } + }; + + /* test chrtoi */ + for (int base = -1; base < 38; base++) { + for (int c = 0; c < 256; c++) { + int expected; + int i = chrtoi(c, base); + if (base < 2 || base > 36 || !isascii(c) || !(isdigit(c) || isalpha(c))) + expected = -1; + else if (isdigit(c) && (c - '0') < base) + expected = c - '0'; + else if (isalpha(c) && (toupper(c) - 'A') + 10 < base) + expected = (toupper(c) - 'A') + 10; + else + expected = -1; + if (i != expected) +// printf(" chrtoi test: convert base %d '%c'(%d)\texpected %d\tresult: %d\n", base, c, c, expected, i); + MY_TEST(i == expected, "failed"); + } + } + + /* test strntol */ + for (struct test_struct *t = oct_tests; t->test; t++) { + retval = test_oct(t->test); +// printf(" oct test: %s\texpected %d\tresult: %d\n", t->test, t->expected, retval); + MY_TEST(retval == t->expected, t->msg); + } + + for (struct test_struct *t = dec_tests; t->test; t++) { + retval = test_dec(t->test); +// printf(" dec test: %s\texpected %d\tresult: %d\n", t->test, t->expected, retval); + MY_TEST(retval == t->expected, t->msg); + } + + for (struct test_struct *t = hex_tests; t->test; t++) { + retval = test_hex(t->test); +// printf(" hex test: %s\texpected %d\tresult: %d\n", t->test, t->expected, retval); + MY_TEST(retval == t->expected, t->msg); + } + + /* test strn_escseq */ + for (struct test_struct *t = escseq_tests; t->test; t++) { + const char *pos = t->test; + retval = strn_escseq(&pos, "", strlen(t->test)); +// printf(" strn_escseq test: %s\texpected %d\tresult: %d\n", t->test, t->expected, retval); + MY_TEST(retval == t->expected, t->msg); + } + + for (struct test_struct *t = escseqextra_tests; t->test; t++) { + const char *pos = t->test; + retval = strn_escseq(&pos, "", strlen(t->test)); +// printf(" strn_escseq test: %s\texpected %d\tresult: %d\n", t->test, t->expected, retval); + MY_TEST(retval == -1, t->msg); + pos = t->test; + retval = strn_escseq(&pos, "*+.|^-[]()", strlen(t->test)); + MY_TEST(retval == t->expected, t->msg); + } + + for (int c = 1; c < 256; c++) { + const char *pos; + char str[2] = " "; + if (strchr("01234567\\\"dxaefnrt", c)) + /* skip chars already tested above */ + continue; + str[0] = c; + pos = str; + retval = strn_escseq(&pos, "", 2); + MY_TEST(retval == -1, " strn_escseq: of unsupported char failed"); + } + + return rc; +} + +#endif /* UNIT_TEST */ diff --git a/parser/lib.h b/parser/lib.h index efa9b9c59..8f158663b 100644 --- a/parser/lib.h +++ b/parser/lib.h @@ -1,7 +1,20 @@ #ifndef __AA_LIB_H_ #define __AA_LIB_H_ +#include + +#define min(a,b) \ + ({ __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a < _b ? _a : _b; }) + int dirat_for_each(DIR *dir, const char *name, void *data, int (* cb)(DIR *, const char *, struct stat *, void *)); +bool isodigit(char c); +long strntol(const char *str, const char **endptr, int base, long maxval, + size_t n); +int strn_escseq(const char **pos, const char *chrs, size_t n); +int str_escseq(const char **pos, const char *chrs); + #endif /* __AA_LIB_H_ */ diff --git a/parser/libapparmor_re/Makefile b/parser/libapparmor_re/Makefile index b54586daa..df205b119 100644 --- a/parser/libapparmor_re/Makefile +++ b/parser/libapparmor_re/Makefile @@ -12,6 +12,8 @@ BISON := bison all : ${TARGET} +UNITTESTS = tst_parse + libapparmor_re.a: parse.o expr-tree.o hfa.o chfa.o aare_rules.o ar ${ARFLAGS} $@ $^ diff --git a/parser/libapparmor_re/parse.y b/parser/libapparmor_re/parse.y index b410437b7..1755a926f 100644 --- a/parser/libapparmor_re/parse.y +++ b/parser/libapparmor_re/parse.y @@ -155,29 +155,11 @@ cset_char : CHAR %% - -int octdigit(char c) -{ - if (c >= '0' && c <= '7') - return c - '0'; - return -1; -} - -int hexdigit(char c) -{ - if (c >= '0' && c <= '9') - return c - '0'; - else if (c >= 'A' && c <= 'F') - return 10 + c - 'A'; - else if (c >= 'a' && c <= 'f') - return 10 + c - 'a'; - else - return -1; -} +#include "../lib.h" int regex_lex(YYSTYPE *val, const char **pos) { - int c; + int tmp; val->c = **pos; switch(*(*pos)++) { @@ -190,67 +172,16 @@ int regex_lex(YYSTYPE *val, const char **pos) return *(*pos - 1); case '\\': - val->c = **pos; - switch(*(*pos)++) { - case '\0': - (*pos)--; - /* fall through */ - case '\\': + tmp = str_escseq(pos, "*+.|^-[]()"); + if (tmp == -1) + /* bad escape sequence, just skip it for now, that + * is output \\ followed by the invalid esc seq + * TODO: output error message + */ val->c = '\\'; - break; - - case '0': - val->c = 0; - if ((c = octdigit(**pos)) >= 0) { - val->c = c; - (*pos)++; - } - if ((c = octdigit(**pos)) >= 0) { - val->c = (val->c << 3) + c; - (*pos)++; - } - if ((c = octdigit(**pos)) >= 0) { - val->c = (val->c << 3) + c; - (*pos)++; - } - break; - - case 'x': - val->c = 0; - if ((c = hexdigit(**pos)) >= 0) { - val->c = c; - (*pos)++; - } - if ((c = hexdigit(**pos)) >= 0) { - val->c = (val->c << 4) + c; - (*pos)++; - } - break; - - case 'a': - val->c = '\a'; - break; - - case 'e': - val->c = 033 /* ESC */; - break; - - case 'f': - val->c = '\f'; - break; - - case 'n': - val->c = '\n'; - break; - - case 'r': - val->c = '\r'; - break; - - case 't': - val->c = '\t'; - break; - } + else + val->c = tmp; + break; } return CHAR; } diff --git a/parser/parser_misc.c b/parser/parser_misc.c index 1e6b32925..133f9edf1 100644 --- a/parser/parser_misc.c +++ b/parser/parser_misc.c @@ -39,6 +39,7 @@ #include #include +#include "lib.h" #include "parser.h" #include "profile.h" #include "parser_yacc.h" @@ -443,38 +444,48 @@ struct aa_network_entry *network_entry(const char *family, const char *type, char *processunquoted(const char *string, int len) { - char *tmp, *s; - int l; + char *buffer, *s; - tmp = (char *)malloc(len + 1); - if (!tmp) + s = buffer = (char *) malloc(len + 1); + if (!buffer) return NULL; - s = tmp; - for (l = 0; l < len; l++) { - if (string[l] == '\\' && l < len - 3) { - if (strchr("0123", string[l + 1]) && - strchr("0123456789", string[l + 2]) && - strchr("0123456789", string[l + 3])) { - /* three digit octal */ - int res = (string[l + 1] - '0') * 64 + - (string[l + 2] - '0') * 8 + - (string[l + 3] - '0'); - *s = res; - l += 3; - } else { - *s = string[l]; - } - s++; + while (len > 0) { + const char *pos = string + 1; + long c; + if (*string == '\\' && len > 1 && + (c = strn_escseq(&pos, "", len)) != -1) { + *s++ = c; + len -= pos - string; + string = pos; } else { - *s = string[l]; - s++; + /* either unescaped char OR + * unsupported escape sequence resulting in char being + * copied. + */ + *s++ = *string++; + len--; } } - *s = 0; - return tmp; + return buffer; +} + +/* rewrite a quoted string substituting escaped characters for the + * real thing. Strip the quotes around the string */ +char *processquoted(const char *string, int len) +{ + /* skip leading " and eat trailing " */ + if (*string == '"') { + len -= 2; + if (len < 0) /* start and end point to same quote */ + len = 0; + return processunquoted(string + 1, len); + } + + /* no quotes? treat as unquoted */ + return processunquoted(string, len); } char *processid(const char *string, int len) @@ -487,72 +498,6 @@ char *processid(const char *string, int len) return processunquoted(string, len); } -/* rewrite a quoted string substituting escaped characters for the - * real thing. Strip the quotes around the string */ - -char *processquoted(const char *string, int len) -{ - char *tmp, *s; - int l; - /* the result string will be shorter or equal in length */ - tmp = (char *)malloc(len + 1); - if (!tmp) - return NULL; - - s = tmp; - for (l = 1; l < len - 1; l++) { - if (string[l] == '\\' && l < len - 2) { - switch (string[l + 1]) { - case 't': - *s = '\t'; - l++; - break; - case 'n': - *s = '\n'; - l++; - break; - case 'r': - *s = '\r'; - l++; - break; - case '"': - *s = '"'; - l++; - break; - case '\\': - *s = '\\'; - l++; - break; - case '0': case '1': case '2': case '3': - if ((l < len - 4) && - strchr("0123456789", string[l + 2]) && - strchr("0123456789", string[l + 3])) { - /* three digit octal */ - int res = (string[l + 1] - '0') * 64 + - (string[l + 2] - '0') * 8 + - (string[l + 3] - '0'); - *s = res; - l += 3; - break; - } - /* fall through */ - default: - /* any unsupported escape sequence results in all - chars being copied. */ - *s = string[l]; - } - s++; - } else { - *s = string[l]; - s++; - } - } - - *s = 0; - - return tmp; -} - /* strip off surrounding delimiters around variables */ char *process_var(const char *var) { @@ -1270,27 +1215,82 @@ int test_str_to_boolean(void) int test_processunquoted(void) { int rc = 0; - const char *teststring, *processedstring; + const char *teststring; + const char *resultstring; teststring = ""; MY_TEST(strcmp(teststring, processunquoted(teststring, strlen(teststring))) == 0, "processunquoted on empty string"); + teststring = "\\1"; + resultstring = "\001"; + MY_TEST(strcmp(resultstring, processunquoted(teststring, strlen(teststring))) == 0, + "processunquoted on one digit octal"); + + teststring = "\\8"; + resultstring = "\\8"; + MY_TEST(strcmp(resultstring, processunquoted(teststring, strlen(teststring))) == 0, + "processunquoted on invalid octal digit \\8"); + + teststring = "\\18"; + resultstring = "\0018"; + MY_TEST(strcmp(resultstring, processunquoted(teststring, strlen(teststring))) == 0, + "processunquoted on one digit octal followed by invalid octal digit"); + + teststring = "\\1a"; + resultstring = "\001a"; + MY_TEST(strcmp(resultstring, processunquoted(teststring, strlen(teststring))) == 0, + "processunquoted on one digit octal followed by hex digit a"); + + teststring = "\\1z"; + resultstring = "\001z"; + MY_TEST(strcmp(resultstring, processunquoted(teststring, strlen(teststring))) == 0, + "processunquoted on one digit octal follow by char z"); + + teststring = "\\11"; + resultstring = "\011"; + MY_TEST(strcmp(resultstring, processunquoted(teststring, strlen(teststring))) == 0, + "processunquoted on two digit octal"); + + teststring = "\\118"; + resultstring = "\0118"; + MY_TEST(strcmp(resultstring, processunquoted(teststring, strlen(teststring))) == 0, + "processunquoted on two digit octal followed by invalid octal digit"); + + teststring = "\\11a"; + resultstring = "\011a"; + MY_TEST(strcmp(resultstring, processunquoted(teststring, strlen(teststring))) == 0, + "processunquoted on two digit octal followed by hex digit a"); + + teststring = "\\11z"; + resultstring = "\011z"; + MY_TEST(strcmp(resultstring, processunquoted(teststring, strlen(teststring))) == 0, + "processunquoted on two digit octal followed by char z"); + + teststring = "\\111"; + resultstring = "\111"; + MY_TEST(strcmp(resultstring, processunquoted(teststring, strlen(teststring))) == 0, + "processunquoted on three digit octal"); + + teststring = "\\378"; + resultstring = "\0378"; + MY_TEST(strcmp(resultstring, processunquoted(teststring, strlen(teststring))) == 0, + "processunquoted on three digit octal two large, taken as 2 digit octal plus trailing char"); + teststring = "123\\421123"; - MY_TEST(strcmp(teststring, processunquoted(teststring, strlen(teststring))) == 0, - "processunquoted on invalid octal"); + resultstring = "123\0421123"; + MY_TEST(strcmp(resultstring, processunquoted(teststring, strlen(teststring))) == 0, + "processunquoted on two character octal followed by valid octal digit \\421"); -/* Oh wow, our octal processing is busticated - FIXME teststring = "123\\109123"; - processedstring = "123\109123"; - MY_TEST(strcmp(processedstring, processunquoted(teststring, strlen(teststring))) == 0, - "processunquoted on octal 10"); + resultstring = "123\109123"; + MY_TEST(strcmp(resultstring, processunquoted(teststring, strlen(teststring))) == 0, + "processunquoted on octal 109"); - teststring = "123\\189123"; - processedstring = "123\189123"; - MY_TEST(strcmp(processedstring, processunquoted(teststring, strlen(teststring))) == 0, - "processunquoted on octal 10"); -*/ + teststring = "123\\1089123"; + resultstring = "123\1089123"; + MY_TEST(strcmp(resultstring, processunquoted(teststring, strlen(teststring))) == 0, + "processunquoted on octal 108"); return rc; } @@ -1377,19 +1377,30 @@ int test_processquoted(void) "processquoted on quoted octal \\176"); free(out); - /* yes, our octal processing is lame; patches accepted */ - teststring = "\"abc\\42defg\""; - processedstring = "abc\\42defg"; + teststring = "\"abc\\429defg\""; + processedstring = "abc\0429defg"; out = processquoted(teststring, strlen(teststring)); MY_TEST(strcmp(processedstring, out) == 0, - "processquoted passthrough quoted invalid octal \\42"); + "processquoted passthrough quoted invalid octal \\429"); free(out); - teststring = "\"abcdefg\\04\""; - processedstring = "abcdefg\\04"; + teststring = "\"abcdefg\\4\""; + processedstring = "abcdefg\004"; out = processquoted(teststring, strlen(teststring)); MY_TEST(strcmp(processedstring, out) == 0, - "processquoted passthrough quoted invalid trailing octal \\04"); + "processquoted passthrough quoted one digit trailing octal \\4"); + + teststring = "\"abcdefg\\04\""; + processedstring = "abcdefg\004"; + out = processquoted(teststring, strlen(teststring)); + MY_TEST(strcmp(processedstring, out) == 0, + "processquoted passthrough quoted two digit trailing octal \\04"); + + teststring = "\"abcdefg\\004\""; + processedstring = "abcdefg\004"; + out = processquoted(teststring, strlen(teststring)); + MY_TEST(strcmp(processedstring, out) == 0, + "processquoted passthrough quoted three digit trailing octal \\004"); free(out); return rc;