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 */
35struct rewrite_context *rewrite_int_curr_context = NULL;
36
37/*
38 * Inits the info
39 */
40struct rewrite_info *
41rewrite_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 */
104int
105rewrite_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 */
159int
160rewrite(
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
171int
172rewrite_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
279rc_return:;
280	if ( op.lo_vars ) {
281		rewrite_var_delete( op.lo_vars );
282	}
283
284	return rc;
285}
286
287