summaryrefslogtreecommitdiff
path: root/src/sp_config.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sp_config.c')
-rw-r--r--src/sp_config.c193
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
7ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus)
8
9sp_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
24static 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 */
51int parse_empty(char *restrict line, char *restrict keyword, void *retval) {
52 *(bool *)retval = true;
53 return 0;
54}
55
56int 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
69int 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
109int 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
121int 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
138int 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
166int 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}