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