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