summaryrefslogtreecommitdiffstats
path: root/libraries/librewrite/info.c
blob: 3952e97122c7ac4ec5236e34109104b86a31d240 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 *
 * Copyright 2000-2021 The OpenLDAP Foundation.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted only as authorized by the OpenLDAP
 * Public License.
 *
 * 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.
 */

#include <portable.h>

#include "rewrite-int.h"

/*
 * Global data
 */

/*
 * This becomes the running context for subsequent calls to
 * rewrite_parse; it can be altered only by a 
 * rewriteContext config line or by a change in info.
 */
struct rewrite_context *rewrite_int_curr_context = NULL;

/*
 * Inits the info
 */
struct rewrite_info *
rewrite_info_init(
		int mode
)
{
	struct rewrite_info *info;
	struct rewrite_context *context;

	switch ( mode ) {
	case REWRITE_MODE_ERR:
	case REWRITE_MODE_OK:
	case REWRITE_MODE_COPY_INPUT:
	case REWRITE_MODE_USE_DEFAULT:
		break;
	default:
		mode = REWRITE_MODE_USE_DEFAULT;
		break;
		/* return NULL */
	}

	/*
	 * Resets the running context for parsing ...
	 */
	rewrite_int_curr_context = NULL;

	info = calloc( sizeof( struct rewrite_info ), 1 );
	if ( info == NULL ) {
		return NULL;
	}

	info->li_state = REWRITE_DEFAULT;
	info->li_max_passes = REWRITE_MAX_PASSES;
	info->li_max_passes_per_rule = REWRITE_MAX_PASSES;
	info->li_rewrite_mode = mode;

	/*
	 * Add the default (empty) rule
	 */
	context = rewrite_context_create( info, REWRITE_DEFAULT_CONTEXT );
	if ( context == NULL ) {
		free( info );
		return NULL;
	}

#ifdef USE_REWRITE_LDAP_PVT_THREADS
	if ( ldap_pvt_thread_rdwr_init( &info->li_cookies_mutex ) ) {
		avl_free( info->li_context, rewrite_context_free );
		free( info );
		return NULL;
	}
	if ( ldap_pvt_thread_rdwr_init( &info->li_params_mutex ) ) {
		ldap_pvt_thread_rdwr_destroy( &info->li_cookies_mutex );
		avl_free( info->li_context, rewrite_context_free );
		free( info );
		return NULL;
	}
#endif /* USE_REWRITE_LDAP_PVT_THREADS */
	
	return info;
}

/*
 * Cleans up the info structure
 */
int
rewrite_info_delete(
		struct rewrite_info **pinfo
)
{
	struct rewrite_info	*info;

	assert( pinfo != NULL );
	assert( *pinfo != NULL );

	info = *pinfo;
	
	if ( info->li_context ) {
		avl_free( info->li_context, rewrite_context_free );
	}
	info->li_context = NULL;

	if ( info->li_maps ) {
		avl_free( info->li_maps, rewrite_builtin_map_free );
	}
	info->li_maps = NULL;

	rewrite_session_destroy( info );

#ifdef USE_REWRITE_LDAP_PVT_THREADS
	ldap_pvt_thread_rdwr_destroy( &info->li_cookies_mutex );
#endif /* USE_REWRITE_LDAP_PVT_THREADS */

	rewrite_param_destroy( info );
	
#ifdef USE_REWRITE_LDAP_PVT_THREADS
	ldap_pvt_thread_rdwr_destroy( &info->li_params_mutex );
#endif /* USE_REWRITE_LDAP_PVT_THREADS */

	free( info );
	*pinfo = NULL;

	return REWRITE_SUCCESS;
}

/*
 * Rewrites a string according to context.
 * If the engine is off, OK is returned, but the return string will be NULL.
 * In case of 'unwilling to perform', UNWILLING is returned, and the
 * return string will also be null. The same in case of error.
 * Otherwise, OK is returned, and result will hold a newly allocated string
 * with the rewriting.
 * 
 * What to do in case of non-existing rewrite context is still an issue.
 * Four possibilities:
 * 	- error, 
 * 	- ok with NULL result, 
 * 	- ok with copy of string as result,
 * 	- use the default rewrite context.
 */
int
rewrite(
		struct rewrite_info *info,
		const char *rewriteContext,
		const char *string,
		char **result
)
{
	return rewrite_session( info, rewriteContext, 
			string, NULL, result );
}

int
rewrite_session(
		struct rewrite_info *info,
		const char *rewriteContext,
		const char *string,
		const void *cookie,
		char **result
)
{
	struct rewrite_context *context;
	struct rewrite_op op = { 0, 0, NULL, NULL, NULL };
	int rc;
	
	assert( info != NULL );
	assert( rewriteContext != NULL );
	assert( string != NULL );
	assert( result != NULL );

	/*
	 * cookie can be null; means: don't care about session stuff
	 */

	*result = NULL;
	op.lo_cookie = cookie;
	
	/*
	 * Engine not on means no failure, but explicit no rewriting
	 */
	if ( info->li_state != REWRITE_ON ) {
		rc = REWRITE_REGEXEC_OK;
		goto rc_return;
	}
	
	/*
	 * Undefined context means no rewriting also
	 * (conservative, are we sure it's what we want?)
	 */
	context = rewrite_context_find( info, rewriteContext );
	if ( context == NULL ) {
		switch ( info->li_rewrite_mode ) {
		case REWRITE_MODE_ERR:
			rc = REWRITE_REGEXEC_ERR;
			goto rc_return;
			
		case REWRITE_MODE_OK:
			rc = REWRITE_REGEXEC_OK;
			goto rc_return;

		case REWRITE_MODE_COPY_INPUT:
			*result = strdup( string );
			rc = ( *result != NULL ) ? REWRITE_REGEXEC_OK : REWRITE_REGEXEC_ERR;
			goto rc_return;

		case REWRITE_MODE_USE_DEFAULT:
			context = rewrite_context_find( info,
					REWRITE_DEFAULT_CONTEXT );
			break;
		}
	}

#if 0 /* FIXME: not used anywhere! (debug? then, why strdup?) */
	op.lo_string = strdup( string );
	if ( op.lo_string == NULL ) {
		rc = REWRITE_REGEXEC_ERR;
		goto rc_return;
	}
#endif
	
	/*
	 * Applies rewrite context
	 */
	rc = rewrite_context_apply( info, &op, context, string, result );
	assert( op.lo_depth == 0 );

#if 0 /* FIXME: not used anywhere! (debug? then, why strdup?) */	
	free( op.lo_string );
#endif
	
	switch ( rc ) {
	/*
	 * Success
	 */
	case REWRITE_REGEXEC_OK:
	case REWRITE_REGEXEC_STOP:
		/*
		 * If rewrite succeeded return OK regardless of how
		 * the successful rewriting was obtained!
		 */
		rc = REWRITE_REGEXEC_OK;
		break;
		
	
	/*
	 * Internal or forced error, return = NULL; rc already OK.
	 */
	case REWRITE_REGEXEC_UNWILLING:
	case REWRITE_REGEXEC_ERR:
		if ( *result != NULL ) {
			if ( *result != string ) {
				free( *result );
			}
			*result = NULL;
		}

	default:
		break;
	}

rc_return:;
	if ( op.lo_vars ) {
		rewrite_var_delete( op.lo_vars );
	}
	
	return rc;
}