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