@@ -184,6 +184,8 @@ int expand_macros(modsec_rec *msr, msc_string *var, msre_rule *rule, apr_pool_t
184184 char * text_start = NULL , * next_text_start = NULL ;
185185 msc_string * part = NULL ;
186186 int i , offset = 0 ;
187+ msc_string * tvar = NULL ;
188+ msc_string * lasttvar = NULL ;
187189
188190 if (var -> value == NULL ) return 0 ;
189191
@@ -192,130 +194,161 @@ int expand_macros(modsec_rec *msr, msc_string *var, msre_rule *rule, apr_pool_t
192194 * no macros in the input data.
193195 */
194196
195- data = apr_pstrdup (mptmp , var -> value ); /* IMP1 Are we modifying data anywhere? */
196- arr = apr_array_make (mptmp , 16 , sizeof (msc_string * ));
197- if ((data == NULL )|| (arr == NULL )) return -1 ;
198-
199- text_start = next_text_start = data ;
197+ if (msr -> txcfg -> debuglog_level >= 9 ) {
198+ msr_log (msr , 9 , "Received macro to resolve: %s" , log_escape_nq_ex (mptmp , var -> value , var -> value_len ));
199+ }
200+ data = apr_pstrndup (mptmp , var -> value , var -> value_len ); /* IMP1 Are we modifying data anywhere? */
201+ text_start = data ;
202+ // first loop - try to find all %{..} patterns as it exists
203+ // start with the innermost one
204+ int loopcnt = 1 ;
200205 do {
201- text_start = next_text_start ;
202- p = strstr (text_start , "%" );
203- if (p != NULL ) {
204- char * var_name = NULL ;
205- char * var_value = NULL ;
206-
207- if ((* (p + 1 ) == '{' )&& (* (p + 2 ) != '\0' )) {
208- char * var_start = p + 2 ;
209-
210- t = var_start ;
211- while ((* t != '\0' )&& (* t != '}' )) t ++ ;
212- if (* t == '}' ) {
213- /* Named variable. */
214-
215- var_name = apr_pstrmemdup (mptmp , var_start , t - var_start );
216- q = strstr (var_name , "." );
217- if (q != NULL ) {
218- var_value = q + 1 ;
219- * q = '\0' ;
220- }
221-
222- next_text_start = t + 1 ; /* *t was '}' */
223- } else {
224- /* Warn about a possiblly forgotten '}' */
225- if (msr -> txcfg -> debuglog_level >= 9 ) {
226- msr_log (msr , 9 , "Warning: Possibly unterminated macro: \"%s\"" ,
227- log_escape_ex (mptmp , var_start - 2 , t - var_start + 2 ));
228- }
229-
230- next_text_start = t ; /* *t was '\0' */
206+ // try to find the last one '%{' seq
207+ char * last_open = NULL ;
208+ char * first_close = NULL ;
209+ while ((text_start = strstr (text_start , "%{" )) != NULL ) {
210+ last_open = text_start ;
211+ text_start += 2 ; // move to next possible '%{'
212+ }
213+ // check if we found a macro open
214+ // if yes, find the first close char
215+ if (last_open != NULL ) {
216+ first_close = strchr (last_open + 2 , '}' );
217+ if (first_close != NULL ) {
218+ // we have the macro's position, split the string into three pieces
219+ // here_starts_the_var_%{tx.macro}_last_part
220+ // ^------------------^
221+ // ^---------^
222+ // ^--------^
223+ // create an array to store parts
224+ arr = apr_array_make (mptmp , 16 , sizeof (msc_string * ));
225+
226+ // create a variable from the macro
227+ char * var_name = NULL ;
228+ char * var_value = NULL ;
229+ var_name = apr_pstrmemdup (mptmp , last_open + 2 , first_close - last_open - 2 );
230+ q = strstr (var_name , "." );
231+ if (q != NULL ) {
232+ var_value = q + 1 ;
233+ * q = '\0' ;
231234 }
232- }
233235
234- if (var_name != NULL ) {
235- char * my_error_msg = NULL ;
236- msre_var * var_generated = NULL ;
237- msre_var * var_resolved = NULL ;
238-
239- /* Add the text part before the macro to the array. */
240- part = (msc_string * )apr_pcalloc (mptmp , sizeof (msc_string ));
241- if (part == NULL ) return -1 ;
242- part -> value_len = p - text_start ;
243- part -> value = apr_pstrmemdup (mptmp , text_start , part -> value_len );
244- * (msc_string * * )apr_array_push (arr ) = part ;
245-
246- /* Resolve the macro and add that to the array. */
247- var_resolved = msre_create_var_ex (mptmp , msr -> modsecurity -> msre , var_name , var_value ,
248- msr , & my_error_msg );
249- if (var_resolved != NULL ) {
250- var_generated = generate_single_var (msr , var_resolved , NULL , rule , mptmp );
251- if (var_generated != NULL ) {
252- part = (msc_string * )apr_pcalloc (mptmp , sizeof (msc_string ));
253- if (part == NULL ) return -1 ;
254- part -> value_len = var_generated -> value_len ;
255- part -> value = (char * )var_generated -> value ;
236+ // resolve the macro
237+ if (var_name != NULL ) {
238+ char * my_error_msg = NULL ;
239+ msre_var * var_generated = NULL ;
240+ msre_var * var_resolved = NULL ;
241+
242+ /* Add the text part before the macro to the array. */
243+ part = (msc_string * )apr_pcalloc (mptmp , sizeof (msc_string ));
244+ if (part == NULL ) return -1 ;
245+ part -> value_len = last_open - data ;
246+ if (part -> value_len > 0 ) {
247+ part -> value = apr_pstrmemdup (mptmp , data , part -> value_len );
256248 * (msc_string * * )apr_array_push (arr ) = part ;
257249 if (msr -> txcfg -> debuglog_level >= 9 ) {
250+ msr_log (msr , 9 , "Macro's prefix in round #%d: %s" , loopcnt , log_escape_nq_ex (mptmp , part -> value , part -> value_len ));
251+ }
252+ }
253+
254+ /* Resolve the macro and add that to the array. */
255+ var_resolved = msre_create_var_ex (mptmp , msr -> modsecurity -> msre , var_name , var_value ,
256+ msr , & my_error_msg );
257+ if (var_resolved != NULL ) {
258+ var_generated = generate_single_var (msr , var_resolved , NULL , rule , mptmp );
259+ if (var_generated != NULL ) {
260+ part = (msc_string * )apr_pcalloc (mptmp , sizeof (msc_string ));
261+ if (part == NULL ) return -1 ;
262+ part -> value_len = var_generated -> value_len ;
263+ part -> value = (char * )var_generated -> value ;
264+ * (msc_string * * )apr_array_push (arr ) = part ;
258265 msr_log (msr , 9 , "Resolved macro %%{%s%s%s} to: %s" ,
259266 var_name ,
260267 (var_value ? "." : "" ),
261268 (var_value ? var_value : "" ),
262269 log_escape_nq_ex (mptmp , part -> value , part -> value_len ));
263270 }
271+ } else {
272+ if (msr -> txcfg -> debuglog_level >= 4 ) {
273+ msr_log (msr , 4 , "Failed to resolve macro %%{%s%s%s}: %s" ,
274+ var_name ,
275+ (var_value ? "." : "" ),
276+ (var_value ? var_value : "" ),
277+ my_error_msg );
278+ }
264279 }
265280 } else {
266- if (msr -> txcfg -> debuglog_level >= 4 ) {
267- msr_log (msr , 4 , "Failed to resolve macro %%{%s%s%s}: %s" ,
268- var_name ,
269- (var_value ? "." : "" ),
270- (var_value ? var_value : "" ),
271- my_error_msg );
272- }
281+ /* We could not identify a valid macro so add it as text.
282+ This part remained from previous implementation, probably it's not needed here,
283+ won't be executed ever */
284+ part = (msc_string * )apr_pcalloc (mptmp , sizeof (msc_string ));
285+ if (part == NULL ) return -1 ;
286+ part -> value_len = last_open - data + 1 ; /* len(text)+len("%") */
287+ part -> value = apr_pstrmemdup (mptmp , data , part -> value_len );
288+ * (msc_string * * )apr_array_push (arr ) = part ;
273289 }
274- } else {
275- /* We could not identify a valid macro so add it as text. */
290+
291+ // last part
276292 part = (msc_string * )apr_pcalloc (mptmp , sizeof (msc_string ));
277- if (part == NULL ) return -1 ;
278- part -> value_len = p - text_start + 1 ; /* len(text)+len("%") */
279- part -> value = apr_pstrmemdup (mptmp , text_start , part -> value_len );
280- * (msc_string * * )apr_array_push (arr ) = part ;
293+ part -> value = apr_pstrdup (mptmp , first_close + 1 );
294+ part -> value_len = strlen (part -> value );
295+ if (part -> value_len > 0 ) {
296+ * (msc_string * * )apr_array_push (arr ) = part ;
297+ if (msr -> txcfg -> debuglog_level >= 9 ) {
298+ msr_log (msr , 9 , "Macro's suffix in round #%d: %s" , loopcnt , log_escape_nq_ex (mptmp , part -> value , part -> value_len ));
299+ }
300+ }
301+
302+ if (arr -> nelts > 0 ) {
303+ tvar = apr_palloc (mptmp , sizeof (msc_string ));
304+ memset (tvar , '\0' , sizeof (msc_string ));
305+ /* Figure out the required size for the string. */
306+ tvar -> value_len = 0 ;
307+ for (i = 0 ; i < arr -> nelts ; i ++ ) {
308+ part = ((msc_string * * )arr -> elts )[i ];
309+ tvar -> value_len += part -> value_len ;
310+ }
281311
282- next_text_start = p + 1 ;
312+ /* Allocate the string. */
313+ tvar -> value = apr_palloc (msr -> mp , tvar -> value_len + 1 );
314+ if (tvar -> value == NULL ) return -1 ;
315+
316+ /* Combine the parts. */
317+ offset = 0 ;
318+ for (i = 0 ; i < arr -> nelts ; i ++ ) {
319+ if (part -> value_len > 0 ) {
320+ part = ((msc_string * * )arr -> elts )[i ];
321+ memcpy ((char * )(tvar -> value + offset ), part -> value , part -> value_len );
322+ offset += part -> value_len ;
323+ }
324+ }
325+ tvar -> value [offset ] = '\0' ;
326+ lasttvar = tvar ;
327+ data = apr_pstrdup (mptmp , tvar -> value );
328+ text_start = data ;
329+ }
330+ }
331+ else { // no close '}', can't resolve macro
332+ msr_log (msr , 9 , "Warning: Possibly unterminated macro: \"%s\"" ,
333+ log_escape_ex (mptmp , last_open , strlen (last_open )));
334+ text_start = NULL ;
335+ return -1 ;
283336 }
284- } else {
285- /* Text part. */
286- part = (msc_string * )apr_pcalloc (mptmp , sizeof (msc_string ));
287- part -> value = apr_pstrdup (mptmp , text_start );
288- part -> value_len = strlen (part -> value );
289- * (msc_string * * )apr_array_push (arr ) = part ;
290337 }
291- } while (p != NULL );
338+ else {
339+ // no other macro was found, exit from the loop
340+ text_start = NULL ;
341+ }
292342
293- /* If there's more than one member of the array that
294- * means there was at least one macro present. Combine
295- * text parts into a single string now.
296- */
297- if (arr -> nelts > 1 ) {
298- /* Figure out the required size for the string. */
299- var -> value_len = 0 ;
300- for (i = 0 ; i < arr -> nelts ; i ++ ) {
301- part = ((msc_string * * )arr -> elts )[i ];
302- var -> value_len += part -> value_len ;
303- }
304-
305- /* Allocate the string. */
306- var -> value = apr_palloc (msr -> mp , var -> value_len + 1 );
307- if (var -> value == NULL ) return -1 ;
308-
309- /* Combine the parts. */
310- offset = 0 ;
311- for (i = 0 ; i < arr -> nelts ; i ++ ) {
312- part = ((msc_string * * )arr -> elts )[i ];
313- memcpy ((char * )(var -> value + offset ), part -> value , part -> value_len );
314- offset += part -> value_len ;
315- }
316- var -> value [offset ] = '\0' ;
317- }
343+ } while (text_start != NULL );
318344
345+ if (lasttvar != NULL ) {
346+ msr_log (msr , 9 , "Resolved macro: '%s' to '%s'" ,
347+ var -> value ,
348+ log_escape_ex (mptmp , lasttvar -> value , lasttvar -> value_len ));
349+ var -> value_len = lasttvar -> value_len ;
350+ var -> value = apr_pstrndup (msr -> mp , lasttvar -> value , lasttvar -> value_len );
351+ }
319352 return 1 ;
320353}
321354
0 commit comments