1 #include "buffer.h"
2 #include "log.h"
3 #include "mod_ssi.h"
4 #include "mod_ssi_expr.h"
5 #include "mod_ssi_exprparser.h"
6 
7 #include <ctype.h>
8 #include <string.h>
9 
10 typedef struct {
11 	const char *input;
12 	size_t offset;
13 	size_t size;
14 
15 	int line_pos;
16 
17 	int in_key;
18 	int in_brace;
19 	int in_cond;
20 } ssi_tokenizer_t;
21 
ssi_val_init(void)22 ssi_val_t *ssi_val_init(void) {
23 	ssi_val_t *s;
24 
25 	s = calloc(1, sizeof(*s));
26 
27 	return s;
28 }
29 
ssi_val_free(ssi_val_t * s)30 void ssi_val_free(ssi_val_t *s) {
31 	if (s->str) buffer_free(s->str);
32 
33 	free(s);
34 }
35 
ssi_val_tobool(ssi_val_t * B)36 int ssi_val_tobool(ssi_val_t *B) {
37 	if (B->type == SSI_TYPE_STRING) {
38 		return B->str->used > 1 ? 1 : 0;
39 	} else {
40 		return B->bo;
41 	}
42 }
43 
ssi_expr_tokenizer(server * srv,connection * con,plugin_data * p,ssi_tokenizer_t * t,int * token_id,buffer * token)44 static int ssi_expr_tokenizer(server *srv, connection *con, plugin_data *p,
45 			      ssi_tokenizer_t *t, int *token_id, buffer *token) {
46 	int tid = 0;
47 	size_t i;
48 
49 	UNUSED(con);
50 
51 	for (tid = 0; tid == 0 && t->offset < t->size && t->input[t->offset] ; ) {
52 		char c = t->input[t->offset];
53 		data_string *ds;
54 
55 		switch (c) {
56 		case '=':
57 			tid = TK_EQ;
58 
59 			t->offset++;
60 			t->line_pos++;
61 
62 			buffer_copy_string_len(token, CONST_STR_LEN("(=)"));
63 
64 			break;
65 		case '>':
66 			if (t->input[t->offset + 1] == '=') {
67 				t->offset += 2;
68 				t->line_pos += 2;
69 
70 				tid = TK_GE;
71 
72 				buffer_copy_string_len(token, CONST_STR_LEN("(>=)"));
73 			} else {
74 				t->offset += 1;
75 				t->line_pos += 1;
76 
77 				tid = TK_GT;
78 
79 				buffer_copy_string_len(token, CONST_STR_LEN("(>)"));
80 			}
81 
82 			break;
83 		case '<':
84 			if (t->input[t->offset + 1] == '=') {
85 				t->offset += 2;
86 				t->line_pos += 2;
87 
88 				tid = TK_LE;
89 
90 				buffer_copy_string_len(token, CONST_STR_LEN("(<=)"));
91 			} else {
92 				t->offset += 1;
93 				t->line_pos += 1;
94 
95 				tid = TK_LT;
96 
97 				buffer_copy_string_len(token, CONST_STR_LEN("(<)"));
98 			}
99 
100 			break;
101 
102 		case '!':
103 			if (t->input[t->offset + 1] == '=') {
104 				t->offset += 2;
105 				t->line_pos += 2;
106 
107 				tid = TK_NE;
108 
109 				buffer_copy_string_len(token, CONST_STR_LEN("(!=)"));
110 			} else {
111 				t->offset += 1;
112 				t->line_pos += 1;
113 
114 				tid = TK_NOT;
115 
116 				buffer_copy_string_len(token, CONST_STR_LEN("(!)"));
117 			}
118 
119 			break;
120 		case '&':
121 			if (t->input[t->offset + 1] == '&') {
122 				t->offset += 2;
123 				t->line_pos += 2;
124 
125 				tid = TK_AND;
126 
127 				buffer_copy_string_len(token, CONST_STR_LEN("(&&)"));
128 			} else {
129 				log_error_write(srv, __FILE__, __LINE__, "sds",
130 						"pos:", t->line_pos,
131 						"missing second &");
132 				return -1;
133 			}
134 
135 			break;
136 		case '|':
137 			if (t->input[t->offset + 1] == '|') {
138 				t->offset += 2;
139 				t->line_pos += 2;
140 
141 				tid = TK_OR;
142 
143 				buffer_copy_string_len(token, CONST_STR_LEN("(||)"));
144 			} else {
145 				log_error_write(srv, __FILE__, __LINE__, "sds",
146 						"pos:", t->line_pos,
147 						"missing second |");
148 				return -1;
149 			}
150 
151 			break;
152 		case '\t':
153 		case ' ':
154 			t->offset++;
155 			t->line_pos++;
156 			break;
157 
158 		case '\'':
159 			/* search for the terminating " */
160 			for (i = 1; t->input[t->offset + i] && t->input[t->offset + i] != '\'';  i++);
161 
162 			if (t->input[t->offset + i]) {
163 				tid = TK_VALUE;
164 
165 				buffer_copy_string_len(token, t->input + t->offset + 1, i-1);
166 
167 				t->offset += i + 1;
168 				t->line_pos += i + 1;
169 			} else {
170 				/* ERROR */
171 
172 				log_error_write(srv, __FILE__, __LINE__, "sds",
173 						"pos:", t->line_pos,
174 						"missing closing quote");
175 
176 				return -1;
177 			}
178 
179 			break;
180 		case '(':
181 			t->offset++;
182 			t->in_brace++;
183 
184 			tid = TK_LPARAN;
185 
186 			buffer_copy_string_len(token, CONST_STR_LEN("("));
187 			break;
188 		case ')':
189 			t->offset++;
190 			t->in_brace--;
191 
192 			tid = TK_RPARAN;
193 
194 			buffer_copy_string_len(token, CONST_STR_LEN(")"));
195 			break;
196 		case '$':
197 			if (t->input[t->offset + 1] == '{') {
198 				for (i = 2; t->input[t->offset + i] && t->input[t->offset + i] != '}';  i++);
199 
200 				if (t->input[t->offset + i] != '}') {
201 					log_error_write(srv, __FILE__, __LINE__, "sds",
202 							"pos:", t->line_pos,
203 							"missing closing quote");
204 
205 					return -1;
206 				}
207 
208 				buffer_copy_string_len(token, t->input + t->offset + 2, i-3);
209 			} else {
210 				for (i = 1; isalpha(t->input[t->offset + i]) || t->input[t->offset + i] == '_';  i++);
211 
212 				buffer_copy_string_len(token, t->input + t->offset + 1, i-1);
213 			}
214 
215 			tid = TK_VALUE;
216 
217 			if (NULL != (ds = (data_string *)array_get_element(p->ssi_cgi_env, token->ptr))) {
218 				buffer_copy_string_buffer(token, ds->value);
219 			} else if (NULL != (ds = (data_string *)array_get_element(p->ssi_vars, token->ptr))) {
220 				buffer_copy_string_buffer(token, ds->value);
221 			} else {
222 				buffer_copy_string_len(token, CONST_STR_LEN(""));
223 			}
224 
225 			t->offset += i;
226 			t->line_pos += i;
227 
228 			break;
229 		default:
230 			for (i = 0; isgraph(t->input[t->offset + i]);  i++) {
231 				char d = t->input[t->offset + i];
232 				switch(d) {
233 				case ' ':
234 				case '\t':
235 				case ')':
236 				case '(':
237 				case '\'':
238 				case '=':
239 				case '!':
240 				case '<':
241 				case '>':
242 				case '&':
243 				case '|':
244 					break;
245 				}
246 			}
247 
248 			tid = TK_VALUE;
249 
250 			buffer_copy_string_len(token, t->input + t->offset, i);
251 
252 			t->offset += i;
253 			t->line_pos += i;
254 
255 			break;
256 		}
257 	}
258 
259 	if (tid) {
260 		*token_id = tid;
261 
262 		return 1;
263 	} else if (t->offset < t->size) {
264 		log_error_write(srv, __FILE__, __LINE__, "sds",
265 				"pos:", t->line_pos,
266 				"foobar");
267 	}
268 	return 0;
269 }
270 
ssi_eval_expr(server * srv,connection * con,plugin_data * p,const char * expr)271 int ssi_eval_expr(server *srv, connection *con, plugin_data *p, const char *expr) {
272 	ssi_tokenizer_t t;
273 	void *pParser;
274 	int token_id;
275 	buffer *token;
276 	ssi_ctx_t context;
277 	int ret;
278 
279 	t.input = expr;
280 	t.offset = 0;
281 	t.size = strlen(expr);
282 	t.line_pos = 1;
283 
284 	t.in_key = 1;
285 	t.in_brace = 0;
286 	t.in_cond = 0;
287 
288 	context.ok = 1;
289 	context.srv = srv;
290 
291 	/* default context */
292 
293 	pParser = ssiexprparserAlloc( malloc );
294 	token = buffer_init();
295 	while((1 == (ret = ssi_expr_tokenizer(srv, con, p, &t, &token_id, token))) && context.ok) {
296 		ssiexprparser(pParser, token_id, token, &context);
297 
298 		token = buffer_init();
299 	}
300 	ssiexprparser(pParser, 0, token, &context);
301 	ssiexprparserFree(pParser, free );
302 
303 	buffer_free(token);
304 
305 	if (ret == -1) {
306 		log_error_write(srv, __FILE__, __LINE__, "s",
307 				"expr parser failed");
308 		return -1;
309 	}
310 
311 	if (context.ok == 0) {
312 		log_error_write(srv, __FILE__, __LINE__, "sds",
313 				"pos:", t.line_pos,
314 				"parser failed somehow near here");
315 		return -1;
316 	}
317 #if 0
318 	log_error_write(srv, __FILE__, __LINE__, "ssd",
319 			"expr: ",
320 			expr,
321 			context.val.bo);
322 #endif
323 	return context.val.bo;
324 }
325