1 /*	$NetBSD: info.c,v 1.1.1.3 2010/12/12 15:22:12 adam Exp $	*/
2 
3 /* OpenLDAP: pkg/ldap/libraries/librewrite/info.c,v 1.15.2.6 2010/04/13 20:23:08 kurt Exp */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 2000-2010 The OpenLDAP Foundation.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in the file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17 /* ACKNOWLEDGEMENT:
18  * This work was initially developed by Pierangelo Masarati for
19  * inclusion in OpenLDAP Software.
20  */
21 
22 #include <portable.h>
23 
24 #include "rewrite-int.h"
25 
26 /*
27  * Global data
28  */
29 
30 /*
31  * This becomes the running context for subsequent calls to
32  * rewrite_parse; it can be altered only by a
33  * rewriteContext config line or by a change in info.
34  */
35 struct rewrite_context *rewrite_int_curr_context = NULL;
36 
37 /*
38  * Inits the info
39  */
40 struct rewrite_info *
41 rewrite_info_init(
42 		int mode
43 )
44 {
45 	struct rewrite_info *info;
46 	struct rewrite_context *context;
47 
48 	switch ( mode ) {
49 	case REWRITE_MODE_ERR:
50 	case REWRITE_MODE_OK:
51 	case REWRITE_MODE_COPY_INPUT:
52 	case REWRITE_MODE_USE_DEFAULT:
53 		break;
54 	default:
55 		mode = REWRITE_MODE_USE_DEFAULT;
56 		break;
57 		/* return NULL */
58 	}
59 
60 	/*
61 	 * Resets the running context for parsing ...
62 	 */
63 	rewrite_int_curr_context = NULL;
64 
65 	info = calloc( sizeof( struct rewrite_info ), 1 );
66 	if ( info == NULL ) {
67 		return NULL;
68 	}
69 
70 	info->li_state = REWRITE_DEFAULT;
71 	info->li_max_passes = REWRITE_MAX_PASSES;
72 	info->li_max_passes_per_rule = REWRITE_MAX_PASSES;
73 	info->li_rewrite_mode = mode;
74 
75 	/*
76 	 * Add the default (empty) rule
77 	 */
78 	context = rewrite_context_create( info, REWRITE_DEFAULT_CONTEXT );
79 	if ( context == NULL ) {
80 		free( info );
81 		return NULL;
82 	}
83 
84 #ifdef USE_REWRITE_LDAP_PVT_THREADS
85 	if ( ldap_pvt_thread_rdwr_init( &info->li_cookies_mutex ) ) {
86 		avl_free( info->li_context, rewrite_context_free );
87 		free( info );
88 		return NULL;
89 	}
90 	if ( ldap_pvt_thread_rdwr_init( &info->li_params_mutex ) ) {
91 		ldap_pvt_thread_rdwr_destroy( &info->li_cookies_mutex );
92 		avl_free( info->li_context, rewrite_context_free );
93 		free( info );
94 		return NULL;
95 	}
96 #endif /* USE_REWRITE_LDAP_PVT_THREADS */
97 
98 	return info;
99 }
100 
101 /*
102  * Cleans up the info structure
103  */
104 int
105 rewrite_info_delete(
106 		struct rewrite_info **pinfo
107 )
108 {
109 	struct rewrite_info	*info;
110 
111 	assert( pinfo != NULL );
112 	assert( *pinfo != NULL );
113 
114 	info = *pinfo;
115 
116 	if ( info->li_context ) {
117 		avl_free( info->li_context, rewrite_context_free );
118 	}
119 	info->li_context = NULL;
120 
121 	if ( info->li_maps ) {
122 		avl_free( info->li_maps, rewrite_builtin_map_free );
123 	}
124 	info->li_maps = NULL;
125 
126 	rewrite_session_destroy( info );
127 
128 #ifdef USE_REWRITE_LDAP_PVT_THREADS
129 	ldap_pvt_thread_rdwr_destroy( &info->li_cookies_mutex );
130 #endif /* USE_REWRITE_LDAP_PVT_THREADS */
131 
132 	rewrite_param_destroy( info );
133 
134 #ifdef USE_REWRITE_LDAP_PVT_THREADS
135 	ldap_pvt_thread_rdwr_destroy( &info->li_params_mutex );
136 #endif /* USE_REWRITE_LDAP_PVT_THREADS */
137 
138 	free( info );
139 	*pinfo = NULL;
140 
141 	return REWRITE_SUCCESS;
142 }
143 
144 /*
145  * Rewrites a string according to context.
146  * If the engine is off, OK is returned, but the return string will be NULL.
147  * In case of 'unwilling to perform', UNWILLING is returned, and the
148  * return string will also be null. The same in case of error.
149  * Otherwise, OK is returned, and result will hold a newly allocated string
150  * with the rewriting.
151  *
152  * What to do in case of non-existing rewrite context is still an issue.
153  * Four possibilities:
154  * 	- error,
155  * 	- ok with NULL result,
156  * 	- ok with copy of string as result,
157  * 	- use the default rewrite context.
158  */
159 int
160 rewrite(
161 		struct rewrite_info *info,
162 		const char *rewriteContext,
163 		const char *string,
164 		char **result
165 )
166 {
167 	return rewrite_session( info, rewriteContext,
168 			string, NULL, result );
169 }
170 
171 int
172 rewrite_session(
173 		struct rewrite_info *info,
174 		const char *rewriteContext,
175 		const char *string,
176 		const void *cookie,
177 		char **result
178 )
179 {
180 	struct rewrite_context *context;
181 	struct rewrite_op op = { 0, 0, NULL, NULL, NULL };
182 	int rc;
183 
184 	assert( info != NULL );
185 	assert( rewriteContext != NULL );
186 	assert( string != NULL );
187 	assert( result != NULL );
188 
189 	/*
190 	 * cookie can be null; means: don't care about session stuff
191 	 */
192 
193 	*result = NULL;
194 	op.lo_cookie = cookie;
195 
196 	/*
197 	 * Engine not on means no failure, but explicit no rewriting
198 	 */
199 	if ( info->li_state != REWRITE_ON ) {
200 		rc = REWRITE_REGEXEC_OK;
201 		goto rc_return;
202 	}
203 
204 	/*
205 	 * Undefined context means no rewriting also
206 	 * (conservative, are we sure it's what we want?)
207 	 */
208 	context = rewrite_context_find( info, rewriteContext );
209 	if ( context == NULL ) {
210 		switch ( info->li_rewrite_mode ) {
211 		case REWRITE_MODE_ERR:
212 			rc = REWRITE_REGEXEC_ERR;
213 			goto rc_return;
214 
215 		case REWRITE_MODE_OK:
216 			rc = REWRITE_REGEXEC_OK;
217 			goto rc_return;
218 
219 		case REWRITE_MODE_COPY_INPUT:
220 			*result = strdup( string );
221 			rc = ( *result != NULL ) ? REWRITE_REGEXEC_OK : REWRITE_REGEXEC_ERR;
222 			goto rc_return;
223 
224 		case REWRITE_MODE_USE_DEFAULT:
225 			context = rewrite_context_find( info,
226 					REWRITE_DEFAULT_CONTEXT );
227 			break;
228 		}
229 	}
230 
231 #if 0 /* FIXME: not used anywhere! (debug? then, why strdup?) */
232 	op.lo_string = strdup( string );
233 	if ( op.lo_string == NULL ) {
234 		rc = REWRITE_REGEXEC_ERR;
235 		goto rc_return;
236 	}
237 #endif
238 
239 	/*
240 	 * Applies rewrite context
241 	 */
242 	rc = rewrite_context_apply( info, &op, context, string, result );
243 	assert( op.lo_depth == 0 );
244 
245 #if 0 /* FIXME: not used anywhere! (debug? then, why strdup?) */
246 	free( op.lo_string );
247 #endif
248 
249 	switch ( rc ) {
250 	/*
251 	 * Success
252 	 */
253 	case REWRITE_REGEXEC_OK:
254 	case REWRITE_REGEXEC_STOP:
255 		/*
256 		 * If rewrite succeeded return OK regardless of how
257 		 * the successful rewriting was obtained!
258 		 */
259 		rc = REWRITE_REGEXEC_OK;
260 		break;
261 
262 
263 	/*
264 	 * Internal or forced error, return = NULL; rc already OK.
265 	 */
266 	case REWRITE_REGEXEC_UNWILLING:
267 	case REWRITE_REGEXEC_ERR:
268 		if ( *result != NULL ) {
269 			if ( *result != string ) {
270 				free( *result );
271 			}
272 			*result = NULL;
273 		}
274 
275 	default:
276 		break;
277 	}
278 
279 rc_return:;
280 	if ( op.lo_vars ) {
281 		rewrite_var_delete( op.lo_vars );
282 	}
283 
284 	return rc;
285 }
286 
287