rwmconf.c 9.86 KB
Newer Older
1
2
3
4
/* rwmconf.c - rewrite/map configuration file routines */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 *
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
5
 * Copyright 1999-2021 The OpenLDAP Foundation.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
6
7
 * Portions Copyright 1999-2003 Howard Chu.
 * Portions Copyright 2000-2003 Pierangelo Masarati.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted only as authorized by the OpenLDAP
 * Public License.
 *
 * A copy of this license is available in the file LICENSE in the
 * top-level directory of the distribution or, alternatively, at
 * <http://www.OpenLDAP.org/license.html>.
 */
/* ACKNOWLEDGEMENTS:
 * This work was initially developed by the Howard Chu for inclusion
 * in OpenLDAP Software and subsequently enhanced by Pierangelo
 * Masarati.
 */

#include "portable.h"

26
27
#ifdef SLAPD_OVER_RWM

28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <stdio.h>

#include <ac/string.h>
#include <ac/socket.h>

#include "slap.h"
#include "rwm.h"
#include "lutil.h"

int
rwm_map_config(
		struct ldapmap	*oc_map,
		struct ldapmap	*at_map,
		const char	*fname,
		int		lineno,
		int		argc,
		char		**argv )
{
	struct ldapmap		*map;
	struct ldapmapping	*mapping;
	char			*src, *dst;
	int			is_oc = 0;
50
	int			rc = 0;
51
52

	if ( argc < 3 || argc > 4 ) {
53
		Debug( LDAP_DEBUG_ANY,
54
	"%s: line %d: syntax is \"map {objectclass | attribute} [<local> | *] {<foreign> | *}\"\n",
55
			fname, lineno );
56
57
58
59
60
61
62
63
64
65
66
		return 1;
	}

	if ( strcasecmp( argv[1], "objectclass" ) == 0 ) {
		map = oc_map;
		is_oc = 1;

	} else if ( strcasecmp( argv[1], "attribute" ) == 0 ) {
		map = at_map;

	} else {
67
		Debug( LDAP_DEBUG_ANY, "%s: line %d: syntax is "
68
69
			"\"map {objectclass | attribute} [<local> | *] "
			"{<foreign> | *}\"\n",
70
			fname, lineno );
71
72
73
		return 1;
	}

74
75
76
77
78
79
80
	if ( !is_oc && map->map == NULL ) {
		/* only init if required */
		if ( rwm_map_init( map, &mapping ) != LDAP_SUCCESS ) {
			return 1;
		}
	}

81
82
83
	if ( strcmp( argv[2], "*" ) == 0 ) {
		if ( argc < 4 || strcmp( argv[3], "*" ) == 0 ) {
			map->drop_missing = ( argc < 4 );
84
			goto success_return;
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
		}
		src = dst = argv[3];

	} else if ( argc < 4 ) {
		src = "";
		dst = argv[2];

	} else {
		src = argv[2];
		dst = ( strcmp( argv[3], "*" ) == 0 ? src : argv[3] );
	}

	if ( ( map == at_map )
			&& ( strcasecmp( src, "objectclass" ) == 0
			|| strcasecmp( dst, "objectclass" ) == 0 ) )
	{
101
		Debug( LDAP_DEBUG_ANY,
102
			"%s: line %d: objectclass attribute cannot be mapped\n",
103
			fname, lineno );
104
		return 1;
105
106
107
108
109
	}

	mapping = (struct ldapmapping *)ch_calloc( 2,
		sizeof(struct ldapmapping) );
	if ( mapping == NULL ) {
110
		Debug( LDAP_DEBUG_ANY,
111
			"%s: line %d: out of memory\n",
112
			fname, lineno );
113
114
		return 1;
	}
115
116
117
118
119
120
121
	ber_str2bv( src, 0, 1, &mapping[0].m_src );
	ber_str2bv( dst, 0, 1, &mapping[0].m_dst );
	mapping[1].m_src = mapping[0].m_dst;
	mapping[1].m_dst = mapping[0].m_src;

	mapping[0].m_flags = RWMMAP_F_NONE;
	mapping[1].m_flags = RWMMAP_F_NONE;
122
123
124
125
126
127

	/*
	 * schema check
	 */
	if ( is_oc ) {
		if ( src[0] != '\0' ) {
128
129
			mapping[0].m_src_oc = oc_bvfind( &mapping[0].m_src );
			if ( mapping[0].m_src_oc == NULL ) {
130
				Debug( LDAP_DEBUG_ANY,
131
132
133
134
135
136
137
	"%s: line %d: warning, source objectClass '%s' "
	"should be defined in schema\n",
					fname, lineno, src );

				/*
				 * FIXME: this should become an err
				 */
138
139
140
141
				mapping[0].m_src_oc = ch_malloc( sizeof( ObjectClass ) );
				memset( mapping[0].m_src_oc, 0, sizeof( ObjectClass ) );
				mapping[0].m_src_oc->soc_cname = mapping[0].m_src;
				mapping[0].m_flags |= RWMMAP_F_FREE_SRC;
142
			}
143
			mapping[1].m_dst_oc = mapping[0].m_src_oc;
144
145
		}

146
147
		mapping[0].m_dst_oc = oc_bvfind( &mapping[0].m_dst );
		if ( mapping[0].m_dst_oc == NULL ) {
148
			Debug( LDAP_DEBUG_ANY,
149
150
151
	"%s: line %d: warning, destination objectClass '%s' "
	"is not defined in schema\n",
				fname, lineno, dst );
152

153
154
			mapping[0].m_dst_oc = oc_bvfind_undef( &mapping[0].m_dst );
			if ( mapping[0].m_dst_oc == NULL ) {
155
				Debug( LDAP_DEBUG_ANY, "%s: line %d: unable to mimic destination objectClass '%s'\n",
156
					fname, lineno, dst );
157
				goto error_return;
158
			}
159
		}
160
161
162
163
164
		mapping[1].m_src_oc = mapping[0].m_dst_oc;

		mapping[0].m_flags |= RWMMAP_F_IS_OC;
		mapping[1].m_flags |= RWMMAP_F_IS_OC;

165
166
167
168
169
	} else {
		int			rc;
		const char		*text = NULL;

		if ( src[0] != '\0' ) {
170
171
			rc = slap_bv2ad( &mapping[0].m_src,
					&mapping[0].m_src_ad, &text );
172
			if ( rc != LDAP_SUCCESS ) {
173
				Debug( LDAP_DEBUG_ANY,
174
175
176
177
178
	"%s: line %d: warning, source attributeType '%s' "
	"should be defined in schema\n",
					fname, lineno, src );

				/*
179
				 * we create a fake "proxied" ad 
180
				 * and add it here.
181
182
				 */

Pierangelo Masarati's avatar
Pierangelo Masarati committed
183
				rc = slap_bv2undef_ad( &mapping[0].m_src,
184
185
						&mapping[0].m_src_ad, &text,
						SLAP_AD_PROXIED );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
186
				if ( rc != LDAP_SUCCESS ) {
187
188
189
190
					Debug(LDAP_DEBUG_ANY,
					      "%s: line %d: source attributeType '%s': %d (%s)\n",
					      fname, lineno, src, rc,
					      text ? text : "null" );
191
					goto error_return;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
192
193
				}

194
195
			}
			mapping[1].m_dst_ad = mapping[0].m_src_ad;
196
197
		}

198
		rc = slap_bv2ad( &mapping[0].m_dst, &mapping[0].m_dst_ad, &text );
199
		if ( rc != LDAP_SUCCESS ) {
200
			Debug( LDAP_DEBUG_ANY,
201
202
203
	"%s: line %d: warning, destination attributeType '%s' "
	"is not defined in schema\n",
				fname, lineno, dst );
204

Pierangelo Masarati's avatar
Pierangelo Masarati committed
205
			rc = slap_bv2undef_ad( &mapping[0].m_dst,
206
207
					&mapping[0].m_dst_ad, &text,
					SLAP_AD_PROXIED );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
208
			if ( rc != LDAP_SUCCESS ) {
209
210
211
212
				Debug(LDAP_DEBUG_ANY,
				      "%s: line %d: destination attributeType '%s': %d (%s)\n",
				      fname, lineno, dst, rc,
				      text ? text : "null" );
213
				goto error_return;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
214
			}
215
		}
216
		mapping[1].m_src_ad = mapping[0].m_dst_ad;
217
218
	}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
219
	if ( ( src[0] != '\0' && avl_find( map->map, (caddr_t)mapping, rwm_mapping_cmp ) != NULL)
220
			|| avl_find( map->remap, (caddr_t)&mapping[1], rwm_mapping_cmp ) != NULL)
221
	{
222
		Debug( LDAP_DEBUG_ANY,
223
			"%s: line %d: duplicate mapping found.\n",
224
			fname, lineno );
225
226
227
228
229
		/* FIXME: free stuff */
		goto error_return;
	}

	if ( src[0] != '\0' ) {
230
		avl_insert( &map->map, (caddr_t)&mapping[0],
231
					rwm_mapping_cmp, rwm_mapping_dup );
232
233
	}
	avl_insert( &map->remap, (caddr_t)&mapping[1],
234
				rwm_mapping_cmp, rwm_mapping_dup );
235

236
237
success_return:;
	return rc;
238
239
240

error_return:;
	if ( mapping ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
241
		rwm_mapping_free( mapping );
242
243
244
245
246
247
	}

	return 1;
}

static char *
248
rwm_suffix_massage_regexize( const char *s )
249
250
251
252
253
{
	char *res, *ptr;
	const char *p, *r;
	int i;

254
	if ( s[0] == '\0' ) {
255
		return ch_strdup( "^(.+)$" );
256
257
	}

258
259
260
261
262
	for ( i = 0, p = s; 
			( r = strchr( p, ',' ) ) != NULL; 
			p = r + 1, i++ )
		;

263
264
265
266
	res = ch_calloc( sizeof( char ), strlen( s )
			+ STRLENOF( "((.+),)?" )
			+ STRLENOF( "[ ]?" ) * i
			+ STRLENOF( "$" ) + 1 );
267

268
	ptr = lutil_strcopy( res, "((.+),)?" );
269
270
271
272
273
274
275
276
277
278
	for ( i = 0, p = s;
			( r = strchr( p, ',' ) ) != NULL;
			p = r + 1 , i++ ) {
		ptr = lutil_strncopy( ptr, p, r - p + 1 );
		ptr = lutil_strcopy( ptr, "[ ]?" );

		if ( r[ 1 ] == ' ' ) {
			r++;
		}
	}
279
280
281
	ptr = lutil_strcopy( ptr, p );
	ptr[0] = '$';
	ptr[1] = '\0';
282
283
284
285
286

	return res;
}

static char *
287
rwm_suffix_massage_patternize( const char *s, const char *p )
288
289
{
	ber_len_t	len;
290
	char		*res, *ptr;
291

292
293
294
295
296
	len = strlen( p );

	if ( s[ 0 ] == '\0' ) {
		len++;
	}
297

Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
298
	res = ch_calloc( sizeof( char ), len + STRLENOF( "%1" ) + 1 );
299
300
301
302
	if ( res == NULL ) {
		return NULL;
	}

303
304
305
306
307
308
	ptr = lutil_strcopy( res, ( p[0] == '\0' ? "%2" : "%1" ) );
	if ( s[ 0 ] == '\0' ) {
		ptr[ 0 ] = ',';
		ptr++;
	}
	lutil_strcopy( ptr, p );
309
310
311
312
313

	return res;
}

int
314
rwm_suffix_massage_config( 
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
		struct rewrite_info *info,
		struct berval *pvnc,
		struct berval *nvnc,
		struct berval *prnc,
		struct berval *nrnc
)
{
	char *rargv[ 5 ];
	int line = 0;

	rargv[ 0 ] = "rewriteEngine";
	rargv[ 1 ] = "on";
	rargv[ 2 ] = NULL;
	rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );

	rargv[ 0 ] = "rewriteContext";
	rargv[ 1 ] = "default";
	rargv[ 2 ] = NULL;
	rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );

	rargv[ 0 ] = "rewriteRule";
336
	rargv[ 1 ] = rwm_suffix_massage_regexize( pvnc->bv_val );
337
	rargv[ 2 ] = rwm_suffix_massage_patternize( pvnc->bv_val, prnc->bv_val );
338
339
340
341
342
343
	rargv[ 3 ] = ":";
	rargv[ 4 ] = NULL;
	rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
	ch_free( rargv[ 1 ] );
	ch_free( rargv[ 2 ] );
	
344
345
346
347
348
349
350
351
352
	if ( BER_BVISEMPTY( pvnc ) ) {
		rargv[ 0 ] = "rewriteRule";
		rargv[ 1 ] = "^$";
		rargv[ 2 ] = prnc->bv_val;
		rargv[ 3 ] = ":";
		rargv[ 4 ] = NULL;
		rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
	}

353
	rargv[ 0 ] = "rewriteContext";
354
	rargv[ 1 ] = "searchEntryDN";
355
356
357
358
	rargv[ 2 ] = NULL;
	rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
	
	rargv[ 0 ] = "rewriteRule";
359
	rargv[ 1 ] = rwm_suffix_massage_regexize( prnc->bv_val );
360
	rargv[ 2 ] = rwm_suffix_massage_patternize( prnc->bv_val, pvnc->bv_val );
361
362
363
364
365
366
	rargv[ 3 ] = ":";
	rargv[ 4 ] = NULL;
	rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
	ch_free( rargv[ 1 ] );
	ch_free( rargv[ 2 ] );

367
368
369
370
371
372
373
374
375
	if ( BER_BVISEMPTY( prnc ) ) {
		rargv[ 0 ] = "rewriteRule";
		rargv[ 1 ] = "^$";
		rargv[ 2 ] = pvnc->bv_val;
		rargv[ 3 ] = ":";
		rargv[ 4 ] = NULL;
		rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
	}

376
377
378
	rargv[ 0 ] = "rewriteContext";
	rargv[ 1 ] = "matchedDN";
	rargv[ 2 ] = "alias";
379
	rargv[ 3 ] = "searchEntryDN";
380
381
382
	rargv[ 4 ] = NULL;
	rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );

383
384
#ifdef RWM_REFERRAL_REWRITE
	/* FIXME: we don't want this on by default, do we? */
385
386
387
388
389
390
	rargv[ 0 ] = "rewriteContext";
	rargv[ 1 ] = "referralDN";
	rargv[ 2 ] = "alias";
	rargv[ 3 ] = "searchEntryDN";
	rargv[ 4 ] = NULL;
	rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
391
392
393
394
395
396
397
398
399
400
401
#else /* ! RWM_REFERRAL_REWRITE */
	rargv[ 0 ] = "rewriteContext";
	rargv[ 1 ] = "referralAttrDN";
	rargv[ 2 ] = NULL;
	rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );

	rargv[ 0 ] = "rewriteContext";
	rargv[ 1 ] = "referralDN";
	rargv[ 2 ] = NULL;
	rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
#endif /* ! RWM_REFERRAL_REWRITE */
402

403
404
405
	rargv[ 0 ] = "rewriteContext";
	rargv[ 1 ] = "searchAttrDN";
	rargv[ 2 ] = "alias";
406
	rargv[ 3 ] = "searchEntryDN";
407
408
409
410
411
	rargv[ 4 ] = NULL;
	rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );

	return 0;
}
412
413

#endif /* SLAPD_OVER_RWM */