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