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