rwmconf.c revision 1.2 1 /* $NetBSD: rwmconf.c,v 1.2 2020/08/11 13:15:42 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-2020 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.2 2020/08/11 13:15:42 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