Home | History | Annotate | Line # | Download | only in overlays
rwmconf.c revision 1.1.1.3.24.1
      1 /*	$NetBSD: rwmconf.c,v 1.1.1.3.24.1 2014/08/10 07:09:51 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