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