subst.c 10.3 KB
Newer Older
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1
2
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
Pierangelo Masarati's avatar
Pierangelo Masarati committed
3
 *
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
4
 * Copyright 2000-2020 The OpenLDAP Foundation.
Pierangelo Masarati's avatar
Pierangelo Masarati committed
5
6
 * All rights reserved.
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
7
8
9
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted only as authorized by the OpenLDAP
 * Public License.
Pierangelo Masarati's avatar
Pierangelo Masarati committed
10
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
11
12
13
14
15
16
17
18
 * A copy of this license is available in the file LICENSE in the
 * top-level directory of the distribution or, alternatively, at
 * <http://www.OpenLDAP.org/license.html>.
 */
/* ACKNOWLEDGEMENT:
 * This work was initially developed by Pierangelo Masarati for
 * inclusion in OpenLDAP Software.
 */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
19
20
21
22
23
24
25
26
27
28
29

#include <portable.h>

#include "rewrite-int.h"

/*
 * Compiles a substitution pattern
 */
struct rewrite_subst *
rewrite_subst_compile(
		struct rewrite_info *info,
30
		const char *str
Pierangelo Masarati's avatar
Pierangelo Masarati committed
31
32
33
)
{
	size_t subs_len;
34
	struct berval *subs = NULL, *tmps;
35
	struct rewrite_submatch *submatch = NULL, *tmpsm;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
36
37
38

	struct rewrite_subst *s = NULL;

39
	char *result, *begin, *p;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
40
41
42
	int nsub = 0, l;

	assert( info != NULL );
43
44
45
46
47
48
	assert( str != NULL );

	result = strdup( str );
	if ( result == NULL ) {
		return NULL;
	}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
49
50
51
52
53

	/*
	 * Take care of substitution string
	 */
	for ( p = begin = result, subs_len = 0; p[ 0 ] != '\0'; p++ ) {
54

Pierangelo Masarati's avatar
Pierangelo Masarati committed
55
		/*
56
		 * Keep only single escapes '%'
Pierangelo Masarati's avatar
Pierangelo Masarati committed
57
		 */
58
		if (  !IS_REWRITE_SUBMATCH_ESCAPE( p[ 0 ] ) ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
59
			continue;
60
		} 
61

62
		if (  IS_REWRITE_SUBMATCH_ESCAPE( p[ 1 ] ) ) {
63
64
			/* Pull &p[1] over p, including the trailing '\0' */
			AC_MEMCPY((char *)p, &p[ 1 ], strlen( p ) );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
65
66
67
			continue;
		}

68
		tmps = ( struct berval * )realloc( subs,
69
				sizeof( struct berval )*( nsub + 1 ) );
70
		if ( tmps == NULL ) {
71
			goto cleanup;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
72
		}
73
		subs = tmps;
74
75
76
77
78
79
80
81
82
83
		subs[ nsub ].bv_val = NULL;

		tmpsm = ( struct rewrite_submatch * )realloc( submatch,
				sizeof( struct rewrite_submatch )*( nsub + 1 ) );
		if ( tmpsm == NULL ) {
			goto cleanup;
		}
		submatch = tmpsm;
		submatch[ nsub ].ls_map = NULL;

Pierangelo Masarati's avatar
Pierangelo Masarati committed
84
85
86
87
88
89
90
		/*
		 * I think an `if l > 0' at runtime is better outside than
		 * inside a function call ...
		 */
		l = p - begin;
		if ( l > 0 ) {
			subs_len += l;
91
92
93
			subs[ nsub ].bv_len = l;
			subs[ nsub ].bv_val = malloc( l + 1 );
			if ( subs[ nsub ].bv_val == NULL ) {
94
				goto cleanup;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
95
			}
96
97
			AC_MEMCPY( subs[ nsub ].bv_val, begin, l );
			subs[ nsub ].bv_val[ l ] = '\0';
Pierangelo Masarati's avatar
Pierangelo Masarati committed
98
		} else {
99
100
			subs[ nsub ].bv_val = NULL;
			subs[ nsub ].bv_len = 0;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
101
102
103
104
105
		}
		
		/*
		 * Substitution pattern
		 */
106
		if ( isdigit( (unsigned char) p[ 1 ] ) ) {
107
			int d = p[ 1 ] - '0';
Pierangelo Masarati's avatar
Pierangelo Masarati committed
108
109
110
111

			/*
			 * Add a new value substitution scheme
			 */
112

113
			submatch[ nsub ].ls_submatch = d;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
114
115
116
117
118
119

			/*
			 * If there is no argument, use default
			 * (substitute substring as is)
			 */
			if ( p[ 2 ] != '{' ) {
120
				submatch[ nsub ].ls_type = 
Pierangelo Masarati's avatar
Pierangelo Masarati committed
121
					REWRITE_SUBMATCH_ASIS;
122
				submatch[ nsub ].ls_map = NULL;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
123
				begin = ++p + 1;
124

Pierangelo Masarati's avatar
Pierangelo Masarati committed
125
126
127
			} else {
				struct rewrite_map *map;

128
				submatch[ nsub ].ls_type =
Pierangelo Masarati's avatar
Pierangelo Masarati committed
129
130
131
					REWRITE_SUBMATCH_XMAP;

				map = rewrite_xmap_parse( info,
132
						p + 3, (const char **)&begin );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
133
				if ( map == NULL ) {
134
					goto cleanup;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
135
				}
136
				submatch[ nsub ].ls_map = map;
137
				p = begin - 1;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
138
139
140
141
142
143
144
145
			}

		/*
		 * Map with args ...
		 */
		} else if ( p[ 1 ] == '{' ) {
			struct rewrite_map *map;

146
147
			map = rewrite_map_parse( info, p + 2,
					(const char **)&begin );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
148
			if ( map == NULL ) {
149
				goto cleanup;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
150
151
152
153
154
155
			}
			p = begin - 1;

			/*
			 * Add a new value substitution scheme
			 */
156
			submatch[ nsub ].ls_type =
Pierangelo Masarati's avatar
Pierangelo Masarati committed
157
				REWRITE_SUBMATCH_MAP_W_ARG;
158
			submatch[ nsub ].ls_map = map;
159
160
161
162
163
164
165
166
167

		/*
		 * Escape '%' ...
		 */
		} else if ( p[ 1 ] == '%' ) {
			AC_MEMCPY( &p[ 1 ], &p[ 2 ], strlen( &p[ 1 ] ) );
			continue;

		} else {
168
			goto cleanup;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
169
		}
170
171

		nsub++;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
172
173
174
175
176
	}
	
	/*
	 * Last part of string
	 */
177
	tmps = (struct berval * )realloc( subs, sizeof( struct berval )*( nsub + 1 ) );
178
	if ( tmps == NULL ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
179
180
181
		/*
		 * XXX need to free the value subst stuff!
		 */
182
		free( subs );
183
		goto cleanup;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
184
	}
185
	subs = tmps;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
186
187
188
	l = p - begin;
	if ( l > 0 ) {
		subs_len += l;
189
190
		subs[ nsub ].bv_len = l;
		subs[ nsub ].bv_val = malloc( l + 1 );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
191
192
193
		if ( subs[ nsub ].bv_val == NULL ) {
			goto cleanup;
		}
194
195
		AC_MEMCPY( subs[ nsub ].bv_val, begin, l );
		subs[ nsub ].bv_val[ l ] = '\0';
Pierangelo Masarati's avatar
Pierangelo Masarati committed
196
	} else {
197
198
		subs[ nsub ].bv_val = NULL;
		subs[ nsub ].bv_len = 0;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
199
200
201
202
	}

	s = calloc( sizeof( struct rewrite_subst ), 1 );
	if ( s == NULL ) {
203
		goto cleanup;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
204
205
206
	}

	s->lt_subs_len = subs_len;
Howard Chu's avatar
Howard Chu committed
207
208
209
210
211
	s->lt_subs = subs;
	s->lt_num_submatch = nsub;
	s->lt_submatch = submatch;
	subs = NULL;
	submatch = NULL;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
212

213
cleanup:;
Howard Chu's avatar
Howard Chu committed
214
215
216
217
218
219
220
221
222
223
224
225
	if ( subs ) {
		for ( l=0; l<nsub; l++ ) {
			free( subs[nsub].bv_val );
		}
		free( subs );
	}
	if ( submatch ) {
		for ( l=0; l<nsub; l++ ) {
			free( submatch[nsub].ls_map );
		}
		free( submatch );
	}
226
227
	free( result );

Pierangelo Masarati's avatar
Pierangelo Masarati committed
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
	return s;
}

/*
 * Copies the match referred to by submatch and fetched in string by match.
 * Helper for rewrite_rule_apply.
 */
static int
submatch_copy(
		struct rewrite_submatch *submatch,
		const char *string,
		const regmatch_t *match,
		struct berval *val
)
{
243
244
	int		c, l;
	const char	*s;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
245
246
247
248
249
250
251

	assert( submatch != NULL );
	assert( submatch->ls_type == REWRITE_SUBMATCH_ASIS
			|| submatch->ls_type == REWRITE_SUBMATCH_XMAP );
	assert( string != NULL );
	assert( match != NULL );
	assert( val != NULL );
252
	assert( val->bv_val == NULL );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
253
254
255
256
257
258
	
	c = submatch->ls_submatch;
	s = string + match[ c ].rm_so;
	l = match[ c ].rm_eo - match[ c ].rm_so;
	
	val->bv_len = l;
259
	val->bv_val = malloc( l + 1 );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
260
261
262
263
	if ( val->bv_val == NULL ) {
		return REWRITE_ERR;
	}
	
264
	AC_MEMCPY( val->bv_val, s, l );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
	val->bv_val[ l ] = '\0';
	
	return REWRITE_SUCCESS;
}

/*
 * Substitutes a portion of rewritten string according to substitution
 * pattern using submatches
 */
int
rewrite_subst_apply(
		struct rewrite_info *info,
		struct rewrite_op *op,
		struct rewrite_subst *subst,
		const char *string,
		const regmatch_t *match,
		struct berval *val
)
{
	struct berval *submatch = NULL;
	char *res = NULL;
286
	int n = 0, l, cl;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
287
288
289
290
291
292
293
294
295
	int rc = REWRITE_REGEXEC_OK;

	assert( info != NULL );
	assert( op != NULL );
	assert( subst != NULL );
	assert( string != NULL );
	assert( match != NULL );
	assert( val != NULL );

296
297
	assert( val->bv_val == NULL );

Pierangelo Masarati's avatar
Pierangelo Masarati committed
298
299
300
301
302
303
	val->bv_val = NULL;
	val->bv_len = 0;

	/*
	 * Prepare room for submatch expansion
	 */
304
305
306
307
308
309
	if ( subst->lt_num_submatch > 0 ) {
		submatch = calloc( sizeof( struct berval ),
				subst->lt_num_submatch );
		if ( submatch == NULL ) {
			return REWRITE_REGEXEC_ERR;
		}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
310
311
312
313
314
315
	}
	
	/*
	 * Resolve submatches (simple subst, map expansion and so).
	 */
	for ( n = 0, l = 0; n < subst->lt_num_submatch; n++ ) {
316
317
318
		struct berval	key = { 0, NULL };

		submatch[ n ].bv_val = NULL;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
319
320
321
322
		
		/*
		 * Get key
		 */
323
		switch ( subst->lt_submatch[ n ].ls_type ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
324
325
		case REWRITE_SUBMATCH_ASIS:
		case REWRITE_SUBMATCH_XMAP:
326
			rc = submatch_copy( &subst->lt_submatch[ n ],
Pierangelo Masarati's avatar
Pierangelo Masarati committed
327
328
					string, match, &key );
			if ( rc != REWRITE_SUCCESS ) {
329
330
				rc = REWRITE_REGEXEC_ERR;
				goto cleanup;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
331
332
333
334
			}
			break;
			
		case REWRITE_SUBMATCH_MAP_W_ARG:
335
			switch ( subst->lt_submatch[ n ].ls_map->lm_type ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
336
337
338
339
340
			case REWRITE_MAP_GET_OP_VAR:
			case REWRITE_MAP_GET_SESN_VAR:
			case REWRITE_MAP_GET_PARAM:
				rc = REWRITE_SUCCESS;
				break;
341

Pierangelo Masarati's avatar
Pierangelo Masarati committed
342
343
			default:
				rc = rewrite_subst_apply( info, op, 
344
					subst->lt_submatch[ n ].ls_map->lm_subst,
Pierangelo Masarati's avatar
Pierangelo Masarati committed
345
346
347
348
					string, match, &key);
			}
			
			if ( rc != REWRITE_SUCCESS ) {
349
				goto cleanup;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
350
351
352
353
			}
			break;

		default:
354
			Debug( LDAP_DEBUG_ANY, "Not Implemented\n", 0, 0, 0 );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
355
356
357
358
359
			rc = REWRITE_ERR;
			break;
		}
		
		if ( rc != REWRITE_SUCCESS ) {
360
361
			rc = REWRITE_REGEXEC_ERR;
			goto cleanup;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
362
363
364
365
366
		}

		/*
		 * Resolve key
		 */
367
		switch ( subst->lt_submatch[ n ].ls_type ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
368
369
370
371
372
373
374
		case REWRITE_SUBMATCH_ASIS:
			submatch[ n ] = key;
			rc = REWRITE_SUCCESS;
			break;
			
		case REWRITE_SUBMATCH_XMAP:
			rc = rewrite_xmap_apply( info, op,
375
					subst->lt_submatch[ n ].ls_map,
Pierangelo Masarati's avatar
Pierangelo Masarati committed
376
					&key, &submatch[ n ] );
377
378
			free( key.bv_val );
			key.bv_val = NULL;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
379
380
381
382
			break;
			
		case REWRITE_SUBMATCH_MAP_W_ARG:
			rc = rewrite_map_apply( info, op,
383
					subst->lt_submatch[ n ].ls_map,
Pierangelo Masarati's avatar
Pierangelo Masarati committed
384
					&key, &submatch[ n ] );
385
386
			free( key.bv_val );
			key.bv_val = NULL;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
387
			break;
388

Pierangelo Masarati's avatar
Pierangelo Masarati committed
389
390
391
392
393
394
395
396
397
398
		default:
			/*
			 * When implemented, this might return the
                         * exit status of a rewrite context,
                         * which may include a stop, or an
                         * unwilling to perform
                         */
			rc = REWRITE_ERR;
			break;
		}
399

Pierangelo Masarati's avatar
Pierangelo Masarati committed
400
		if ( rc != REWRITE_SUCCESS ) {
401
			rc = REWRITE_REGEXEC_ERR;
402
			goto cleanup;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
403
404
405
406
407
408
409
410
411
		}
		
		/*
                 * Increment the length of the resulting string
                 */
		l += submatch[ n ].bv_len;
	}
	
	/*
Pierangelo Masarati's avatar
Pierangelo Masarati committed
412
         * Alloc result buffer
Pierangelo Masarati's avatar
Pierangelo Masarati committed
413
414
         */
	l += subst->lt_subs_len;
415
	res = malloc( l + 1 );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
416
	if ( res == NULL ) {
417
418
		rc = REWRITE_REGEXEC_ERR;
		goto cleanup;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
419
420
421
	}

	/*
Pierangelo Masarati's avatar
Pierangelo Masarati committed
422
	 * Apply submatches (possibly resolved thru maps)
Pierangelo Masarati's avatar
Pierangelo Masarati committed
423
424
	 */
        for ( n = 0, cl = 0; n < subst->lt_num_submatch; n++ ) {
425
426
427
428
		if ( subst->lt_subs[ n ].bv_val != NULL ) {
                	AC_MEMCPY( res + cl, subst->lt_subs[ n ].bv_val,
					subst->lt_subs[ n ].bv_len );
			cl += subst->lt_subs[ n ].bv_len;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
429
		}
430
431
		AC_MEMCPY( res + cl, submatch[ n ].bv_val, 
				submatch[ n ].bv_len );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
432
433
		cl += submatch[ n ].bv_len;
	}
434
435
436
	if ( subst->lt_subs[ n ].bv_val != NULL ) {
		AC_MEMCPY( res + cl, subst->lt_subs[ n ].bv_val,
				subst->lt_subs[ n ].bv_len );
437
		cl += subst->lt_subs[ n ].bv_len;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
438
	}
439
	res[ cl ] = '\0';
Pierangelo Masarati's avatar
Pierangelo Masarati committed
440
441
442

	val->bv_val = res;
	val->bv_len = l;
443
444
445

cleanup:;
	if ( submatch ) {
446
447
448
449
450
        	for ( ; --n >= 0; ) {
			if ( submatch[ n ].bv_val ) {
				free( submatch[ n ].bv_val );
			}
		}
451
452
453
		free( submatch );
	}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
454
455
456
	return rc;
}

457
458
459
460
461
462
463
464
465
466
467
/*
 * frees data
 */
int
rewrite_subst_destroy(
		struct rewrite_subst **psubst
)
{
	int			n;
	struct rewrite_subst	*subst;

468
469
	assert( psubst != NULL );
	assert( *psubst != NULL );
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495

	subst = *psubst;

	for ( n = 0; n < subst->lt_num_submatch; n++ ) {
		if ( subst->lt_subs[ n ].bv_val ) {
			free( subst->lt_subs[ n ].bv_val );
			subst->lt_subs[ n ].bv_val = NULL;
		}

		switch ( subst->lt_submatch[ n ].ls_type ) {
		case REWRITE_SUBMATCH_ASIS:
			break;

		case REWRITE_SUBMATCH_XMAP:
			rewrite_xmap_destroy( &subst->lt_submatch[ n ].ls_map );
			break;

		case REWRITE_SUBMATCH_MAP_W_ARG:
			rewrite_map_destroy( &subst->lt_submatch[ n ].ls_map );
			break;

		default:
			break;
		}
	}

496
497
498
	free( subst->lt_submatch );
	subst->lt_submatch = NULL;

499
500
501
502
503
504
	/* last one */
	if ( subst->lt_subs[ n ].bv_val ) {
		free( subst->lt_subs[ n ].bv_val );
		subst->lt_subs[ n ].bv_val = NULL;
	}

505
506
507
	free( subst->lt_subs );
	subst->lt_subs = NULL;

508
509
510
511
512
513
	free( subst );
	*psubst = NULL;

	return 0;
}