rwmconf.c revision 1.1.1.2
1/*	$NetBSD: rwmconf.c,v 1.1.1.2 2010/03/08 02:14:20 lukem Exp $	*/
2
3/* rwmconf.c - rewrite/map configuration file routines */
4/* OpenLDAP: pkg/ldap/servers/slapd/overlays/rwmconf.c,v 1.25.2.5 2009/01/22 00:01:13 kurt Exp */
5/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6 *
7 * Copyright 1999-2009 The OpenLDAP Foundation.
8 * Portions Copyright 1999-2003 Howard Chu.
9 * Portions Copyright 2000-2003 Pierangelo Masarati.
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted only as authorized by the OpenLDAP
14 * Public License.
15 *
16 * A copy of this license is available in the file LICENSE in the
17 * top-level directory of the distribution or, alternatively, at
18 * <http://www.OpenLDAP.org/license.html>.
19 */
20/* ACKNOWLEDGEMENTS:
21 * This work was initially developed by the Howard Chu for inclusion
22 * in OpenLDAP Software and subsequently enhanced by Pierangelo
23 * Masarati.
24 */
25
26#include "portable.h"
27
28#ifdef SLAPD_OVER_RWM
29
30#include <stdio.h>
31
32#include <ac/string.h>
33#include <ac/socket.h>
34
35#include "slap.h"
36#include "rwm.h"
37#include "lutil.h"
38
39int
40rwm_map_config(
41		struct ldapmap	*oc_map,
42		struct ldapmap	*at_map,
43		const char	*fname,
44		int		lineno,
45		int		argc,
46		char		**argv )
47{
48	struct ldapmap		*map;
49	struct ldapmapping	*mapping;
50	char			*src, *dst;
51	int			is_oc = 0;
52	int			rc = 0;
53
54	if ( argc < 3 || argc > 4 ) {
55		fprintf( stderr,
56	"%s: line %d: syntax is \"map {objectclass | attribute} [<local> | *] {<foreign> | *}\"\n",
57			fname, lineno );
58		return 1;
59	}
60
61	if ( strcasecmp( argv[1], "objectclass" ) == 0 ) {
62		map = oc_map;
63		is_oc = 1;
64
65	} else if ( strcasecmp( argv[1], "attribute" ) == 0 ) {
66		map = at_map;
67
68	} else {
69		fprintf( stderr, "%s: line %d: syntax is "
70			"\"map {objectclass | attribute} [<local> | *] "
71			"{<foreign> | *}\"\n",
72			fname, lineno );
73		return 1;
74	}
75
76	if ( !is_oc && map->map == NULL ) {
77		/* only init if required */
78		if ( rwm_map_init( map, &mapping ) != LDAP_SUCCESS ) {
79			return 1;
80		}
81	}
82
83	if ( strcmp( argv[2], "*" ) == 0 ) {
84		if ( argc < 4 || strcmp( argv[3], "*" ) == 0 ) {
85			map->drop_missing = ( argc < 4 );
86			goto success_return;
87		}
88		src = dst = argv[3];
89
90	} else if ( argc < 4 ) {
91		src = "";
92		dst = argv[2];
93
94	} else {
95		src = argv[2];
96		dst = ( strcmp( argv[3], "*" ) == 0 ? src : argv[3] );
97	}
98
99	if ( ( map == at_map )
100			&& ( strcasecmp( src, "objectclass" ) == 0
101			|| strcasecmp( dst, "objectclass" ) == 0 ) )
102	{
103		fprintf( stderr,
104			"%s: line %d: objectclass attribute cannot be mapped\n",
105			fname, lineno );
106		return 1;
107	}
108
109	mapping = (struct ldapmapping *)ch_calloc( 2,
110		sizeof(struct ldapmapping) );
111	if ( mapping == NULL ) {
112		fprintf( stderr,
113			"%s: line %d: out of memory\n",
114			fname, lineno );
115		return 1;
116	}
117	ber_str2bv( src, 0, 1, &mapping[0].m_src );
118	ber_str2bv( dst, 0, 1, &mapping[0].m_dst );
119	mapping[1].m_src = mapping[0].m_dst;
120	mapping[1].m_dst = mapping[0].m_src;
121
122	mapping[0].m_flags = RWMMAP_F_NONE;
123	mapping[1].m_flags = RWMMAP_F_NONE;
124
125	/*
126	 * schema check
127	 */
128	if ( is_oc ) {
129		if ( src[0] != '\0' ) {
130			mapping[0].m_src_oc = oc_bvfind( &mapping[0].m_src );
131			if ( mapping[0].m_src_oc == NULL ) {
132				fprintf( stderr,
133	"%s: line %d: warning, source objectClass '%s' "
134	"should be defined in schema\n",
135					fname, lineno, src );
136
137				/*
138				 * FIXME: this should become an err
139				 */
140				mapping[0].m_src_oc = ch_malloc( sizeof( ObjectClass ) );
141				memset( mapping[0].m_src_oc, 0, sizeof( ObjectClass ) );
142				mapping[0].m_src_oc->soc_cname = mapping[0].m_src;
143				mapping[0].m_flags |= RWMMAP_F_FREE_SRC;
144			}
145			mapping[1].m_dst_oc = mapping[0].m_src_oc;
146		}
147
148		mapping[0].m_dst_oc = oc_bvfind( &mapping[0].m_dst );
149		if ( mapping[0].m_dst_oc == NULL ) {
150			fprintf( stderr,
151	"%s: line %d: warning, destination objectClass '%s' "
152	"is not defined in schema\n",
153				fname, lineno, dst );
154
155			mapping[0].m_dst_oc = oc_bvfind_undef( &mapping[0].m_dst );
156			if ( mapping[0].m_dst_oc == NULL ) {
157				fprintf( stderr, "%s: line %d: unable to mimic destination objectClass '%s'\n",
158					fname, lineno, dst );
159				goto error_return;
160			}
161		}
162		mapping[1].m_src_oc = mapping[0].m_dst_oc;
163
164		mapping[0].m_flags |= RWMMAP_F_IS_OC;
165		mapping[1].m_flags |= RWMMAP_F_IS_OC;
166
167	} else {
168		int			rc;
169		const char		*text = NULL;
170
171		if ( src[0] != '\0' ) {
172			rc = slap_bv2ad( &mapping[0].m_src,
173					&mapping[0].m_src_ad, &text );
174			if ( rc != LDAP_SUCCESS ) {
175				fprintf( stderr,
176	"%s: line %d: warning, source attributeType '%s' "
177	"should be defined in schema\n",
178					fname, lineno, src );
179
180				/*
181				 * we create a fake "proxied" ad
182				 * and add it here.
183				 */
184
185				rc = slap_bv2undef_ad( &mapping[0].m_src,
186						&mapping[0].m_src_ad, &text,
187						SLAP_AD_PROXIED );
188				if ( rc != LDAP_SUCCESS ) {
189					fprintf( stderr,
190	"%s: line %d: source attributeType '%s': %d (%s)\n",
191						fname, lineno, src, rc, text ? text : "null" );
192					goto error_return;
193				}
194
195			}
196			mapping[1].m_dst_ad = mapping[0].m_src_ad;
197		}
198
199		rc = slap_bv2ad( &mapping[0].m_dst, &mapping[0].m_dst_ad, &text );
200		if ( rc != LDAP_SUCCESS ) {
201			fprintf( stderr,
202	"%s: line %d: warning, destination attributeType '%s' "
203	"is not defined in schema\n",
204				fname, lineno, dst );
205
206			rc = slap_bv2undef_ad( &mapping[0].m_dst,
207					&mapping[0].m_dst_ad, &text,
208					SLAP_AD_PROXIED );
209			if ( rc != LDAP_SUCCESS ) {
210				fprintf( stderr,
211	"%s: line %d: destination attributeType '%s': %d (%s)\n",
212					fname, lineno, dst, rc, text ? text : "null" );
213				goto error_return;
214			}
215		}
216		mapping[1].m_src_ad = mapping[0].m_dst_ad;
217	}
218
219	if ( ( src[0] != '\0' && avl_find( map->map, (caddr_t)mapping, rwm_mapping_cmp ) != NULL)
220			|| avl_find( map->remap, (caddr_t)&mapping[1], rwm_mapping_cmp ) != NULL)
221	{
222		fprintf( stderr,
223			"%s: line %d: duplicate mapping found.\n",
224			fname, lineno );
225		/* FIXME: free stuff */
226		goto error_return;
227	}
228
229	if ( src[0] != '\0' ) {
230		avl_insert( &map->map, (caddr_t)&mapping[0],
231					rwm_mapping_cmp, rwm_mapping_dup );
232	}
233	avl_insert( &map->remap, (caddr_t)&mapping[1],
234				rwm_mapping_cmp, rwm_mapping_dup );
235
236success_return:;
237	return rc;
238
239error_return:;
240	if ( mapping ) {
241		rwm_mapping_free( mapping );
242	}
243
244	return 1;
245}
246
247static char *
248rwm_suffix_massage_regexize( const char *s )
249{
250	char *res, *ptr;
251	const char *p, *r;
252	int i;
253
254	if ( s[0] == '\0' ) {
255		return ch_strdup( "^(.+)$" );
256	}
257
258	for ( i = 0, p = s;
259			( r = strchr( p, ',' ) ) != NULL;
260			p = r + 1, i++ )
261		;
262
263	res = ch_calloc( sizeof( char ), strlen( s )
264			+ STRLENOF( "((.+),)?" )
265			+ STRLENOF( "[ ]?" ) * i
266			+ STRLENOF( "$" ) + 1 );
267
268	ptr = lutil_strcopy( res, "((.+),)?" );
269	for ( i = 0, p = s;
270			( r = strchr( p, ',' ) ) != NULL;
271			p = r + 1 , i++ ) {
272		ptr = lutil_strncopy( ptr, p, r - p + 1 );
273		ptr = lutil_strcopy( ptr, "[ ]?" );
274
275		if ( r[ 1 ] == ' ' ) {
276			r++;
277		}
278	}
279	ptr = lutil_strcopy( ptr, p );
280	ptr[0] = '$';
281	ptr[1] = '\0';
282
283	return res;
284}
285
286static char *
287rwm_suffix_massage_patternize( const char *s, const char *p )
288{
289	ber_len_t	len;
290	char		*res, *ptr;
291
292	len = strlen( p );
293
294	if ( s[ 0 ] == '\0' ) {
295		len++;
296	}
297
298	res = ch_calloc( sizeof( char ), len + STRLENOF( "%1" ) + 1 );
299	if ( res == NULL ) {
300		return NULL;
301	}
302
303	ptr = lutil_strcopy( res, ( p[0] == '\0' ? "%2" : "%1" ) );
304	if ( s[ 0 ] == '\0' ) {
305		ptr[ 0 ] = ',';
306		ptr++;
307	}
308	lutil_strcopy( ptr, p );
309
310	return res;
311}
312
313int
314rwm_suffix_massage_config(
315		struct rewrite_info *info,
316		struct berval *pvnc,
317		struct berval *nvnc,
318		struct berval *prnc,
319		struct berval *nrnc
320)
321{
322	char *rargv[ 5 ];
323	int line = 0;
324
325	rargv[ 0 ] = "rewriteEngine";
326	rargv[ 1 ] = "on";
327	rargv[ 2 ] = NULL;
328	rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
329
330	rargv[ 0 ] = "rewriteContext";
331	rargv[ 1 ] = "default";
332	rargv[ 2 ] = NULL;
333	rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
334
335	rargv[ 0 ] = "rewriteRule";
336	rargv[ 1 ] = rwm_suffix_massage_regexize( pvnc->bv_val );
337	rargv[ 2 ] = rwm_suffix_massage_patternize( pvnc->bv_val, prnc->bv_val );
338	rargv[ 3 ] = ":";
339	rargv[ 4 ] = NULL;
340	rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
341	ch_free( rargv[ 1 ] );
342	ch_free( rargv[ 2 ] );
343
344	if ( BER_BVISEMPTY( pvnc ) ) {
345		rargv[ 0 ] = "rewriteRule";
346		rargv[ 1 ] = "^$";
347		rargv[ 2 ] = prnc->bv_val;
348		rargv[ 3 ] = ":";
349		rargv[ 4 ] = NULL;
350		rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
351	}
352
353	rargv[ 0 ] = "rewriteContext";
354	rargv[ 1 ] = "searchEntryDN";
355	rargv[ 2 ] = NULL;
356	rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
357
358	rargv[ 0 ] = "rewriteRule";
359	rargv[ 1 ] = rwm_suffix_massage_regexize( prnc->bv_val );
360	rargv[ 2 ] = rwm_suffix_massage_patternize( prnc->bv_val, pvnc->bv_val );
361	rargv[ 3 ] = ":";
362	rargv[ 4 ] = NULL;
363	rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
364	ch_free( rargv[ 1 ] );
365	ch_free( rargv[ 2 ] );
366
367	if ( BER_BVISEMPTY( prnc ) ) {
368		rargv[ 0 ] = "rewriteRule";
369		rargv[ 1 ] = "^$";
370		rargv[ 2 ] = pvnc->bv_val;
371		rargv[ 3 ] = ":";
372		rargv[ 4 ] = NULL;
373		rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
374	}
375
376	rargv[ 0 ] = "rewriteContext";
377	rargv[ 1 ] = "matchedDN";
378	rargv[ 2 ] = "alias";
379	rargv[ 3 ] = "searchEntryDN";
380	rargv[ 4 ] = NULL;
381	rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
382
383#ifdef RWM_REFERRAL_REWRITE
384	/* FIXME: we don't want this on by default, do we? */
385	rargv[ 0 ] = "rewriteContext";
386	rargv[ 1 ] = "referralDN";
387	rargv[ 2 ] = "alias";
388	rargv[ 3 ] = "searchEntryDN";
389	rargv[ 4 ] = NULL;
390	rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
391#else /* ! RWM_REFERRAL_REWRITE */
392	rargv[ 0 ] = "rewriteContext";
393	rargv[ 1 ] = "referralAttrDN";
394	rargv[ 2 ] = NULL;
395	rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
396
397	rargv[ 0 ] = "rewriteContext";
398	rargv[ 1 ] = "referralDN";
399	rargv[ 2 ] = NULL;
400	rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
401#endif /* ! RWM_REFERRAL_REWRITE */
402
403	rargv[ 0 ] = "rewriteContext";
404	rargv[ 1 ] = "searchAttrDN";
405	rargv[ 2 ] = "alias";
406	rargv[ 3 ] = "searchEntryDN";
407	rargv[ 4 ] = NULL;
408	rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
409
410	return 0;
411}
412
413#endif /* SLAPD_OVER_RWM */
414