xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/overlays/rwmconf.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
1 /*	$NetBSD: rwmconf.c,v 1.3 2021/08/14 16:15: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-2021 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.3 2021/08/14 16:15: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
rwm_map_config(struct ldapmap * oc_map,struct ldapmap * at_map,const char * fname,int lineno,int argc,char ** argv)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 );
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 );
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 );
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 );
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 					Debug(LDAP_DEBUG_ANY,
193 					      "%s: line %d: source attributeType '%s': %d (%s)\n",
194 					      fname, lineno, src, rc,
195 					      text ? text : "null" );
196 					goto error_return;
197 				}
198 
199 			}
200 			mapping[1].m_dst_ad = mapping[0].m_src_ad;
201 		}
202 
203 		rc = slap_bv2ad( &mapping[0].m_dst, &mapping[0].m_dst_ad, &text );
204 		if ( rc != LDAP_SUCCESS ) {
205 			Debug( LDAP_DEBUG_ANY,
206 	"%s: line %d: warning, destination attributeType '%s' "
207 	"is not defined in schema\n",
208 				fname, lineno, dst );
209 
210 			rc = slap_bv2undef_ad( &mapping[0].m_dst,
211 					&mapping[0].m_dst_ad, &text,
212 					SLAP_AD_PROXIED );
213 			if ( rc != LDAP_SUCCESS ) {
214 				Debug(LDAP_DEBUG_ANY,
215 				      "%s: line %d: destination attributeType '%s': %d (%s)\n",
216 				      fname, lineno, dst, rc,
217 				      text ? text : "null" );
218 				goto error_return;
219 			}
220 		}
221 		mapping[1].m_src_ad = mapping[0].m_dst_ad;
222 	}
223 
224 	if ( ( src[0] != '\0' && ldap_avl_find( map->map, (caddr_t)mapping, rwm_mapping_cmp ) != NULL)
225 			|| ldap_avl_find( map->remap, (caddr_t)&mapping[1], rwm_mapping_cmp ) != NULL)
226 	{
227 		Debug( LDAP_DEBUG_ANY,
228 			"%s: line %d: duplicate mapping found.\n",
229 			fname, lineno );
230 		/* FIXME: free stuff */
231 		goto error_return;
232 	}
233 
234 	if ( src[0] != '\0' ) {
235 		ldap_avl_insert( &map->map, (caddr_t)&mapping[0],
236 					rwm_mapping_cmp, rwm_mapping_dup );
237 	}
238 	ldap_avl_insert( &map->remap, (caddr_t)&mapping[1],
239 				rwm_mapping_cmp, rwm_mapping_dup );
240 
241 success_return:;
242 	return rc;
243 
244 error_return:;
245 	if ( mapping ) {
246 		rwm_mapping_free( mapping );
247 	}
248 
249 	return 1;
250 }
251 
252 static char *
rwm_suffix_massage_regexize(const char * s)253 rwm_suffix_massage_regexize( const char *s )
254 {
255 	char *res, *ptr;
256 	const char *p, *r;
257 	int i;
258 
259 	if ( s[0] == '\0' ) {
260 		return ch_strdup( "^(.+)$" );
261 	}
262 
263 	for ( i = 0, p = s;
264 			( r = strchr( p, ',' ) ) != NULL;
265 			p = r + 1, i++ )
266 		;
267 
268 	res = ch_calloc( sizeof( char ), strlen( s )
269 			+ STRLENOF( "((.+),)?" )
270 			+ STRLENOF( "[ ]?" ) * i
271 			+ STRLENOF( "$" ) + 1 );
272 
273 	ptr = lutil_strcopy( res, "((.+),)?" );
274 	for ( i = 0, p = s;
275 			( r = strchr( p, ',' ) ) != NULL;
276 			p = r + 1 , i++ ) {
277 		ptr = lutil_strncopy( ptr, p, r - p + 1 );
278 		ptr = lutil_strcopy( ptr, "[ ]?" );
279 
280 		if ( r[ 1 ] == ' ' ) {
281 			r++;
282 		}
283 	}
284 	ptr = lutil_strcopy( ptr, p );
285 	ptr[0] = '$';
286 	ptr[1] = '\0';
287 
288 	return res;
289 }
290 
291 static char *
rwm_suffix_massage_patternize(const char * s,const char * p)292 rwm_suffix_massage_patternize( const char *s, const char *p )
293 {
294 	ber_len_t	len;
295 	char		*res, *ptr;
296 
297 	len = strlen( p );
298 
299 	if ( s[ 0 ] == '\0' ) {
300 		len++;
301 	}
302 
303 	res = ch_calloc( sizeof( char ), len + STRLENOF( "%1" ) + 1 );
304 	if ( res == NULL ) {
305 		return NULL;
306 	}
307 
308 	ptr = lutil_strcopy( res, ( p[0] == '\0' ? "%2" : "%1" ) );
309 	if ( s[ 0 ] == '\0' ) {
310 		ptr[ 0 ] = ',';
311 		ptr++;
312 	}
313 	lutil_strcopy( ptr, p );
314 
315 	return res;
316 }
317 
318 int
rwm_suffix_massage_config(struct rewrite_info * info,struct berval * pvnc,struct berval * nvnc,struct berval * prnc,struct berval * nrnc)319 rwm_suffix_massage_config(
320 		struct rewrite_info *info,
321 		struct berval *pvnc,
322 		struct berval *nvnc,
323 		struct berval *prnc,
324 		struct berval *nrnc
325 )
326 {
327 	char *rargv[ 5 ];
328 	int line = 0;
329 
330 	rargv[ 0 ] = "rewriteEngine";
331 	rargv[ 1 ] = "on";
332 	rargv[ 2 ] = NULL;
333 	rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
334 
335 	rargv[ 0 ] = "rewriteContext";
336 	rargv[ 1 ] = "default";
337 	rargv[ 2 ] = NULL;
338 	rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
339 
340 	rargv[ 0 ] = "rewriteRule";
341 	rargv[ 1 ] = rwm_suffix_massage_regexize( pvnc->bv_val );
342 	rargv[ 2 ] = rwm_suffix_massage_patternize( pvnc->bv_val, prnc->bv_val );
343 	rargv[ 3 ] = ":";
344 	rargv[ 4 ] = NULL;
345 	rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
346 	ch_free( rargv[ 1 ] );
347 	ch_free( rargv[ 2 ] );
348 
349 	if ( BER_BVISEMPTY( pvnc ) ) {
350 		rargv[ 0 ] = "rewriteRule";
351 		rargv[ 1 ] = "^$";
352 		rargv[ 2 ] = prnc->bv_val;
353 		rargv[ 3 ] = ":";
354 		rargv[ 4 ] = NULL;
355 		rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
356 	}
357 
358 	rargv[ 0 ] = "rewriteContext";
359 	rargv[ 1 ] = "searchEntryDN";
360 	rargv[ 2 ] = NULL;
361 	rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
362 
363 	rargv[ 0 ] = "rewriteRule";
364 	rargv[ 1 ] = rwm_suffix_massage_regexize( prnc->bv_val );
365 	rargv[ 2 ] = rwm_suffix_massage_patternize( prnc->bv_val, pvnc->bv_val );
366 	rargv[ 3 ] = ":";
367 	rargv[ 4 ] = NULL;
368 	rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
369 	ch_free( rargv[ 1 ] );
370 	ch_free( rargv[ 2 ] );
371 
372 	if ( BER_BVISEMPTY( prnc ) ) {
373 		rargv[ 0 ] = "rewriteRule";
374 		rargv[ 1 ] = "^$";
375 		rargv[ 2 ] = pvnc->bv_val;
376 		rargv[ 3 ] = ":";
377 		rargv[ 4 ] = NULL;
378 		rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
379 	}
380 
381 	rargv[ 0 ] = "rewriteContext";
382 	rargv[ 1 ] = "matchedDN";
383 	rargv[ 2 ] = "alias";
384 	rargv[ 3 ] = "searchEntryDN";
385 	rargv[ 4 ] = NULL;
386 	rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
387 
388 #ifdef RWM_REFERRAL_REWRITE
389 	/* FIXME: we don't want this on by default, do we? */
390 	rargv[ 0 ] = "rewriteContext";
391 	rargv[ 1 ] = "referralDN";
392 	rargv[ 2 ] = "alias";
393 	rargv[ 3 ] = "searchEntryDN";
394 	rargv[ 4 ] = NULL;
395 	rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
396 #else /* ! RWM_REFERRAL_REWRITE */
397 	rargv[ 0 ] = "rewriteContext";
398 	rargv[ 1 ] = "referralAttrDN";
399 	rargv[ 2 ] = NULL;
400 	rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
401 
402 	rargv[ 0 ] = "rewriteContext";
403 	rargv[ 1 ] = "referralDN";
404 	rargv[ 2 ] = NULL;
405 	rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
406 #endif /* ! RWM_REFERRAL_REWRITE */
407 
408 	rargv[ 0 ] = "rewriteContext";
409 	rargv[ 1 ] = "searchAttrDN";
410 	rargv[ 2 ] = "alias";
411 	rargv[ 3 ] = "searchEntryDN";
412 	rargv[ 4 ] = NULL;
413 	rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
414 
415 	return 0;
416 }
417 
418 #endif /* SLAPD_OVER_RWM */
419