diff options
Diffstat (limited to 'src/sp_config.c')
| -rw-r--r-- | src/sp_config.c | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/src/sp_config.c b/src/sp_config.c new file mode 100644 index 0000000..f73347d --- /dev/null +++ b/src/sp_config.c | |||
| @@ -0,0 +1,193 @@ | |||
| 1 | #include <errno.h> | ||
| 2 | #include <stdio.h> | ||
| 3 | #include <string.h> | ||
| 4 | |||
| 5 | #include "php_snuffleupagus.h" | ||
| 6 | |||
| 7 | ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus) | ||
| 8 | |||
| 9 | sp_config_tokens const sp_func[] = { | ||
| 10 | {.func = parse_unserialize, .token = SP_TOKEN_UNSERIALIZE_HMAC}, | ||
| 11 | {.func = parse_random, .token = SP_TOKEN_HARDEN_RANDOM}, | ||
| 12 | {.func = parse_disabled_functions, .token = SP_TOKEN_DISABLE_FUNC}, | ||
| 13 | {.func = parse_readonly_exec, .token = SP_TOKEN_READONLY_EXEC}, | ||
| 14 | {.func = parse_global_strict, .token = SP_TOKEN_GLOBAL_STRICT}, | ||
| 15 | {.func = parse_upload_validation, .token = SP_TOKEN_UPLOAD_VALIDATION}, | ||
| 16 | {.func = parse_cookie_encryption, .token = SP_TOKEN_COOKIE_ENCRYPTION}, | ||
| 17 | {.func = parse_global, .token = SP_TOKEN_GLOBAL}, | ||
| 18 | {.func = parse_auto_cookie_secure, .token = SP_TOKEN_AUTO_COOKIE_SECURE}, | ||
| 19 | {.func = parse_disable_xxe, .token = SP_TOKEN_DISABLE_XXE}, | ||
| 20 | {NULL, NULL}}; | ||
| 21 | |||
| 22 | /* Top level keyword parsing */ | ||
| 23 | |||
| 24 | static int parse_line(char *line) { | ||
| 25 | char *ptr = line; | ||
| 26 | |||
| 27 | while (*ptr == ' ' || *ptr == '\t') { | ||
| 28 | ++ptr; | ||
| 29 | } | ||
| 30 | |||
| 31 | if (!*ptr || *ptr == '#' || *ptr == ';') { | ||
| 32 | return 0; | ||
| 33 | } | ||
| 34 | |||
| 35 | if (strncmp(ptr, SP_TOKEN_BASE, strlen(SP_TOKEN_BASE))) { | ||
| 36 | sp_log_err("config", "Invalid configuration prefix for '%s'.", line); | ||
| 37 | return -1; | ||
| 38 | } | ||
| 39 | ptr += strlen(SP_TOKEN_BASE); | ||
| 40 | |||
| 41 | for (size_t i = 0; sp_func[i].func; i++) { | ||
| 42 | if (!strncmp(sp_func[i].token, ptr, strlen(sp_func[i].token))) { | ||
| 43 | return sp_func[i].func(ptr + strlen(sp_func[i].token)); | ||
| 44 | } | ||
| 45 | } | ||
| 46 | sp_log_err("config", "Invalid configuration section '%s'.", line); | ||
| 47 | return -1; | ||
| 48 | } | ||
| 49 | |||
| 50 | /* keyword parsing */ | ||
| 51 | int parse_empty(char *restrict line, char *restrict keyword, void *retval) { | ||
| 52 | *(bool *)retval = true; | ||
| 53 | return 0; | ||
| 54 | } | ||
| 55 | |||
| 56 | int parse_int(char *restrict line, char *restrict keyword, void *retval) { | ||
| 57 | size_t consumed = 0; | ||
| 58 | char *value = get_param(&consumed, line, SP_TYPE_INT, keyword); | ||
| 59 | if (value) { | ||
| 60 | sscanf(value, "%ud", (uint32_t *)retval); | ||
| 61 | pefree(value, 1); | ||
| 62 | return consumed; | ||
| 63 | } else { | ||
| 64 | sp_log_err("error", "%s) is expecting a valid integer.", keyword); | ||
| 65 | return -1; | ||
| 66 | } | ||
| 67 | } | ||
| 68 | |||
| 69 | int parse_php_type(char *restrict line, char *restrict keyword, void *retval) { | ||
| 70 | size_t consumed = 0; | ||
| 71 | char *value = get_param(&consumed, line, SP_TYPE_STR, keyword); | ||
| 72 | if (value) { | ||
| 73 | if (0 == strcasecmp("undef", value)) { | ||
| 74 | *(sp_php_type*)retval = SP_PHP_TYPE_UNDEF; | ||
| 75 | } else if (0 == strcasecmp("null", value)) { | ||
| 76 | *(sp_php_type*)retval = SP_PHP_TYPE_NULL; | ||
| 77 | } else if (0 == strcasecmp("true", value)) { | ||
| 78 | *(sp_php_type*)retval = SP_PHP_TYPE_TRUE; | ||
| 79 | } else if (0 == strcasecmp("false", value)) { | ||
| 80 | *(sp_php_type*)retval = SP_PHP_TYPE_FALSE; | ||
| 81 | } else if (0 == strcasecmp("long", value)) { | ||
| 82 | *(sp_php_type*)retval = SP_PHP_TYPE_LONG; | ||
| 83 | } else if (0 == strcasecmp("double", value)) { | ||
| 84 | *(sp_php_type*)retval = SP_PHP_TYPE_DOUBLE; | ||
| 85 | } else if (0 == strcasecmp("string", value)) { | ||
| 86 | *(sp_php_type*)retval = SP_PHP_TYPE_STRING; | ||
| 87 | } else if (0 == strcasecmp("array", value)) { | ||
| 88 | *(sp_php_type*)retval = SP_PHP_TYPE_ARRAY; | ||
| 89 | } else if (0 == strcasecmp("object", value)) { | ||
| 90 | *(sp_php_type*)retval = SP_PHP_TYPE_OBJECT; | ||
| 91 | } else if (0 == strcasecmp("resource", value)) { | ||
| 92 | *(sp_php_type*)retval = SP_PHP_TYPE_RESOURCE; | ||
| 93 | } else if (0 == strcasecmp("reference", value)) { | ||
| 94 | *(sp_php_type*)retval = SP_PHP_TYPE_REFERENCE; | ||
| 95 | } else { | ||
| 96 | pefree(value, 1); | ||
| 97 | sp_log_err("error", "%s) is expecting a valid php type ('false', 'true'," | ||
| 98 | " 'array'. 'object', 'long', 'double', 'null', 'resource', 'reference'," | ||
| 99 | " 'undef').", keyword); | ||
| 100 | return -1; | ||
| 101 | } | ||
| 102 | pefree(value, 1); | ||
| 103 | return consumed; | ||
| 104 | } else { | ||
| 105 | return -1; | ||
| 106 | } | ||
| 107 | } | ||
| 108 | |||
| 109 | int parse_str(char *restrict line, char *restrict keyword, void *retval) { | ||
| 110 | char *value = NULL; | ||
| 111 | |||
| 112 | size_t consumed = 0; | ||
| 113 | value = get_param(&consumed, line, SP_TYPE_STR, keyword); | ||
| 114 | if (value) { | ||
| 115 | *(char **)retval = value; | ||
| 116 | return consumed; | ||
| 117 | } | ||
| 118 | return -1; | ||
| 119 | } | ||
| 120 | |||
| 121 | int parse_cidr(char *restrict line, char *restrict keyword, void *retval) { | ||
| 122 | size_t consumed = 0; | ||
| 123 | char *value = get_param(&consumed, line, SP_TYPE_STR, keyword); | ||
| 124 | sp_cidr *cidr = pecalloc(sizeof(sp_cidr), 1, 1); | ||
| 125 | |||
| 126 | if (value) { | ||
| 127 | if (-1 == get_ip_and_cidr(value, cidr)) { | ||
| 128 | return -1; | ||
| 129 | } | ||
| 130 | *(sp_cidr **)retval = cidr; | ||
| 131 | return consumed; | ||
| 132 | } else { | ||
| 133 | sp_log_err("config", "%s doesn't contain a valid cidr.", line); | ||
| 134 | return -1; | ||
| 135 | } | ||
| 136 | } | ||
| 137 | |||
| 138 | int parse_regexp(char *restrict line, char *restrict keyword, void *retval) { | ||
| 139 | /* TODO: Do we want to use pcre_study? | ||
| 140 | * (http://www.pcre.org/original/doc/html/pcre_study.html) | ||
| 141 | * maybe not: http://sljit.sourceforge.net/pcre.html*/ | ||
| 142 | size_t consumed = 0; | ||
| 143 | char *value = get_param(&consumed, line, SP_TYPE_STR, keyword); | ||
| 144 | |||
| 145 | if (value) { | ||
| 146 | const char *pcre_error; | ||
| 147 | int pcre_error_offset; | ||
| 148 | pcre *compiled_re = pcre_compile(value, PCRE_CASELESS, &pcre_error, | ||
| 149 | &pcre_error_offset, NULL); | ||
| 150 | if (NULL == compiled_re) { | ||
| 151 | sp_log_err("config", "Failed to compile '%s': %s.", value, pcre_error); | ||
| 152 | } else { | ||
| 153 | *(pcre **)retval = compiled_re; | ||
| 154 | return consumed; | ||
| 155 | } | ||
| 156 | } | ||
| 157 | char *closing_paren = strchr(line, ')'); | ||
| 158 | if (NULL != closing_paren) { | ||
| 159 | closing_paren[0] = '\0'; | ||
| 160 | } | ||
| 161 | sp_log_err("config", "'%s)' is expecting a valid regexp, and not '%s'.", | ||
| 162 | keyword, line); | ||
| 163 | return -1; | ||
| 164 | } | ||
| 165 | |||
| 166 | int sp_parse_config(const char *conf_file) { | ||
| 167 | FILE *fd = fopen(conf_file, "r"); | ||
| 168 | char *lineptr = NULL; | ||
| 169 | size_t n = 0; | ||
| 170 | |||
| 171 | if (fd == NULL) { | ||
| 172 | sp_log_err("config", "Could not open configuration file %s : %s", conf_file, | ||
| 173 | strerror(errno)); | ||
| 174 | return FAILURE; | ||
| 175 | } | ||
| 176 | |||
| 177 | while (getline(&lineptr, &n, fd) > 0) { | ||
| 178 | /* We trash the terminal `\n`. This simplify the display of logs. */ | ||
| 179 | if (lineptr[strlen(lineptr) - 1] == '\n') { | ||
| 180 | lineptr[strlen(lineptr) - 1] = '\0'; | ||
| 181 | } | ||
| 182 | if (parse_line(lineptr) == -1) { | ||
| 183 | fclose(fd); | ||
| 184 | free(lineptr); | ||
| 185 | return FAILURE; | ||
| 186 | } | ||
| 187 | free(lineptr); | ||
| 188 | lineptr = NULL; | ||
| 189 | n = 0; | ||
| 190 | } | ||
| 191 | fclose(fd); | ||
| 192 | return SUCCESS; | ||
| 193 | } | ||
